From 83fcd28272909b98677bfd8f580b2e45bad787cf Mon Sep 17 00:00:00 2001
From: Baptiste LENIAU <baptiste.leniau@subatech.in2p3.fr>
Date: Wed, 29 Apr 2015 13:13:10 +0000
Subject: [PATCH] BuildFuel function rewritten . It is now much more simpler
 and quicker. CLASS execution time is reduce by a factor 2 !

git-svn-id: svn+ssh://svn.in2p3.fr/class@651 0e7d625b-0364-4367-a6be-d5be4a48d228
---
 source/trunk/src/EquivalenceModel.cxx | 277 +++++++++++---------------
 1 file changed, 118 insertions(+), 159 deletions(-)

diff --git a/source/trunk/src/EquivalenceModel.cxx b/source/trunk/src/EquivalenceModel.cxx
index 7856fab2b..b88835959 100644
--- a/source/trunk/src/EquivalenceModel.cxx
+++ b/source/trunk/src/EquivalenceModel.cxx
@@ -1,20 +1,19 @@
 #include "EquivalenceModel.hxx"
 
 
-
 EquivalenceModel::EquivalenceModel():CLASSObject()
 {
 	fRelativMassPrecision = 1/10000.; //Mass precision
-	fMaxInterration = 1000; // Max iterration in build fueld algorythum
-	fFirstGuessFissilContent = 0.04;
+	fMaxInterration = 100; // Max iterration in build fueld algorythum
+	fFirstGuessFissilContent = 0.02;
 
 }
 
 EquivalenceModel::EquivalenceModel(CLASSLogger* log):CLASSObject(log)
 {
 	fRelativMassPrecision = 1/10000.; //Mass precision
-	fMaxInterration = 1000; // Max iterration in build fueld algorythm
-	fFirstGuessFissilContent = 0.04;
+	fMaxInterration = 100; // Max iterration in build fueld algorythm
+	fFirstGuessFissilContent = 0.02;
 
 }
 
@@ -23,100 +22,157 @@ EquivalenceModel::~EquivalenceModel()
 
 }
 //________________________________________________________________________
-vector<double> EquivalenceModel::BuildFuel(double BurnUp, double HMMass,vector<IsotopicVector> FissilArray, vector<IsotopicVector> FertilArray)
+double EquivalenceModel::LAMBDA_TOT_FOR(double MassNeeded, vector<IsotopicVector> Stocks,string FisOrFer)
+{	
+	double Lambda_tot = 0;
+
+	//Calculating total mass of stock once and for all
+	if( fTotalFissileMassInStocks==0 || fTotalFertileMassInStocks==0 )
+	{	
+		double TotalMassInStocks = 0;
+		for( int i = 0 ; i<(int)Stocks.size() ; i++ )
+			TotalMassInStocks += Stocks[i].GetTotalMass() ;
+
+		if(FisOrFer == "Fis")
+			fTotalFissileMassInStocks = TotalMassInStocks*1e6; //in g
+	
+		else
+			fTotalFertileMassInStocks = TotalMassInStocks*1e6; //in g
+	}
+
+	double TotalMassInStocks = 0;
+	if(FisOrFer == "Fis")
+		TotalMassInStocks = fTotalFissileMassInStocks;
+	else
+		TotalMassInStocks = fTotalFertileMassInStocks;
+
+	//If there is not enought matter in stocks construction fails
+	if( MassNeeded > TotalMassInStocks )
+	{
+		WARNING<<"Not enought "<< FisOrFer <<" material to build fuel"<<endl;
+		WARNING<<TotalMassInStocks<<endl;
+		return -1;
+	}
+
+	for( int i = 0 ; i<(int)Stocks.size() ; i++ )
+	{
+
+		if( MassNeeded  >= (Stocks[i].GetTotalMass()*1e6) )
+		{	Lambda_tot+=1;
+			MassNeeded -= (Stocks[i].GetTotalMass()*1e6);
+		}
+		else
+		{
+			Lambda_tot+=MassNeeded/(Stocks[i].GetTotalMass()*1e6);
+			break;
+		}
+	}
+
+return Lambda_tot;
+}
+//________________________________________________________________________
+bool EquivalenceModel::Build_Fuel_According_Lambda(vector<double> &lambda,vector<IsotopicVector> FissilArray, vector<IsotopicVector> FertilArray, double HMMass,IsotopicVector &Fissile, IsotopicVector &Fertile)
 {
-DBGL
-	HMMass*=1e6;//tons to gram
+		//Build the Plutonium vector from stocks
+		Fissile.Clear();	
 
-	/****Some initializations**/
-	fActualFissileContent = GetBuildFuelFirstGuess(); //usefull for EQM_MLP_Kinf
+		for( int i = 0 ; i < (int)FissilArray.size() ; i++ )
+			Fissile +=lambda[i] * FissilArray[i];
 
-	vector<double> lambda ; //vector of portion of stocks taken (fissile & fertil)
-	for(int i = 0 ; i < (int)FissilArray.size() + (int)FertilArray.size() ; i++ )
-		lambda.push_back(0);
+		double AvailablePuMass = Fissile.GetTotalMass() * 1e6; //in grams
+		//Building complementary Fertile from stocks
+		double FertilMassNeeded = HMMass - AvailablePuMass;			
+		double LAMBDA_FERTILE = LAMBDA_TOT_FOR( FertilMassNeeded , FertilArray , "Fer" );
+		
+		SetLambda(lambda, (int)FissilArray.size(), (int)lambda.size()-1,LAMBDA_FERTILE);
+		
+		int j=-1;
+		Fertile.Clear();
+		for(int i = (int)FissilArray.size() ; i < (int)FissilArray.size()+(int)FertilArray.size() ; i++)
+		{	j++;
+			Fertile +=  lambda[i] * FertilArray[j];
+		}
+	
+		if(  fabs(Fertile.GetTotalMass()*1e6 - FertilMassNeeded) > FertilMassNeeded * 1e-6)//Not enought fertile in stocks
+		{
+			WARNING<<"Not enought fertile material to build fuel"<<endl;
+			return false;
+		}
 
+return true;
+}
+//________________________________________________________________________
+vector<double> EquivalenceModel::BuildFuel(double BurnUp, double HMMass,vector<IsotopicVector> FissilArray, vector<IsotopicVector> FertilArray)
+{
 
+DBGL	
+	/***Test if there is a stock**/
 	if( (int)FissilArray.size()==0 )
 	{	WARNING<<" No fissile stocks available ! Fuel not build"<<endl;
 		lambda[0] = -1;
 		return lambda;
 	}
 
+	HMMass*=1e6;//tons to gram
+
+	/****Some initializations**/
+	fTotalFissileMassInStocks = 0;
+	fTotalFertileMassInStocks = 0;
+	fActualFissileContent = GetBuildFuelFirstGuess(); 
 
-	fLambda_max = FindLambdaMax( FissilArray, HMMass );
-	fOld_Lambda_Tot_Minus = 0;
-	fOld_Lambda_Tot_Plus  = fLambda_max;
-	DBGV("fLambda_max "<<fLambda_max);
+	vector<double> lambda ; //vector of portion of stocks taken (fissile & fertil)
+	for(int i = 0 ; i < (int)FissilArray.size() + (int)FertilArray.size() ; i++ )
+		lambda.push_back(0);
 
 	IsotopicVector Fertile;
 	IsotopicVector Fissile;
 	double AvailablePuMass = 0;
-	double PuMassNeeded = HMMass * 0.01; //At present time I have no clue what is the requiered Pu mass, I assume at least 1kg is needed
+	double PuMassNeeded = HMMass * fActualFissileContent; 
 	double WeightPuContent = 0;
-
 	int loopCount = 0;
-	
+
 	do
 	{
-		//Increase the portion of the stock stokID taken, according to the followings variables
-		double DeltaM=PuMassNeeded-AvailablePuMass;
-		GuessLambda( lambda, 0, (int)FissilArray.size()-1, DeltaM, FissilArray ,HMMass);
-		
-		if(lambda[0]==-1)	// Check if previous lambda was well calculated
+		double LAMBDA_NEEDED = LAMBDA_TOT_FOR(PuMassNeeded,FissilArray,"Fis");
+		if(LAMBDA_NEEDED == -1)	// Check if previous lambda was well calculated
 		{	
 			for(int i=0 ; i < (int)FissilArray.size() + (int)FertilArray.size();i++ )
 				lambda[i]= -1;
 			
 			WARNING<<"Not enought fissile material to build fuel"<<endl;
+
 			return lambda;
 		}
-		else if (loopCount > fMaxInterration)
-		{
-			ERROR << "Too much iterration in BuildFuel Method ! Need improvement in fuel fabrication ! Ask for it or D.I.Y. !!" << endl;
-			exit(1);
+		SetLambda(lambda,0,FissilArray.size()-1,LAMBDA_NEEDED );
+		bool succeed = Build_Fuel_According_Lambda(lambda,FissilArray,FertilArray,HMMass,Fissile,Fertile);
+		if(!succeed)
+		{	for( int i = 0 ; i < (int)FissilArray.size() + (int)FertilArray.size() ; i++ )
+				lambda[i] = -1; //error code (read by FabricationPlant)
+
+			return lambda;
 		}
-		
-		
-		//Build the Plutonium vector from stocks
-		Fissile.Clear();
-		
-		for( int i = 0 ; i < (int)FissilArray.size() ; i++ )
-			Fissile +=lambda[i] * FissilArray[i];
 
 		AvailablePuMass = Fissile.GetTotalMass() * 1e6; //in grams
-		//Building complementary Fertile from stocks
-		double FertilMassNeeded = HMMass - AvailablePuMass;			
-		double LAMBDA_FERTILE = FindLambdaMax(FertilArray, FertilMassNeeded);
-		
-		SetLambda(lambda, (int)FissilArray.size(), (int)lambda.size()-1,LAMBDA_FERTILE);
-		
-		int j=-1;
-		Fertile.Clear();
-		for(int i = (int)FissilArray.size() ; i < (int)FissilArray.size()+(int)FertilArray.size() ; i++)
-		{	j++;
-			Fertile +=  lambda[i] * FertilArray[j];
-		}
-	
-		if(  fabs(Fertile.GetTotalMass()*1e6 - FertilMassNeeded) > FertilMassNeeded * 1e-6)//Not enought fertile in stocks
+
+		if (loopCount > fMaxInterration)
 		{
-			for( int i = 0 ; i < (int)FissilArray.size() + (int)FertilArray.size() ; i++ )
-				lambda[i] = -1; //error code (read by FabricationPlant)
-			WARNING<<"Not enought fertile material to build fuel"<<endl;
-			return lambda;
+			ERROR << "Too much iterration in BuildFuel Method ! Need improvement in fuel fabrication ! Ask for it or D.I.Y. !!" << endl;
+			exit(1);
 		}
 		
 		/*Calcul the quantity of this composition needed to reach the burnup*/
 		double MolarPuContent = GetFissileMolarFraction(Fissile, Fertile, BurnUp);
-		fActualFissileContent = MolarPuContent; //usefull for EQM_MLP_Kinf
 		double MeanMolarPu = Fissile.MeanMolar();
 		double MeanMolarDepletedU = Fertile.MeanMolar();
 		double MeanMolar   = MeanMolarPu * MolarPuContent + (1-MolarPuContent)*MeanMolarDepletedU;
-		
-		DBGV("MolarPuContent "<<MolarPuContent<<" DeltaM "<<PuMassNeeded-AvailablePuMass << " g");
-		
 		WeightPuContent = MolarPuContent * MeanMolarPu / MeanMolar ;
+
+		fActualFissileContent = MolarPuContent; //fActualFissileContent can be accessed by a derivated EquivalenModel to accelerate GetFissileMolarFraction function (exemple in EQM_MLP_Kinf)
 		PuMassNeeded = WeightPuContent  *  HMMass ;
+		DBGV("MolarPuContent "<<MolarPuContent<<" DeltaM "<<PuMassNeeded-AvailablePuMass << " g");
+
 		loopCount++;
+
 	}while(  fabs(PuMassNeeded - AvailablePuMass)/HMMass > fRelativMassPrecision );
 
 
@@ -125,7 +181,6 @@ DBGL
 	for(int i = 0 ; i < (int)FissilArray.size() + (int)FertilArray.size() ; i++ )
 			DBGV(lambda[i]);
 	
-DBGL
 	return lambda;
 }
 //________________________________________________________________________
@@ -140,108 +195,12 @@ void EquivalenceModel::SetLambda(vector<double>& lambda ,int FirstStockID, int L
 		for(int i = FirstStockID ; i <= LastStockID ; i++) //set to 0 all non touched value (to be sure)
 			lambda[i] = 0  ;
 
-		int PartieEntier = floor( LAMBDA_TOT );
-		double PartieDecimal = LAMBDA_TOT - PartieEntier;
+		int IntegerPart = floor( LAMBDA_TOT );
+		double DecimalPart = LAMBDA_TOT - IntegerPart;
 
-		for(int i=FirstStockID  ; i < FirstStockID +PartieEntier ;i++ )
+		for(int i=FirstStockID  ; i < FirstStockID +IntegerPart ;i++ )
 				lambda[i]=1;
 
-		lambda[FirstStockID + PartieEntier] = PartieDecimal  ;
-
-}
-//________________________________________________________________________
-void EquivalenceModel::GuessLambda(vector<double>& lambda,int FirstStockID, int LastStockID, double DeltaM, vector<IsotopicVector> Stocks, double  HMMass)
-{
-	double	LAMBDA_TOT=0;
-	
-	for (int i = FirstStockID; i <=LastStockID ; i++)
-		LAMBDA_TOT+=lambda[i]	;
-
-
-	if( LAMBDA_TOT == 0 ) //Initialization Looking for lambda such as the fissile content is GetBuildFuelFirstGuess() of HM
-	{
-		double	MASS = 0 ; 
-		int ID_max = 0;
-		while( MASS < GetBuildFuelFirstGuess()*HMMass )
-		{		
-			double StockMass = Stocks[ID_max].GetTotalMass() * 1e6;
-
-			if( StockMass > HMMass )
-				LAMBDA_TOT += 0.01*HMMass/StockMass;
-			else
-				 LAMBDA_TOT += 0.01;
-
-			if(LAMBDA_TOT > ID_max+1)	
-			{	
-				LAMBDA_TOT=ID_max+1;
-				ID_max++ ;
-				if( ID_max >=(int) Stocks.size())
-				{	lambda[0]=-1;//error code;
-					break;
-				}	
-			}	
-			SetLambda(lambda,FirstStockID,LastStockID,LAMBDA_TOT );
-
-			IsotopicVector test;
-			int j=0;
-			for(int i=FirstStockID;i<=LastStockID;i++)
-			{
-				IsotopicVector IVTMP =	lambda[i] * Stocks[j];
-				test += IVTMP;
-				j++;
-			}	
-			MASS = test.GetTotalMass() * 1e6; //in grams
-		}
-	}
-
-	else  if( DeltaM > 0) 
-	{
-		fOld_Lambda_Tot_Minus = LAMBDA_TOT;
-		LAMBDA_TOT += (fOld_Lambda_Tot_Plus - LAMBDA_TOT)/2.;
-
-		if( ( (fLambda_max - LAMBDA_TOT ) < 1)
-			&& ( fLambda_max - LAMBDA_TOT ) * Stocks.back().GetTotalMass() * 1e6 < HMMass *fRelativMassPrecision/2.) //if we get close to the total of the stocks
-				lambda[0]=-1;//error code;
-		else
-			SetLambda(lambda,FirstStockID,LastStockID,LAMBDA_TOT );
-	}
-
-	else  if( DeltaM < 0) 
-	{	fOld_Lambda_Tot_Plus =  LAMBDA_TOT;
-		LAMBDA_TOT = LAMBDA_TOT - fabs(fOld_Lambda_Tot_Minus - LAMBDA_TOT) / 2. ;
-		SetLambda(lambda,FirstStockID,LastStockID,LAMBDA_TOT );
-	}
-	DBGV("LAMBDA_TOT :"<<LAMBDA_TOT);
+		lambda[FirstStockID + IntegerPart] = DecimalPart  ;
 }
 //________________________________________________________________________
-double EquivalenceModel::FindLambdaMax(vector<IsotopicVector> Stocks, double  HMMass)
-{	
-	//je cherche les lambda telle que j'ai 100% de HMass  ou bien la mass total des stocks
-	double LAMBDA = 0;
-	double TotStockMass = 0;
-	for (int i = 0 ; i < (int)Stocks.size() ; i++)
-		TotStockMass += Stocks[i].GetTotalMass() * 1e6;
-		
-
-	if(TotStockMass <= HMMass)
-		return Stocks.size() ;
-
-	else
-	{	
-		double RemainHM=HMMass;
-		for(int i=0 ;i<(int)Stocks.size();i++ )
-		{
-			if( RemainHM - Stocks[i].GetTotalMass() * 1e6 > 0)
-			{
-				RemainHM -= Stocks[i].GetTotalMass() * 1e6;
-				LAMBDA++;
-			}
-			else
-			{	LAMBDA+= RemainHM / (Stocks[i].GetTotalMass() * 1e6);
-				return LAMBDA;
-			}	
-		}
-	}
-
-return -1;
-}
\ No newline at end of file
-- 
GitLab