From 08aa3a1bd82905111dfe79f60f405449eb8850c6 Mon Sep 17 00:00:00 2001 From: Baptiste LENIAU <baptiste.leniau@subatech.in2p3.fr> Date: Mon, 31 Aug 2015 16:58:41 +0000 Subject: [PATCH] adding Fanny's Equivalence model (MOX on enriched uranium support) git-svn-id: svn+ssh://svn.in2p3.fr/class@731 0e7d625b-0364-4367-a6be-d5be4a48d228 --- .../Model/Equivalence/EQM_MLP_PWR_MOxEUS.cxx | 639 ++++++++++++++++++ .../Model/Equivalence/EQM_MLP_PWR_MOxEUS.hxx | 67 ++ 2 files changed, 706 insertions(+) create mode 100644 source/branches/CLASSV4.2/Model/Equivalence/EQM_MLP_PWR_MOxEUS.cxx create mode 100644 source/branches/CLASSV4.2/Model/Equivalence/EQM_MLP_PWR_MOxEUS.hxx diff --git a/source/branches/CLASSV4.2/Model/Equivalence/EQM_MLP_PWR_MOxEUS.cxx b/source/branches/CLASSV4.2/Model/Equivalence/EQM_MLP_PWR_MOxEUS.cxx new file mode 100644 index 000000000..1fc98217d --- /dev/null +++ b/source/branches/CLASSV4.2/Model/Equivalence/EQM_MLP_PWR_MOxEUS.cxx @@ -0,0 +1,639 @@ +#include "EquivalenceModel.hxx" +#include "EQM_MLP_PWR_MOxEUS.hxx" +#include "CLASSLogger.hxx" +#include "StringLine.hxx" + +#include <string> +#include <iostream> +#include <fstream> +#include <algorithm> +#include <cmath> +#include <cassert> + +#include "TSystem.h" +#include "TMVA/Reader.h" +#include "TMVA/Tools.h" +#include "TMVA/MethodCuts.h" + + +//________________________________________________________________________ +// +// EQM_MLP_PWR_MOxEUS +// +// Equivalenve Model based on multi layer perceptron from TMVA (root cern) +// For PWR MOxEUS use +// -> MOxEUS building +// - if PuMassContent calculated < Maximal Pu value => MOx fuel +// - if PuMassContent calculated > Maximal Pu value => Uranium enrichment adjusted to reach BU +// +//________________________________________________________________________ + +EQM_MLP_PWR_MOxEUS::EQM_MLP_PWR_MOxEUS(string TMVAWeightPath, int NumOfBatch, double CriticalityThreshold, double MaximalPuMassContent):EquivalenceModel(new CLASSLogger("EQM_MLP_PWR_MOxEUS.log")) +{ + fNumberOfBatch = NumOfBatch; + fKThreshold = CriticalityThreshold ; + fMaximalPuMassContent = MaximalPuMassContent; + + fTMVAWeightPath.push_back(TMVAWeightPath); + + ZAI U8(92,238,0); + ZAI U5(92,235,0); + ZAI Pu8(94,238,0); + ZAI Pu9(94,239,0); + ZAI Pu0(94,240,0); + ZAI Pu1(94,241,0); + ZAI Pu2(94,242,0); + + fStreamList["PuList"] = Pu8*1+Pu9*1+Pu0*1+Pu1*1+Pu2*1; + fStreamList["EnrichmentList"] = U5*1; + fStreamList["FertileList"] = U8*1; + fFirstGuessContent["PuList"] = 0.02; + fFirstGuessContent["EnrichmentList"] = (1-fFirstGuessContent["PuList"])*0.0025; + fFirstGuessContent["FertileList"] = 1 - fFirstGuessContent["PuList"] - fFirstGuessContent["EnrichmentList"]; + + fSpecificPower = 34.24; + fMaximalPuMolarContent = 0.20; + fMaximalBU = 100; + + SetMinimalU5Enrichment(0.0025); + SetMaximalU5Enrichment(0.10); + + SetBurnUpPrecision(0.005);//1 % of the targeted burnup + SetPCMPrecision(10); + + INFO<<"__An equivalence model of PWR MOxEUS has been define__"<<endl; + INFO<<"\tThis model is based on a multi layer perceptron"<<endl; + INFO<<"\t\tThe TMVA weight file is :"<<endl; + INFO<<"\t\t\t"<<fTMVAWeightPath[0]<<endl; + +} + +//________________________________________________________________________ +EQM_MLP_PWR_MOxEUS::EQM_MLP_PWR_MOxEUS(CLASSLogger* log, string TMVAWeightPath, int NumOfBatch, double CriticalityThreshold, double MaximalPuMassContent):EquivalenceModel(log) +{ + fNumberOfBatch = NumOfBatch; + fKThreshold = CriticalityThreshold ; + fMaximalPuMassContent = MaximalPuMassContent; + + fTMVAWeightPath.push_back(TMVAWeightPath); + + ZAI U8(92,238,0); + ZAI U5(92,235,0); + ZAI Pu8(94,238,0); + ZAI Pu9(94,239,0); + ZAI Pu0(94,240,0); + ZAI Pu1(94,241,0); + ZAI Pu2(94,242,0); + + fStreamList["PuList"] = Pu8*1+Pu9*1+Pu0*1+Pu1*1+Pu2*1; + fStreamList["EnrichmentList"] = U5*1; + fStreamList["FertileList"] = U8*1; + fFirstGuessContent["PuList"] = 0.02; + fFirstGuessContent["EnrichmentList"] = (1-fFirstGuessContent["PuList"])*0.0025; + fFirstGuessContent["FertileList"] = 1 - fFirstGuessContent["PuList"] - fFirstGuessContent["EnrichmentList"]; + + fSpecificPower = 34.24; + fMaximalPuMolarContent = 0.20; + fMaximalBU = 100; + + SetMinimalU5Enrichment(0.0025); + SetMaximalU5Enrichment(0.10); + + SetBurnUpPrecision(0.005);//1 % of the targeted burnup + SetPCMPrecision(10); + + INFO<<"__An equivalence model of PWR MOxEUS has been define__"<<endl; + INFO<<"\tThis model is based on a multi layer perceptron"<<endl; + INFO<<"\t\tThe TMVA weight file is :"<<endl; + INFO<<"\t\t\t"<<fTMVAWeightPath[0]<<endl; + +} + +//________________________________________________________________________ +map <string , vector<double> > EQM_MLP_PWR_MOxEUS::BuildFuel(double BurnUp, double HMMass, map < string , vector <IsotopicVector> > StreamArray) +{ + + map <string , vector<double> > lambda ; // map containing name of the list and associated vector of proportions taken from stocks + + //Iterators declaration + map < string , vector <IsotopicVector> >::iterator it_s_vIV; + map < string , vector <double> >::iterator it_s_vD; + map < string , IsotopicVector >::iterator it_s_IV; + map < string , double >::iterator it_s_D; + map < string , bool >::iterator it_s_B; + + for( it_s_vIV = StreamArray.begin(); it_s_vIV != StreamArray.end(); it_s_vIV++) + { + for(int i=0; i<StreamArray[(*it_s_vIV).first].size(); i++) + { + lambda[(*it_s_vIV).first].push_back(0); + } + } + + /*** Test if there is stocks **/ + bool BreakReturnLambda = false; + for( it_s_vIV = StreamArray.begin(); it_s_vIV != StreamArray.end(); it_s_vIV++) + { + if(StreamArray[(*it_s_vIV).first].size() == 0) + { + WARNING << " No stock available for stream : "<< (*it_s_vIV).first <<". Fuel not build." << endl; + SetLambdaToErrorCode(lambda[(*it_s_vIV).first]); + BreakReturnLambda = true; + } + } + if(BreakReturnLambda) { return lambda;} + HMMass *= 1e6; //Unit onversion : tons to gram + + /**** Some initializations **/ + for( it_s_vIV = StreamArray.begin(); it_s_vIV != StreamArray.end(); it_s_vIV++) + fTotalMassInStocks[(*it_s_vIV).first] = 0; + + StocksTotalMassCalculation(StreamArray); + + fActualMassContentInFuel = GetBuildFuelFirstGuess(); + int loopCount = 0; + bool FuelBuiltCorrectly = false ; + + map <string , IsotopicVector > IVStream; + map <string , double > MaterialMolarContent; + map <string , double > MaterialMassContent; + map <string , double > MaterialMassNeeded; + map <string , double > LambdaNeeded; + + for( it_s_vIV = StreamArray.begin(); it_s_vIV != StreamArray.end(); it_s_vIV++) + LambdaNeeded[(*it_s_vIV).first] = 0; + + for( it_s_vIV = StreamArray.begin(); it_s_vIV != StreamArray.end(); it_s_vIV++) + MaterialMassNeeded[(*it_s_vIV).first] = HMMass*fActualMassContentInFuel[(*it_s_vIV).first]; + + do + { + map < string , double > MaterialMeanMolar; + map < string , double > MaterialMassAvailable; + map < string , bool > CheckOnMass; + + double FuelMeanMolar = 0; + + bool NotEnoughPuInStock = false; + BreakReturnLambda = false; + + for( it_s_D = MaterialMolarContent.begin(); it_s_D != MaterialMolarContent.end(); it_s_D++) + { + MaterialMolarContent[(*it_s_D).first] = 0; + MaterialMassContent[(*it_s_D).first] = 0; + } + + for( it_s_vIV = StreamArray.begin(); it_s_vIV != StreamArray.end(); it_s_vIV++) + LambdaNeeded[(*it_s_vIV).first] = LambdaCalculation((*it_s_vIV).first, MaterialMassNeeded[(*it_s_vIV).first], StreamArray[(*it_s_vIV).first]); + + for( it_s_D = LambdaNeeded.begin(); it_s_D != LambdaNeeded.end(); it_s_D++) + { + if( LambdaNeeded[(*it_s_D).first] == -1 ) + { + SetLambdaToErrorCode(lambda[(*it_s_D).first]); + WARNING << "Not enough : "<< (*it_s_D).first <<" to build fuel." << endl; + BreakReturnLambda = true; + } + } + + if(BreakReturnLambda && !NotEnoughPuInStock){ return lambda;} + + if(BreakReturnLambda && NotEnoughPuInStock) + { + MaterialMolarContent["PuList"] = -1; + break; + } + + for( it_s_D = LambdaNeeded.begin(); it_s_D != LambdaNeeded.end(); it_s_D++) + SetLambda(lambda[(*it_s_D).first], LambdaNeeded[(*it_s_D).first]); + + for( it_s_vIV = StreamArray.begin(); it_s_vIV != StreamArray.end(); it_s_vIV++) + IVStream[(*it_s_vIV).first].Clear(); + + for( it_s_vIV = StreamArray.begin(); it_s_vIV != StreamArray.end(); it_s_vIV++) + { + for(int i=0; i<StreamArray[(*it_s_vIV).first].size(); i++) + IVStream[(*it_s_vIV).first] += lambda[(*it_s_vIV).first][i] * StreamArray[(*it_s_vIV).first][i]; + } + + if (loopCount > fMaxInterration) + { + ERROR << "Too much iterration in BuildFuel Method !"; + ERROR << "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 */ + MaterialMolarContent = GetMolarFraction(IVStream, BurnUp); + + for( it_s_D = MaterialMolarContent.begin(); it_s_D != MaterialMolarContent.end(); it_s_D++) + { + if( MaterialMolarContent[(*it_s_D).first] < 0 || MaterialMolarContent[(*it_s_D).first] > 1 ) + { + SetLambdaToErrorCode(lambda[(*it_s_D).first]); + WARNING << "GetFissileMolarFraction return negative or greater than one value, at least for one material : "<<(*it_s_D).first; + return lambda; + } + } + + for( it_s_IV = IVStream.begin(); it_s_IV != IVStream.end(); it_s_IV++) + MaterialMassAvailable[(*it_s_IV).first] = IVStream[(*it_s_IV).first].GetTotalMass()*1e06; + + for( it_s_D = MaterialMolarContent.begin(); it_s_D != MaterialMolarContent.end(); it_s_D++) + { + MaterialMeanMolar[(*it_s_D).first] = IVStream[(*it_s_D).first].GetMeanMolarMass(); + FuelMeanMolar += MaterialMolarContent[(*it_s_D).first] * MaterialMeanMolar[(*it_s_D).first]; + } + + for( it_s_D = MaterialMolarContent.begin(); it_s_D != MaterialMolarContent.end(); it_s_D++) + MaterialMassContent [(*it_s_D).first] = MaterialMolarContent[(*it_s_D).first] * MaterialMeanMolar[(*it_s_D).first] / FuelMeanMolar; + + fActualMolarContentInFuel = MaterialMolarContent; //fActualMolarContentInFuel can be accessed by a derivated EquivalenModel to accelerate GetMolarFraction function (exemple in EQM_MLP_Kinf) + + for( it_s_D = MaterialMassContent.begin(); it_s_D != MaterialMassContent.end(); it_s_D++) + MaterialMassNeeded[(*it_s_D).first] = HMMass*MaterialMassContent[(*it_s_D).first]; + + for( it_s_D = MaterialMassNeeded.begin(); it_s_D != MaterialMassNeeded.end(); it_s_D++) + { + double DeltaM = fabs(MaterialMassNeeded[(*it_s_D).first] - MaterialMassAvailable[(*it_s_D).first]) / HMMass ; + if(DeltaM<fRelativMassPrecision) {CheckOnMass[(*it_s_D).first] = true;} + else{CheckOnMass[(*it_s_D).first] = false;} + } + + FuelBuiltCorrectly = true; + for( it_s_B = CheckOnMass.begin(); it_s_B != CheckOnMass.end(); it_s_B++) + { + if(!CheckOnMass[(*it_s_B).first]) {FuelBuiltCorrectly = false;} + } + + loopCount++; + + }while(!FuelBuiltCorrectly); + + if(MaterialMassContent["PuList"]>fMaximalPuMassContent || MaterialMolarContent["PuList"]==-1) + { + for( it_s_vD = lambda.begin(); it_s_vD != lambda.end(); it_s_vD++) + lambda[(*it_s_vD).first].clear(); + + for( it_s_D = LambdaNeeded.begin(); it_s_D != LambdaNeeded.end(); it_s_D++) + LambdaNeeded[(*it_s_D).first] = 0; + + for( it_s_IV = IVStream.begin(); it_s_IV != IVStream.end(); it_s_IV++) + IVStream[(*it_s_IV).first] = IsotopicVector(); + + if(MaterialMassContent["PuList"]>fMaximalPuMassContent) + { + MaterialMolarContent["PuList"] = 0; + MaterialMassNeeded["PuList"] = fMaximalPuMassContent*HMMass; + LambdaNeeded["PuList"] = LambdaCalculation("PuList", MaterialMassNeeded["PuList"], StreamArray["PuList"]); + } + + if(MaterialMolarContent["PuList"]==-1) + { + LambdaNeeded["PuList"] = LambdaCalculation("PuList", fTotalMassInStocks["PuList"], StreamArray["PuList"]); + } + + SetLambda(lambda["PuList"], LambdaNeeded["PuList"]); + + for( int i = 0 ; i < (int)lambda["PuList"].size() ; i++ ) + IVStream["PuList"] +=lambda["PuList"][i] * StreamArray["PuList"][i]; + + fActualMassContentInFuel["PuList"] = (IVStream["PuList"].GetTotalMass()*1e6)/HMMass; + + LambdaNeeded["EnrichmentList"] = LambdaCalculation("EnrichmentList", HMMass, StreamArray["EnrichmentList"]); + LambdaNeeded["FertileList"] = LambdaCalculation("FertileList", HMMass, StreamArray["FertileList"]); + + SetLambda(lambda["EnrichmentList"], LambdaNeeded["EnrichmentList"]); + SetLambda(lambda["FertileList"], LambdaNeeded["FertileList"]); + + for( int i = 0 ; i < (int)lambda["EnrichmentList"].size() ; i++ ) + IVStream["EnrichmentList"] +=lambda["EnrichmentList"][i] * StreamArray["EnrichmentList"][i]; + + for( int i = 0 ; i < (int)lambda["FertileList"].size() ; i++ ) + IVStream["FertileList"] +=lambda["FertileList"][i] * StreamArray["FertileList"][i]; + + double U5Enrichment = GetU5Enrichment(IVStream, BurnUp); + double MeanMolarUdepleted = U5Enrichment*IVStream["EnrichmentList"].GetMeanMolarMass() + (1 - U5Enrichment)*IVStream["FertileList"].GetMeanMolarMass(); + + double UdepletedMassNeeded = (HMMass - IVStream["PuList"].GetTotalMass() * 1e6); + double EnrichedSupportMassNeeded = U5Enrichment*UdepletedMassNeeded*IVStream["EnrichmentList"].GetMeanMolarMass()/IVStream["FertileList"].GetMeanMolarMass(); + double FertilMassNeeded = UdepletedMassNeeded - EnrichedSupportMassNeeded; + + LambdaNeeded["EnrichmentList"] = LambdaCalculation("EnrichmentList", EnrichedSupportMassNeeded, StreamArray["EnrichmentList"]); + LambdaNeeded["FertileList"] = LambdaCalculation("FertileList", FertilMassNeeded, StreamArray["FertileList"]); + + BreakReturnLambda = false; + + for( it_s_D = LambdaNeeded.begin(); it_s_D != LambdaNeeded.end(); it_s_D++) + { + if( LambdaNeeded[(*it_s_D).first] == -1 ) + { + SetLambdaToErrorCode(lambda[(*it_s_D).first]); + WARNING << "Not enough : "<< (*it_s_D).first <<" to build fuel." << endl; + BreakReturnLambda = true; + } + } + if(BreakReturnLambda) { return lambda;} + + SetLambda(lambda["EnrichmentList"], LambdaNeeded["EnrichmentList"]); + SetLambda(lambda["FertileList"], LambdaNeeded["FertileList"]); + + IVStream["EnrichmentList"] = IsotopicVector(); + IVStream["FertileList"] = IsotopicVector(); + + for( int i = 0 ; i < (int)lambda["EnrichmentList"].size() ; i++ ) + IVStream["EnrichmentList"] +=lambda["EnrichmentList"][i] * StreamArray["EnrichmentList"][i]; + + for( int i = 0 ; i < (int)lambda["FertileList"].size() ; i++ ) + IVStream["FertileList"] +=lambda["FertileList"][i] * StreamArray["FertileList"][i]; + } + + for( it_s_D = MaterialMassNeeded.begin(); it_s_D != MaterialMassNeeded.end(); it_s_D++) + DBGV( "Weight percent : "<<(*it_s_D).first<<" "<< MaterialMassNeeded[(*it_s_D).first]/HMMass); + + for( it_s_vD = lambda.begin(); it_s_vD != lambda.end(); it_s_vD++) + { + DBGV( "Lambda vector : "<<(*it_s_vD).first ); + + for(int i=0; i<lambda[(*it_s_vD).first].size(); i++) + { + DBGV(lambda[(*it_s_vD).first][i]); + } + } + + return lambda; +} + +//________________________________________________________________________ +TTree* EQM_MLP_PWR_MOxEUS::CreateTMVAInputTree(IsotopicVector TheFuel, double ThisTime) +{ + TTree* InputTree = new TTree("EQTMP", "EQTMP"); + + float Pu8 = 0; + float Pu9 = 0; + float Pu10 = 0; + float Pu11 = 0; + float Pu12 = 0; + float Am1 = 0; + float U5 = 0; + float U8 = 0; + float Time = 0; + + InputTree->Branch( "U5" ,&U5 ,"U5/F" ); + InputTree->Branch( "U8" ,&U8 ,"U8/F" ); + InputTree->Branch( "Pu8" ,&Pu8 ,"Pu8/F" ); + InputTree->Branch( "Pu9" ,&Pu9 ,"Pu9/F" ); + InputTree->Branch( "Pu10" ,&Pu10 ,"Pu10/F" ); + InputTree->Branch( "Pu11" ,&Pu11 ,"Pu11/F" ); + InputTree->Branch( "Pu12" ,&Pu12 ,"Pu12/F" ); + InputTree->Branch( "Am1" ,&Am1 ,"Am1/F" ); + InputTree->Branch( "Time" ,&Time ,"Time/F" ); + + double Ntot = TheFuel.GetSumOfAll(); + + U5 = TheFuel.GetZAIIsotopicQuantity(92,235,0)/Ntot; + U8 = TheFuel.GetZAIIsotopicQuantity(92,238,0)/Ntot; + Pu8 = TheFuel.GetZAIIsotopicQuantity(94,238,0)/Ntot; + Pu9 = TheFuel.GetZAIIsotopicQuantity(94,239,0)/Ntot; + Pu10 = TheFuel.GetZAIIsotopicQuantity(94,240,0)/Ntot; + Pu11 = TheFuel.GetZAIIsotopicQuantity(94,241,0)/Ntot; + Pu12 = TheFuel.GetZAIIsotopicQuantity(94,242,0)/Ntot; + Am1 = TheFuel.GetZAIIsotopicQuantity(95,241,0)/Ntot; + + Time=ThisTime; + + InputTree->Fill(); + return InputTree; +} +//________________________________________________________________________ +double EQM_MLP_PWR_MOxEUS::ExecuteTMVA(TTree* theTree, string WeightPath) +{ + // --- Create the Reader object + TMVA::Reader *reader = new TMVA::Reader( "Silent" ); + // Create a set of variables and declare them to the reader + // - the variable names MUST corresponds in name and type to those given in the weight file(s) used + Float_t U5, U8, Pu8,Pu9,Pu10,Pu11,Pu12,Am1, Time; + + reader->AddVariable( "U5" ,&U5 ); + reader->AddVariable( "U8" ,&U8 ); + reader->AddVariable( "Pu8" ,&Pu8 ); + reader->AddVariable( "Pu9" ,&Pu9 ); + reader->AddVariable( "Pu10" ,&Pu10 ); + reader->AddVariable( "Pu11" ,&Pu11 ); + reader->AddVariable( "Pu12" ,&Pu12 ); + reader->AddVariable( "Am1" ,&Am1 ); + reader->AddVariable( "Time" ,&Time ); + + // --- Book the MVA methods + + // Book method MLP + TString methodName = "MLP method"; + reader->BookMVA( methodName, fTMVAWeightPath[0] ); + theTree->SetBranchAddress( "U5" ,&U5 ); + theTree->SetBranchAddress( "U8" ,&U8 ); + theTree->SetBranchAddress( "Pu8" ,&Pu8 ); + theTree->SetBranchAddress( "Pu9" ,&Pu9 ); + theTree->SetBranchAddress( "Pu10" ,&Pu10 ); + theTree->SetBranchAddress( "Pu11" ,&Pu11 ); + theTree->SetBranchAddress( "Pu12" ,&Pu12 ); + theTree->SetBranchAddress( "Am1" ,&Am1 ); + theTree->SetBranchAddress( "Time" ,&Time ); + + theTree->GetEntry(0); + + Float_t val = (reader->EvaluateRegression( methodName ))[0]; + + delete reader; + return (double)val; //return k_eff +} + +//________________________________________________________________________ +double EQM_MLP_PWR_MOxEUS::GetMaximumBurnUp(IsotopicVector TheFuel, double TargetBU) +{ + /**************************************************************************/ + //With a dichotomy, the maximal irradiation time (TheFinalTime) is calculated + //When average Kinf is very close (according "Precision") to the threshold + //then the corresponding irradiation time is convert in burnup and returned + /**************************************************************************/ + //Algorithm initialization + + double TheFinalTime = BurnupToSecond(TargetBU); + double OldFinalTimeMinus = 0; + double MaximumBU = fMaximalBU; + double OldFinalTimePlus = BurnupToSecond(MaximumBU); + double k_av = 0; //average kinf + double OldPredictedk_av = 0; + + for(int b=0;b<fNumberOfBatch;b++) + { + float TheTime = (b+1)*TheFinalTime/fNumberOfBatch; + TTree* InputTree = CreateTMVAInputTree(TheFuel,TheTime); + OldPredictedk_av += ExecuteTMVA(InputTree,fTMVAWeightPath[0]); + delete InputTree; + } + OldPredictedk_av/=fNumberOfBatch; + + //Algorithm control + int count=0; + int MaximumLoopCount = 500; + do + { + if(count > MaximumLoopCount ) + { + ERROR<<"CRITICAL ! Can't manage to predict burnup\nHint : Try to increase the precision on k effective using :\n YourEQM_MLP_Kinf->SetPCMprecision(pcm); with pcm the precision in pcm (default 10) REDUCE IT\n If this message still appear mail to leniau@subatech.in2p3.fr\nor nicolas.thiolliere@subatech.in2p3.fr "<<endl; + exit(1); + } + + if( (OldPredictedk_av-fKThreshold) > 0) //The burnup can be increased + { + OldFinalTimeMinus = TheFinalTime; + TheFinalTime = TheFinalTime + fabs(OldFinalTimePlus - TheFinalTime)/2.; + + if(SecondToBurnup(TheFinalTime) >= (MaximumBU-MaximumBU*GetBurnUpPrecision() ) ) + return MaximumBU; + } + + else if( (OldPredictedk_av-fKThreshold) < 0)//The burnup is too high + { + OldFinalTimePlus = TheFinalTime; + TheFinalTime = TheFinalTime - fabs(OldFinalTimeMinus - TheFinalTime)/2.; + if( SecondToBurnup(TheFinalTime) < TargetBU*GetBurnUpPrecision() ) + return 0; + } + + k_av = 0; + for(int b=0;b<fNumberOfBatch;b++) + { + float TheTime = (b+1)*TheFinalTime/fNumberOfBatch; + TTree* InputTree = CreateTMVAInputTree(TheFuel,TheTime); + k_av += ExecuteTMVA(InputTree,fTMVAWeightPath[0]); + delete InputTree; + } + k_av/=fNumberOfBatch; + + OldPredictedk_av = k_av; + count++; + } while( fabs(OldPredictedk_av-fKThreshold) > GetPCMPrecision() ) ; + + return SecondToBurnup(TheFinalTime); +} + +//________________________________________________________________________ +map < string , double> EQM_MLP_PWR_MOxEUS::GetMolarFraction(map <string , IsotopicVector > IVStream, double TargetBU) +{ + + IsotopicVector Pu = IVStream["PuList"]; + IsotopicVector EnrichedSupport = IVStream["EnrichmentList"]; + IsotopicVector Fertil = IVStream["FertileList"]; + + map < string , double> MolarFraction ; + + double OldPuContentMinus = 0; + double OldPuContentPlus = fMaximalPuMolarContent; + + double PredictedBU = 0 ; + double PuContent = fActualMolarContentInFuel["PuList"]; + double U5Enrichment = fMinimalU5Enrichment; + + IsotopicVector FreshFuel = PuContent*(Pu/Pu.GetSumOfAll()) + U5Enrichment*(1-PuContent) *(EnrichedSupport/EnrichedSupport.GetSumOfAll()) + (1 - U5Enrichment)*(1-PuContent)*(Fertil/Fertil.GetSumOfAll()); + double OldPredictedBU = GetMaximumBurnUp(FreshFuel,TargetBU); + + double Precision = GetBurnUpPrecision()*TargetBU; //1 % of the targeted burnup + int count = 0; + int MaximumLoopCount = 500; + do + { + if(count > MaximumLoopCount ) + { + ERROR<<"CRITICAL ! Can't manage to predict fissile content\nHint : Try to decrease the precision on burnup using :\nYourEQM_MLP_Kinf->SetBurnUpPrecision(prop); with prop the precision (default 0.5percent : 0.005) INCREASE IT\nIf this message still appear mail to leniau@subatech.in2p3.fr\nor nicolas.thiolliere@subatech.in2p3.fr "<<endl; + exit(1); + } + if( (OldPredictedBU - TargetBU) < 0 ) //The Content can be increased + { + OldPuContentMinus = PuContent; + PuContent = PuContent + fabs(OldPuContentPlus-PuContent)/2.; + } + else if( (OldPredictedBU - TargetBU) > 0) //The Content is too high + { + OldPuContentPlus = PuContent; + PuContent = PuContent - fabs(OldPuContentMinus-PuContent)/2.; + } + + IsotopicVector FreshFuel= PuContent*(Pu/Pu.GetSumOfAll()) + U5Enrichment*(1-PuContent) *(EnrichedSupport/EnrichedSupport.GetSumOfAll()) + (1 - U5Enrichment)*(1-PuContent)*(Fertil/Fertil.GetSumOfAll()); + PredictedBU = GetMaximumBurnUp(FreshFuel,TargetBU); + + OldPredictedBU = PredictedBU; + count ++; + + }while(fabs(TargetBU-PredictedBU)>Precision); + + DBGV("Predicted BU "<<PredictedBU<<" PuContent "<<PuContent); + + MolarFraction["PuList"] = PuContent; + MolarFraction["EnrichmentList"] = (1 - MolarFraction["PuList"])*fMinimalU5Enrichment; + MolarFraction["FertileList"] = 1 - MolarFraction["PuList"] - MolarFraction["EnrichmentList"]; + +return MolarFraction; +} +//________________________________________________________________________ + +//________________________________________________________________________ +double EQM_MLP_PWR_MOxEUS::GetU5Enrichment(map <string , IsotopicVector > IVStream, double TargetBU) +{ + IsotopicVector Pu = IVStream["PuList"]; + IsotopicVector EnrichedSupport = IVStream["EnrichmentList"]; + IsotopicVector Fertil = IVStream["FertileList"]; + + double OldU5EnrichmentMinus= fMinimalU5Enrichment; + double OldU5EnrichmentPlus = fMaximalU5Enrichment; + double U5Enrichment = fMinimalU5Enrichment; + + double PredictedBU = 0 ; + double USupportMassNeeded = (Pu.GetTotalMass()*1e6)/fActualPuMassContent - (Pu.GetTotalMass()*1e6); + + IsotopicVector USupport = U5Enrichment*EnrichedSupport + (1 - U5Enrichment)*Fertil; + double USupportMassContent = USupportMassNeeded/(USupport.GetTotalMass()*1e6); + + IsotopicVector FreshFuel = Pu + USupportMassContent*USupport; + FreshFuel = FreshFuel/FreshFuel.GetSumOfAll(); + + double OldPredictedBU = GetMaximumBurnUp(FreshFuel,TargetBU); + double Precision = GetBurnUpPrecision()*TargetBU; //1 % of the targeted burnup + int count = 0; + int MaximumLoopCount = 500; + + do + { + + if(count > MaximumLoopCount ) + { + ERROR<<"CRITICAL ! Can't manage to predict fissile content\nHint : Try to decrease the precision on burnup using :\nYourEQM_MLP_Kinf->SetBurnUpPrecision(prop); with prop the precision (default 0.5percent : 0.005) INCREASE IT\nIf this message still appear mail to leniau@subatech.in2p3.fr\nor nicolas.thiolliere@subatech.in2p3.fr "<<endl; + exit(1); + } + if( (OldPredictedBU - TargetBU) < 0 ) //The Content can be increased + { + OldU5EnrichmentMinus = U5Enrichment; + U5Enrichment = U5Enrichment + fabs(OldU5EnrichmentPlus-U5Enrichment)/2.; + } + else if( (OldPredictedBU - TargetBU) > 0) //The Content is too high + { + OldU5EnrichmentPlus = U5Enrichment; + U5Enrichment = U5Enrichment - fabs(OldU5EnrichmentMinus-U5Enrichment)/2.; + } + + IsotopicVector USupport = U5Enrichment*EnrichedSupport + (1 - U5Enrichment)*Fertil; + + double USupportMassContent = USupportMassNeeded/(USupport.GetTotalMass()*1e6); + IsotopicVector FreshFuel = Pu + USupportMassContent*USupport; + FreshFuel = FreshFuel/FreshFuel.GetSumOfAll(); + + PredictedBU = GetMaximumBurnUp(FreshFuel,TargetBU); + + OldPredictedBU = PredictedBU; + count ++; + }while(fabs(TargetBU-PredictedBU)>Precision); + +DBGV("Predicted BU "<<PredictedBU<<" U5Enrichment "<<U5Enrichment); +return U5Enrichment; + +} \ No newline at end of file diff --git a/source/branches/CLASSV4.2/Model/Equivalence/EQM_MLP_PWR_MOxEUS.hxx b/source/branches/CLASSV4.2/Model/Equivalence/EQM_MLP_PWR_MOxEUS.hxx new file mode 100644 index 000000000..e4a138cf3 --- /dev/null +++ b/source/branches/CLASSV4.2/Model/Equivalence/EQM_MLP_PWR_MOxEUS.hxx @@ -0,0 +1,67 @@ +#ifndef _EQM_MLP_PWR_MOxEUS_HXX +#define _EQM_MLP_PWR_MOxEUS_HXX + +#include "EquivalenceModel.hxx" +#include "TTree.h" + +/*! + \file + \brief Header file for EQM_MLP_PWR_MOxEUS + + + @author FC + @version 1.0 + */ +class EQM_MLP_PWR_MOxEUS : public EquivalenceModel +{ + public : + + EQM_MLP_PWR_MOxEUS(string TMVAWeightPath, int NumOfBatch, double CriticalityThreshold, double MaximalPuMassContent); + EQM_MLP_PWR_MOxEUS(CLASSLogger* log, string TMVAWeightPath, int NumOfBatch, double CriticalityThreshold, double MaximalPuMassContent); + + virtual map <string , vector<double> > BuildFuel(double BurnUp, double HMMass, map < string , vector <IsotopicVector> > StreamArray); + + void SetSpecificPower(double SpecificPower) {fSpecificPower = SpecificPower;} + void SetMinimalU5Enrichment(double MinEU5) {fMinimalU5Enrichment= MinEU5;} + void SetMaximalU5Enrichment(double MaxEU5){fMaximalU5Enrichment= MaxEU5;} + void SetBurnUpPrecision(double precision) {fBurnUpPrecision= precision;} + void SetPCMPrecision(double prop) {fPCMPrecision= prop;} + + double GetBurnUpPrecision(){return fBurnUpPrecision;} + double GetPCMPrecision(){return fPCMPrecision/1e5;} + double GetMinimalU5Enrichment(){return fMinimalU5Enrichment;}; + + TTree* CreateTMVAInputTree(IsotopicVector TheFuel, double ThisTime); + double ExecuteTMVA(TTree* theTree, string WeightPath); + double GetMaximumBurnUp(IsotopicVector TheFuel, double TargetBU); + double GetU5Enrichment(map <string , IsotopicVector > IVStream, double TargetBU); + + map < string , double> GetMolarFraction(map < string , IsotopicVector> IVStream, double BurnUp); + + private: + + double BurnupToSecond(double BurnUp){return BurnUp/fSpecificPower*(24*3.6e6);} + double SecondToBurnup(double Second){return Second*fSpecificPower/(24*3.6e6);} + + int fNumberOfBatch ; + double fKThreshold ; + double fSpecificPower ; + double fMaximalBU; + double fBurnUpPrecision; + double fPCMPrecision; + + double fActualPuMolarContent; + double fActualPuMassContent; + double fMaximalPuMassContent ; + double fMaximalPuMolarContent; + double fMinimalU5Enrichment; + double fMaximalU5Enrichment; + + vector <string> fTMVAWeightPath; //!<The weight needed by TMVA to construct and execute the multilayer perceptron + + + + +}; + +#endif \ No newline at end of file -- GitLab