diff --git a/src/Routines/MinimizerRoutines.cxx b/src/Routines/MinimizerRoutines.cxx index 4c725e2..8469fd8 100755 --- a/src/Routines/MinimizerRoutines.cxx +++ b/src/Routines/MinimizerRoutines.cxx @@ -1,1589 +1,1594 @@ // Copyright 2016 L. Pickering, P Stowell, R. Terri, C. Wilkinson, C. Wret /******************************************************************************* * This file is part of NUISANCE. * * NUISANCE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * NUISANCE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NUISANCE. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ #include "StatusMessage.h" #include "MinimizerRoutines.h" /* Constructor/Destructor */ //************************ void MinimizerRoutines::Init(){ //************************ fInputFile = ""; fInputRootFile = NULL; fOutputFile = ""; fOutputRootFile = NULL; fCovar = NULL; fCovFree = NULL; fCorrel = NULL; fCorFree = NULL; fDecomp = NULL; fDecFree = NULL; fStrategy = "Migrad,FixAtLimBreak,Migrad"; fRoutines.clear(); fCardFile = ""; fFakeDataInput = ""; fSampleFCN = NULL; fMinimizer = NULL; fMinimizerFCN = NULL; fCallFunctor = NULL; fAllowedRoutines = ("Migrad,Simplex,Combined," "Brute,Fumili,ConjugateFR," "ConjugatePR,BFGS,BFGS2," "SteepDesc,GSLSimAn,FixAtLim,FixAtLimBreak" "Chi2Scan1D,Chi2Scan2D,Contours,ErrorBands"); }; //************************************* MinimizerRoutines::~MinimizerRoutines(){ //************************************* }; /* Input Functions */ //************************************* MinimizerRoutines::MinimizerRoutines(int argc, char* argv[]){ //************************************* // Set everything to defaults Init(); std::vector<std::string> configs_cmd; std::string maxevents_flag = ""; int verbosity_flag = 0; int error_flag = 0; // If No Arguments print commands for (int i = 1; i< argc; ++i){ if (i+1 != argc){ // Cardfile if (!std::strcmp(argv[i], "-c")) { fCardFile=argv[i+1]; ++i;} else if (!std::strcmp(argv[i], "-o")) { fOutputFile=argv[i+1]; ++i;} else if (!std::strcmp(argv[i], "-f")) { fStrategy=argv[i+1]; ++i;} else if (!std::strcmp(argv[i], "-d")) { fFakeDataInput=argv[i+1]; ++i;} else if (!std::strcmp(argv[i], "-q")) { configs_cmd.push_back(argv[i+1]); ++i;} else if (!std::strcmp(argv[i], "-n")) { maxevents_flag=argv[i+1]; ++i;} else if (!std::strcmp(argv[i], "-v")) { verbosity_flag -= 1; } else if (!std::strcmp(argv[i], "+v")) { verbosity_flag += 1; } else if (!std::strcmp(argv[i], "-e")) { error_flag -= 1; } else if (!std::strcmp(argv[i], "+e")) { error_flag += 1; } else { ERR(FTL) << "ERROR: unknown command line option given! - '" <<argv[i]<<" "<<argv[i+1]<<"'"<< std::endl; throw; } } } if (fOutputFile.empty()) { ERR(WRN) << "WARNING: output file not specified." << std::endl; ERR(WRN) << "Using " << fCardFile << ".root" << std::endl; fOutputFile = fCardFile + ".root"; } if (fCardFile == fOutputFile) { ERR(WRN) << "WARNING: output file and card file are the same file, " "writing: " << fCardFile << ".root" << std::endl; fOutputFile = fCardFile + ".root"; } if(fCardFile == fOutputFile){ std::cerr << "WARNING: output file and card file are the same file, " "writing: " << fCardFile << ".root" << std::endl; fOutputFile = fCardFile + ".root"; } // Fill fit routines and check they are good fRoutines = GeneralUtils::ParseToStr(fStrategy,","); for (UInt_t i = 0; i < fRoutines.size(); i++){ if (fAllowedRoutines.find(fRoutines[i]) == std::string::npos){ ERR(FTL) << "Unknown fit routine given! " << "Must be provided as a comma seperated list." << std::endl; ERR(FTL) << "Allowed Routines: " << fAllowedRoutines << std::endl; throw; } } // CONFIG // --------------------------- std::string par_dir = GeneralUtils::GetTopLevelDir()+"/parameters/"; FitPar::Config().ReadParamFile( par_dir + "config.list.dat" ); FitPar::Config().ReadParamFile( fCardFile ); for (UInt_t iter = 0; iter < configs_cmd.size(); iter++){ FitPar::Config().ForceParam(configs_cmd[iter]); } if (!maxevents_flag.empty()){ FitPar::Config().SetParI("input.maxevents", atoi(maxevents_flag.c_str())); } if (verbosity_flag != 0){ int curverb = FitPar::Config().GetParI("VERBOSITY"); FitPar::Config().SetParI("VERBOSITY", curverb + verbosity_flag); } if (error_flag != 0){ int curwarn = FitPar::Config().GetParI("ERROR"); FitPar::Config().SetParI("ERROR", curwarn + error_flag); } LOG_VERB(FitPar::Config().GetParI("VERBOSITY")); ERR_VERB(FitPar::Config().GetParI("ERROR")); // CARD // --------------------------- // Parse Card Options ReadCard(fCardFile); // Outputs // --------------------------- // Save Configs to output file fOutputRootFile = new TFile(fOutputFile.c_str(),"RECREATE"); FitPar::Config().Write(); // Starting Setup // --------------------------- SetupCovariance(); SetupRWEngine(); SetupFCN(); return; }; //************************************* void MinimizerRoutines::ReadCard(std::string cardfile){ //************************************* // Read cardlines into vector std::vector<std::string> cardlines = GeneralUtils::ParseFileToStr(cardfile,"\n"); FitPar::Config().cardLines = cardlines; // Read Samples first (norm params can be overridden) int linecount = 0; for (std::vector<std::string>::iterator iter = cardlines.begin(); iter != cardlines.end(); iter++){ std::string line = (*iter); linecount++; // Skip Comments if (line.empty()) continue; if (line.c_str()[0] == '#') continue; // Read Valid Samples int samstatus = ReadSamples(line); // Show line if bad to help user if (samstatus == kErrorStatus) { ERR(FTL) << "Bad Input in cardfile " << fCardFile << " at line " << linecount << "!" << endl; ERR(FTL) << line << endl; throw; } } // Read Parameters second linecount = 0; for (std::vector<std::string>::iterator iter = cardlines.begin(); iter != cardlines.end(); iter++){ std::string line = (*iter); linecount++; // Skip Comments if (line.empty()) continue; if (line.c_str()[0] == '#') continue; // Try Parameter Reads int parstatus = ReadParameters(line); int fakstatus = ReadFakeDataPars(line); // Show line if bad to help user if (parstatus == kErrorStatus || fakstatus == kErrorStatus ){ ERR(FTL) << "Bad Parameter Input in cardfile " << fCardFile << " at line " << linecount << "!" << endl; ERR(FTL) << line << endl; throw; } } return; }; //***************************************** int MinimizerRoutines::ReadParameters(std::string parstring){ //****************************************** std::string inputspec = "RW Dial Inputs Syntax \n" "free input w/ limits: TYPE NAME START MIN MAX STEP [STATE] \n" "fix input: TYPE NAME VALUE [STATE] \n" "free input w/o limits: TYPE NAME START FREE,[STATE] \n" "Allowed Types: \n" "neut_parameter,niwg_parameter,t2k_parameter," "nuwro_parameter,gibuu_parameter"; // Check sample input if (parstring.find("parameter") == std::string::npos) { return kGoodStatus; } // If we find fake_parameter if (parstring.find("fake_parameter") != std::string::npos) { return kGoodStatus; } // Parse inputs std::vector<std::string> strvct = GeneralUtils::ParseToStr(parstring, " "); // Skip if comment or parameter somewhere later in line if (strvct[0].c_str()[0] == '#' || strvct[0].find("parameter") == std::string::npos){ return kGoodStatus; } // Check length if (strvct.size() < 3){ ERR(FTL) << "Input rw dials need to provide at least 3 inputs." << std::endl; std::cout << inputspec << std::endl; return kErrorStatus; } // Setup default inputs std::string partype = strvct[0]; std::string parname = strvct[1]; double parval = GeneralUtils::StrToDbl(strvct[2]); double minval = parval - 1.0; double maxval = parval + 1.0; double stepval = 1.0; std::string state = "FIX"; //[DEFAULT] // Check Type if (FitBase::ConvDialType(partype) == kUNKNOWN){ ERR(FTL) << "Unknown parameter type! " << partype << endl; std::cout << inputspec << std::endl; return kErrorStatus; } // Check Parameter Name if (FitBase::GetDialEnum(partype, parname) == -1){ ERR(FTL) << "Bad RW parameter name! " << partype << " " << parname << endl; std::cout << inputspec << std::endl; return kErrorStatus; } // Option Extra (No Limits) if (strvct.size() == 4){ state = strvct[3]; } // Check for weirder inputs if (strvct.size() > 4 && strvct.size() < 6){ ERR(FTL) << "Provided incomplete limits for " << parname << endl; std::cout << inputspec << std::endl; return kErrorStatus; } // Option Extra (With limits and steps) if (strvct.size() >= 6){ minval = GeneralUtils::StrToDbl(strvct[3]); maxval = GeneralUtils::StrToDbl(strvct[4]); stepval = GeneralUtils::StrToDbl(strvct[5]); } // Option Extra (dial state after limits) if (strvct.size() == 7){ state = strvct[6]; } // Run Parameter Conversion if needed if (state.find("ABS") != std::string::npos){ parval = FitBase::RWAbsToSigma( partype, parname, parval ); minval = FitBase::RWAbsToSigma( partype, parname, minval ); maxval = FitBase::RWAbsToSigma( partype, parname, maxval ); stepval = FitBase::RWAbsToSigma( partype, parname, stepval ); } else if (state.find("FRAC") != std::string::npos){ parval = FitBase::RWFracToSigma( partype, parname, parval ); minval = FitBase::RWFracToSigma( partype, parname, minval ); maxval = FitBase::RWFracToSigma( partype, parname, maxval ); stepval = FitBase::RWFracToSigma( partype, parname, stepval ); } // Check no repeat params if (std::find(fParams.begin(), fParams.end(), parname) != fParams.end()){ ERR(FTL) << "Duplicate parameter names given for " << parname << endl; throw; } // Setup Containers fParams.push_back(parname); fTypeVals[parname] = FitBase::ConvDialType(partype); fStartVals[parname] = parval; fCurVals[parname] = fStartVals[parname]; fErrorVals[parname] = 0.0; fStateVals[parname] = state; bool fixstate = state.find("FIX") != std::string::npos; fFixVals[parname] = fixstate; fStartFixVals[parname] = fFixVals[parname]; fMinVals[parname] = minval; fMaxVals[parname] = maxval; fStepVals[parname] = stepval; // Print the parameter LOG(MIN) << "Read Parameter " << parname << " " << parval << " " << minval << " " << maxval << " " << stepval << " " << state << std::endl; // Tell reader its all good return kGoodStatus; } //******************************************* int MinimizerRoutines::ReadFakeDataPars(std::string parstring){ //****************************************** std::string inputspec = "Fake Data Dial Inputs Syntax \n" "fake value: fake_parameter NAME VALUE \n" "Name should match dialnames given in actual dial specification."; // Check sample input if (parstring.find("fake_parameter") == std::string::npos) return kGoodStatus; // Parse inputs std::vector<std::string> strvct = GeneralUtils::ParseToStr(parstring, " "); // Skip if comment somewhere later in line if (strvct[0].c_str()[0] == '#') { return kGoodStatus; } // Check length if (strvct.size() < 3){ ERR(FTL) << "Fake dials need to provide at least 3 inputs." << std::endl; std::cout << inputspec << std::endl; return kErrorStatus; } // Read Inputs std::string parname = strvct[1]; double parval = GeneralUtils::StrToDbl(strvct[2]); // Setup Container fFakeVals[parname] = parval; // Print the fake parameter LOG(MIN) << "Read Fake Parameter " << parname << " " << parval << std::endl; // Tell reader its all good return kGoodStatus; } //****************************************** int MinimizerRoutines::ReadSamples(std::string samstring){ //****************************************** const static std::string inputspec = "\tsample <sample_name> <input_type>:inputfile.root [OPTS] " "[norm]\nsample_name: Name " "of sample to include. e.g. MiniBooNE_CCQE_XSec_1DQ2_nu\ninput_type: The " "input event format. e.g. NEUT, GENIE, EVSPLN, ...\nOPTS: Additional, " "optional sample options.\nnorm: Additional, optional sample " "normalisation factor."; // Check sample input if (samstring.find("sample") == std::string::npos) return kGoodStatus; // Parse inputs std::vector<std::string> strvct = GeneralUtils::ParseToStr(samstring, " "); // Skip if comment or parameter somewhere later in line if (strvct[0].c_str()[0] == '#' || strvct[0] != "sample"){ return kGoodStatus; } // Check length if (strvct.size() < 3){ ERR(FTL) << "Sample need to provide at least 3 inputs." << std::endl; std::cout << inputspec << std::endl; return kErrorStatus; } // Setup default inputs std::string samname = strvct[1]; std::string samfile = strvct[2]; if (samfile == "FIX") { ERR(FTL) << "Input filename was \"FIX\", this line is probably malformed " "in the input card file. Line:\'" << samstring << "\'" << std::endl; ERR(FTL) << "Expect sample lines to look like:\n\t" << inputspec << std::endl; throw; } std::string samtype = "DEFAULT"; double samnorm = 1.0; // Optional Type if (strvct.size() > 3){ samtype = strvct[3]; samname += "_"+samtype; // Also get rid of the / and replace it with underscore because it might not be supported character while (samname.find("/") != std::string::npos) { samname.replace(samname.find("/"), 1, std::string("_")); } } // Optional Norm if (strvct.size() > 4) samnorm = GeneralUtils::StrToDbl(strvct[4]); // Add Sample Names as Norm Dials std::string normname = samname + "_norm"; // Check no repeat params if (std::find(fParams.begin(), fParams.end(), normname) != fParams.end()){ ERR(FTL) << "Duplicate samples given for " << samname << endl; throw; } fParams.push_back(normname); fTypeVals[normname] = kNORM; fStartVals[normname] = samnorm; fCurVals[normname] = fStartVals[normname]; fErrorVals[normname] = 0.0; fMinVals[normname] = 0.1; fMaxVals[normname] = 10.0; fStepVals[normname] = 0.5; bool state = samtype.find("FREE") == std::string::npos; fFixVals[normname] = state; fStartFixVals[normname] = state; // Print read in LOG(MIN) << "Read sample " << samname << " " << samfile << " " << samtype << " " << samnorm << endl; // Tell reader its all good return kGoodStatus; } /* Setup Functions */ //************************************* void MinimizerRoutines::SetupRWEngine(){ //************************************* for (UInt_t i = 0; i < fParams.size(); i++){ std::string name = fParams[i]; FitBase::GetRW() -> IncludeDial(name, fTypeVals.at(name) ); } UpdateRWEngine(fStartVals); return; } //************************************* void MinimizerRoutines::SetupFCN(){ //************************************* LOG(FIT)<<"Making the jointFCN"<<std::endl; if (fSampleFCN) delete fSampleFCN; fSampleFCN = new JointFCN(fCardFile, fOutputRootFile); SetFakeData(); fMinimizerFCN = new MinimizerFCN( fSampleFCN ); fCallFunctor = new ROOT::Math::Functor( *fMinimizerFCN, fParams.size() ); fSampleFCN->CreateIterationTree( "fit_iterations", FitBase::GetRW() ); return; } //****************************************** void MinimizerRoutines::SetupFitter(std::string routine){ //****************************************** // Make the fitter std::string fitclass = ""; std::string fittype = ""; // Get correct types if (!routine.compare("Migrad")) { fitclass = "Minuit2"; fittype = "Migrad"; } else if (!routine.compare("Simplex")) { fitclass = "Minuit2"; fittype = "Simplex"; } else if (!routine.compare("Combined")) { fitclass = "Minuit2"; fittype = "Combined"; } else if (!routine.compare("Brute")) { fitclass = "Minuit2"; fittype = "Scan"; } else if (!routine.compare("Fumili")) { fitclass = "Minuit2"; fittype = "Fumili"; } else if (!routine.compare("ConjugateFR")) { fitclass = "GSLMultiMin"; fittype = "ConjugateFR"; } else if (!routine.compare("ConjugatePR")) { fitclass = "GSLMultiMin"; fittype = "ConjugatePR"; } else if (!routine.compare("BFGS")) { fitclass = "GSLMultiMin"; fittype = "BFGS"; } else if (!routine.compare("BFGS2")) { fitclass = "GSLMultiMin"; fittype = "BFGS2"; } else if (!routine.compare("SteepDesc")) { fitclass = "GSLMultiMin"; fittype = "SteepestDescent"; // } else if (!routine.compare("GSLMulti")) { fitclass = "GSLMultiFit"; fittype = ""; // Doesn't work out of the box } else if (!routine.compare("GSLSimAn")) { fitclass = "GSLSimAn"; fittype = ""; } // make minimizer if (fMinimizer) delete fMinimizer; fMinimizer = ROOT::Math::Factory::CreateMinimizer(fitclass, fittype); fMinimizer->SetMaxFunctionCalls(FitPar::Config().GetParI("minimizer.maxcalls")); if (!routine.compare("Brute")){ fMinimizer->SetMaxFunctionCalls(fParams.size() * fParams.size()*4); fMinimizer->SetMaxIterations(fParams.size() * fParams.size()*4); } fMinimizer->SetMaxIterations(FitPar::Config().GetParI("minimizer.maxiterations")); fMinimizer->SetTolerance(FitPar::Config().GetParD("minimizer.tolerance")); fMinimizer->SetStrategy(FitPar::Config().GetParI("minimizer.strategy")); fMinimizer->SetFunction(*fCallFunctor); int ipar = 0; //Add Fit Parameters for (UInt_t i = 0; i < fParams.size(); i++){ std::string syst = fParams.at(i); bool fixed = true; double vstart, vstep, vlow, vhigh; vstart = vstep = vlow = vhigh = 0.0; if (fCurVals.find(syst) != fCurVals.end() ) vstart = fCurVals.at(syst); if (fMinVals.find(syst) != fMinVals.end() ) vlow = fMinVals.at(syst); if (fMaxVals.find(syst) != fMaxVals.end() ) vhigh = fMaxVals.at(syst); if (fStepVals.find(syst) != fStepVals.end()) vstep = fStepVals.at(syst); if (fFixVals.find(syst) != fFixVals.end() ) fixed = fFixVals.at(syst); // fix for errors if (vhigh == vlow) vhigh += 1.0; fMinimizer->SetVariable(ipar, syst, vstart, vstep); fMinimizer->SetVariableLimits(ipar,vlow,vhigh); if (fixed) { fMinimizer->FixVariable(ipar); LOG(FIT) << "Fixed Param: "<<syst<<std::endl; } else { LOG(FIT) << "Free Param: "<<syst <<" Start:"<<vstart <<" Range:"<<vlow<<" to "<<vhigh <<" Step:"<<vstep<<std::endl; } ipar++; } LOG(FIT) << "Setup Minimizer: "<<fMinimizer->NDim()<<"(NDim) "<<fMinimizer->NFree()<<"(NFree)"<<std::endl; return; } //************************************* // Set fake data from user input void MinimizerRoutines::SetFakeData(){ //************************************* // If the fake data input field (-d) isn't provided, return to caller if (fFakeDataInput.empty()) return; // If user specifies -d MC we set the data to the MC // User can also specify fake data parameters to reweight by doing "fake_parameter" in input card file // "fake_parameter" gets read in ReadCard function (reads to fFakeVals) if (fFakeDataInput.compare("MC") == 0) { LOG(FIT) << "Setting fake data from MC starting prediction." << std::endl; // fFakeVals get read in in ReadCard UpdateRWEngine(fFakeVals); // Reconfigure the reweight engine FitBase::GetRW()->Reconfigure(); // Reconfigure all the samples to the new reweight fSampleFCN->ReconfigureAllEvents(); // Feed on and set the fake-data in each measurement class fSampleFCN->SetFakeData("MC"); // Changed the reweight engine values back to the current values // So we start the fit at a different value than what we set the fake-data to UpdateRWEngine(fCurVals); LOG(FIT)<<"Set all data to fake MC predictions."<<std::endl; } else { fSampleFCN->SetFakeData(fFakeDataInput); } return; } /* Fitting Functions */ //************************************* void MinimizerRoutines::UpdateRWEngine(std::map<std::string,double>& updateVals){ //************************************* for (UInt_t i = 0; i < fParams.size(); i++){ std::string name = fParams[i]; if (updateVals.find(name) == updateVals.end()) continue; FitBase::GetRW()->SetDialValue(name,updateVals.at(name)); } FitBase::GetRW()->Reconfigure(); return; } //************************************* void MinimizerRoutines::Run(){ //************************************* for (UInt_t i = 0; i < fRoutines.size(); i++){ std::string routine = fRoutines.at(i); int fitstate = kFitUnfinished; LOG(FIT)<<"Running Routine: "<<routine<<std::endl; // Try Routines if (routine.find("LowStat") != std::string::npos) LowStatRoutine(routine); else if (routine == "FixAtLim") FixAtLimit(); else if (routine == "FixAtLimBreak") fitstate = FixAtLimit(); else if (routine.find("ErrorBands") != std::string::npos) GenerateErrorBands(); else if (!routine.compare("Chi2Scan1D")) Create1DScans(); else if (!routine.compare("Chi2Scan2D")) Chi2Scan2D(); else fitstate = RunFitRoutine(routine); // If ending early break here if (fitstate == kFitFinished || fitstate == kNoChange){ LOG(FIT) << "Ending fit routines loop." << endl; break; } } return; } //************************************* int MinimizerRoutines::RunFitRoutine(std::string routine){ //************************************* int endfits = kFitUnfinished; // set fitter at the current start values fOutputRootFile->cd(); SetupFitter(routine); // choose what to do with the minimizer depending on routine. if (!routine.compare("Migrad") or !routine.compare("Simplex") or !routine.compare("Combined") or !routine.compare("Brute") or !routine.compare("Fumili") or !routine.compare("ConjugateFR") or !routine.compare("ConjugatePR") or !routine.compare("BFGS") or !routine.compare("BFGS2") or !routine.compare("SteepDesc") or // !routine.compare("GSLMulti") or !routine.compare("GSLSimAn")) { if (fMinimizer->NFree() > 0){ LOG(FIT) << StatusMessage(fMinimizer->Minimize()) << std::endl; GetMinimizerState(); } } // other otptions else if (!routine.compare("Contour")) { CreateContours(); } return endfits; } //************************************* void MinimizerRoutines::PrintState(){ //************************************* LOG(FIT)<<"------------"<<std::endl; // Count max size int maxcount = 0; for (UInt_t i = 0; i < fParams.size(); i++){ maxcount = max(int(fParams[i].size()), maxcount); } // Header LOG(FIT) << " # " << left << setw(maxcount) << "Parameter " << " = " << setw(10) << "Value" << " +- " << setw(10) << "Error" << " " << setw(8) << "(Units)" << " " << setw(10) << "Conv. Val" << " +- " << setw(10) << "Conv. Err" << " " << setw(8) << "(Units)" << std::endl; // Parameters for (UInt_t i = 0; i < fParams.size(); i++){ std::string syst = fParams.at(i); std::string typestr = FitBase::ConvDialType(fTypeVals[syst]); std::string curunits = "(sig.)"; double curval = fCurVals[syst]; double curerr = fErrorVals[syst]; if (fStateVals[syst].find("ABS") != std::string::npos){ curval = FitBase::RWSigmaToAbs(typestr, syst, curval); curerr = (FitBase::RWSigmaToAbs(typestr, syst, curerr) - FitBase::RWSigmaToAbs(typestr, syst, 0.0)); curunits = "(Abs.)"; } else if (fStateVals[syst].find("FRAC") != std::string::npos){ curval = FitBase::RWSigmaToFrac(typestr, syst, curval); curerr = (FitBase::RWSigmaToFrac(typestr, syst, curerr) - FitBase::RWSigmaToFrac(typestr, syst, 0.0)); curunits = "(Frac)"; } std::string convunits = "(" + FitBase::GetRWUnits(typestr, syst) + ")"; double convval = FitBase::RWSigmaToAbs(typestr, syst, curval); double converr = (FitBase::RWSigmaToAbs(typestr, syst, curerr) - FitBase::RWSigmaToAbs(typestr, syst, 0.0)); std::ostringstream curparstring; curparstring << " " << setw(3) << left << i << ". " << setw(maxcount) << syst << " = " << setw(10) << curval << " +- " << setw(10) << curerr << " " << setw(8) << curunits << " " << setw(10) << convval << " +- " << setw(10) << converr << " " << setw(8) << convunits; LOG(FIT) << curparstring.str() << endl; } LOG(FIT)<<"------------"<<std::endl; double like = fSampleFCN->GetLikelihood(); LOG(FIT) << std::left << std::setw(46) << "Likelihood for JointFCN: " << like << endl; LOG(FIT)<<"------------"<<std::endl; } //************************************* void MinimizerRoutines::GetMinimizerState(){ //************************************* LOG(FIT) << "Minimizer State: "<<std::endl; // Get X and Err const double *values = fMinimizer->X(); const double *errors = fMinimizer->Errors(); // int ipar = 0; for (UInt_t i = 0; i < fParams.size(); i++){ std::string syst = fParams.at(i); fCurVals[syst] = values[i]; fErrorVals[syst] = errors[i]; } PrintState(); // Covar SetupCovariance(); if (fMinimizer->CovMatrixStatus() > 0){ // Fill Full Covar for (int i = 0; i < fCovar->GetNbinsX(); i++){ for (int j = 0; j < fCovar->GetNbinsY(); j++){ fCovar->SetBinContent(i+1,j+1, fMinimizer->CovMatrix(i,j)); } } int freex = 0; int freey = 0; for (int i = 0; i < fCovar->GetNbinsX(); i++){ if (fMinimizer->IsFixedVariable(i)) continue; freey = 0; for (int j = 0; j < fCovar->GetNbinsY(); j++){ if (fMinimizer->IsFixedVariable(j)) continue; fCovFree->SetBinContent(freex+1,freey+1, fMinimizer->CovMatrix(i,j)); freey++; } freex++; } fCorrel = PlotUtils::GetCorrelationPlot(fCovar,"correlation"); fDecomp = PlotUtils::GetDecompPlot(fCovar,"decomposition"); if (fMinimizer->NFree() > 0){ fCorFree = PlotUtils::GetCorrelationPlot(fCovFree,"correlation_free"); fDecFree = PlotUtils::GetDecompPlot(fCovFree,"decomposition_free"); } } return; }; //************************************* void MinimizerRoutines::LowStatRoutine(std::string routine){ //************************************* LOG(FIT) << "Running Low Statistics Routine: "<<routine<<std::endl; int lowstatsevents = FitPar::Config().GetParI("minimizer.lowstatevents"); int maxevents = FitPar::Config().GetParI("input.maxevents"); int verbosity = FitPar::Config().GetParI("VERBOSITY"); std::string trueroutine = routine; std::string substring = "LowStat"; trueroutine.erase( trueroutine.find(substring), substring.length() ); // Set MAX EVENTS=1000 FitPar::Config().SetParI("input.maxevents",lowstatsevents); FitPar::Config().SetParI("VERBOSITY",3); SetupFCN(); RunFitRoutine(trueroutine); FitPar::Config().SetParI("input.maxevents",maxevents); SetupFCN(); FitPar::Config().SetParI("VERBOSITY",verbosity); return; } //************************************* void MinimizerRoutines::Create1DScans(){ //************************************* // 1D Scan Routine // Steps through all free parameters about nominal using the step size // Creates a graph for each free parameter // At the current point create a 1D Scan for all parametes (Uncorrelated) for (UInt_t i = 0; i < fParams.size(); i++){ if (fFixVals[fParams[i]]) continue; LOG(FIT) << "Running 1D Scan for " << fParams[i] << endl; fSampleFCN->CreateIterationTree(fParams[i] + "_scan1D_iterations", FitBase::GetRW()); double scanmiddlepoint = fCurVals[fParams[i]]; // Determine N points needed double limlow = fMinVals[fParams[i]]; double limhigh = fMaxVals[fParams[i]]; double step = fStepVals[fParams[i]]; int npoints = int( fabs(limhigh - limlow)/(step+0.) ); TH1D* contour = new TH1D(("Chi2Scan1D_" + fParams[i]).c_str(), ("Chi2Scan1D_" + fParams[i] + ";" + fParams[i]).c_str(), npoints, limlow, limhigh); // Fill bins for (int x = 0; x < contour->GetNbinsX(); x++){ // Set X Val fCurVals[fParams[i]] = contour->GetXaxis()->GetBinCenter(x+1); // Run Eval double *vals = FitUtils::GetArrayFromMap( fParams, fCurVals ); double chi2 = fSampleFCN->DoEval( vals ); delete vals; // Fill Contour contour->SetBinContent(x+1, chi2); } // Save contour contour->Write(); // Reset Parameter fCurVals[fParams[i]] = scanmiddlepoint; // Save TTree fSampleFCN->WriteIterationTree(); } return; } //************************************* void MinimizerRoutines::Chi2Scan2D(){ //************************************* // Chi2 Scan 2D // Creates a 2D chi2 scan by stepping through all free parameters // Works for all pairwise combos of free parameters // Scan I for (UInt_t i = 0; i < fParams.size(); i++){ if (fFixVals[fParams[i]]) continue; // Scan J for (UInt_t j = 0; j < i; j++){ if (fFixVals[fParams[j]]) continue; fSampleFCN->CreateIterationTree( fParams[i] + "_" + fParams[j] + "_" + "scan2D_iterations", FitBase::GetRW() ); double scanmid_i = fCurVals[fParams[i]]; double scanmid_j = fCurVals[fParams[j]]; double limlow_i = fMinVals[fParams[i]]; double limhigh_i = fMaxVals[fParams[i]]; double step_i = fStepVals[fParams[i]]; double limlow_j = fMinVals[fParams[j]]; double limhigh_j = fMaxVals[fParams[j]]; double step_j = fStepVals[fParams[j]]; int npoints_i = int( fabs(limhigh_i - limlow_i)/(step_i+0.) ) + 1; int npoints_j = int( fabs(limhigh_j - limlow_j)/(step_j+0.) ) + 1; TH2D* contour = new TH2D(("Chi2Scan2D_" + fParams[i] + "_" + fParams[j]).c_str(), ("Chi2Scan2D_" + fParams[i] + "_" + fParams[j] + ";" + fParams[i] + ";" + fParams[j]).c_str(), npoints_i, limlow_i, limhigh_i, npoints_j, limlow_j, limhigh_j ); // Begin Scan LOG(FIT)<<"Running scan for "<<fParams[i]<<" "<<fParams[j]<<endl; // Fill bins for (int x = 0; x < contour->GetNbinsX(); x++){ // Set X Val fCurVals[fParams[i]] = contour->GetXaxis()->GetBinCenter(x+1); // Loop Y for (int y = 0; y < contour->GetNbinsY(); y++){ // Set Y Val fCurVals[fParams[j]] = contour->GetYaxis()->GetBinCenter(y+1); // Run Eval double *vals = FitUtils::GetArrayFromMap( fParams, fCurVals ); double chi2 = fSampleFCN->DoEval( vals ); delete vals; // Fill Contour contour->SetBinContent(x+1,y+1, chi2); fCurVals[fParams[j]] = scanmid_j; } fCurVals[fParams[i]] = scanmid_i; fCurVals[fParams[j]] = scanmid_j; } // Save contour contour->Write(); // Save Iterations fSampleFCN->WriteIterationTree(); } } return; } //************************************* void MinimizerRoutines::CreateContours(){ //************************************* // Use MINUIT for this if possible ERR(FTL) << " Contours not yet implemented as it is really slow!" << endl; throw; return; } //************************************* int MinimizerRoutines::FixAtLimit(){ //************************************* bool fixedparam = false; for (UInt_t i = 0; i < fParams.size(); i++){ std::string syst = fParams.at(i); if (fFixVals[syst]) continue; double curVal = fCurVals.at(syst); double minVal = fMinVals.at(syst); double maxVal = fMinVals.at(syst); if (fabs(curVal - minVal) < 0.0001){ fCurVals[syst] = minVal; fFixVals[syst] = true; fixedparam = true; } if (fabs(maxVal - curVal) < 0.0001){ fCurVals[syst] = maxVal; fFixVals[syst] = true; fixedparam = true; } } if (!fixedparam){ LOG(FIT) << "No dials needed fixing!" << endl; return kNoChange; }else return kStateChange; } /* Write Functions */ //************************************* void MinimizerRoutines::SaveResults(){ //************************************* fOutputRootFile->cd(); if (fMinimizer){ SetupCovariance(); SaveMinimizerState(); } SaveCurrentState(); } //************************************* void MinimizerRoutines::SaveMinimizerState(){ //************************************* if (!fMinimizer){ ERR(FTL) << "Can't save minimizer state without min object" << endl; throw; } // Save main fit tree fSampleFCN->WriteIterationTree(); // Get Vals and Errors GetMinimizerState(); // Save tree with fit status std::vector<std::string> nameVect; std::vector<double> valVect; std::vector<double> errVect; std::vector<double> minVect; std::vector<double> maxVect; std::vector<double> startVect; std::vector<int> endfixVect; std::vector<int> startfixVect; // int NFREEPARS = fMinimizer->NFree(); int NPARS = fMinimizer->NDim(); int ipar = 0; // Dial Vals for (UInt_t i = 0; i < fParams.size(); i++){ std::string name = fParams.at(i); nameVect .push_back( name ); valVect .push_back( fCurVals.at(name) ); errVect .push_back( fErrorVals.at(name) ); minVect .push_back( fMinVals.at(name) ); maxVect .push_back( fMaxVals.at(name) ); startVect .push_back( fStartVals.at(name) ); endfixVect .push_back( fFixVals.at(name) ); startfixVect.push_back( fStartFixVals.at(name) ); ipar++; } int NFREE = fMinimizer->NFree(); int NDIM = fMinimizer->NDim(); double CHI2 = fSampleFCN->GetLikelihood(); int NBINS = fSampleFCN->GetNDOF(); int NDOF = NBINS - NFREE; // Write fit results TTree* fit_tree = new TTree("fit_result","fit_result"); fit_tree->Branch("parameter_names",&nameVect); fit_tree->Branch("parameter_values",&valVect); fit_tree->Branch("parameter_errors",&errVect); fit_tree->Branch("parameter_min",&minVect); fit_tree->Branch("parameter_max",&maxVect); fit_tree->Branch("parameter_start",&startVect); fit_tree->Branch("parameter_fix",&endfixVect); fit_tree->Branch("parameter_startfix",&startfixVect); fit_tree->Branch("CHI2",&CHI2,"CHI2/D"); fit_tree->Branch("NDOF",&NDOF,"NDOF/I"); fit_tree->Branch("NBINS",&NBINS,"NBINS/I"); fit_tree->Branch("NDIM",&NDIM,"NDIM/I"); fit_tree->Branch("NFREE",&NFREE,"NFREE/I"); fit_tree->Fill(); fit_tree->Write(); // Make dial variables TH1D dialvar = TH1D("fit_dials","fit_dials",NPARS,0,NPARS); TH1D startvar = TH1D("start_dials","start_dials",NPARS,0,NPARS); TH1D minvar = TH1D("min_dials","min_dials",NPARS,0,NPARS); TH1D maxvar = TH1D("max_dials","max_dials",NPARS,0,NPARS); TH1D dialvarfree = TH1D("fit_dials_free","fit_dials_free",NFREE,0,NFREE); TH1D startvarfree = TH1D("start_dials_free","start_dials_free",NFREE,0,NFREE); TH1D minvarfree = TH1D("min_dials_free","min_dials_free",NFREE,0,NFREE); TH1D maxvarfree = TH1D("max_dials_free","max_dials_free",NFREE,0,NFREE); int freecount = 0; for (UInt_t i = 0; i < nameVect.size(); i++){ std::string name = nameVect.at(i); dialvar.SetBinContent(i+1, valVect.at(i)); dialvar.SetBinError(i+1, errVect.at(i)); dialvar.GetXaxis()->SetBinLabel(i+1, name.c_str()); startvar.SetBinContent(i+1, startVect.at(i)); startvar.GetXaxis()->SetBinLabel(i+1, name.c_str()); minvar.SetBinContent(i+1, minVect.at(i)); minvar.GetXaxis()->SetBinLabel(i+1, name.c_str()); maxvar.SetBinContent(i+1, maxVect.at(i)); maxvar.GetXaxis()->SetBinLabel(i+1, name.c_str()); if (NFREE > 0){ if (!startfixVect.at(i)){ freecount++; dialvarfree.SetBinContent(freecount, valVect.at(i)); dialvarfree.SetBinError(freecount, errVect.at(i)); dialvarfree.GetXaxis()->SetBinLabel(freecount, name.c_str()); startvarfree.SetBinContent(freecount, startVect.at(i)); startvarfree.GetXaxis()->SetBinLabel(freecount, name.c_str()); minvarfree.SetBinContent(freecount, minVect.at(i)); minvarfree.GetXaxis()->SetBinLabel(freecount, name.c_str()); maxvarfree.SetBinContent(freecount, maxVect.at(i)); maxvarfree.GetXaxis()->SetBinLabel(freecount, name.c_str()); } } } // Save Dial Plots dialvar.Write(); startvar.Write(); minvar.Write(); maxvar.Write(); if (NFREE > 0){ dialvarfree.Write(); startvarfree.Write(); minvarfree.Write(); maxvarfree.Write(); } // Save fit_status plot TH1D statusplot = TH1D("fit_status","fit_status",8,0,8); std::string fit_labels[8] = {"status", "cov_status", \ "maxiter", "maxfunc", \ "iter", "func", \ "precision", "tolerance"}; double fit_vals[8]; fit_vals[0] = fMinimizer->Status() + 0.; fit_vals[1] = fMinimizer->CovMatrixStatus() + 0.; fit_vals[2] = fMinimizer->MaxIterations() + 0.; fit_vals[3] = fMinimizer->MaxFunctionCalls()+ 0.; fit_vals[4] = fMinimizer->NIterations() + 0.; fit_vals[5] = fMinimizer->NCalls() + 0.; fit_vals[6] = fMinimizer->Precision() + 0.; fit_vals[7] = fMinimizer->Tolerance() + 0.; for (int i = 0; i < 8; i++){ statusplot.SetBinContent(i+1, fit_vals[i]); statusplot.GetXaxis()->SetBinLabel(i+1, fit_labels[i].c_str()); } statusplot.Write(); // Save Covars if (fCovar) fCovar->Write(); if (fCovFree) fCovFree->Write(); if (fCorrel) fCorrel->Write(); if (fCorFree) fCorFree->Write(); if (fDecomp) fDecomp->Write(); if (fDecFree) fDecFree->Write(); return; } //************************************* void MinimizerRoutines::SaveCurrentState(std::string subdir){ //************************************* LOG(FIT)<<"Saving current full FCN predictions" <<std::endl; // Setup DIRS TDirectory* curdir = gDirectory; if (!subdir.empty()){ TDirectory* newdir =(TDirectory*) gDirectory->mkdir(subdir.c_str()); newdir->cd(); } FitBase::GetRW()->Reconfigure(); fSampleFCN->ReconfigureAllEvents(); fSampleFCN->Write(); // Change back to current DIR curdir->cd(); return; } //************************************* void MinimizerRoutines::SaveNominal(){ //************************************* fOutputRootFile->cd(); LOG(FIT)<<"Saving Nominal Predictions (be cautious with this)" <<std::endl; FitBase::GetRW()->Reconfigure(); SaveCurrentState("nominal"); }; //************************************* void MinimizerRoutines::SavePrefit(){ //************************************* fOutputRootFile->cd(); LOG(FIT)<<"Saving Prefit Predictions"<<std::endl; UpdateRWEngine(fStartVals); SaveCurrentState("prefit"); UpdateRWEngine(fCurVals); }; /* MISC Functions */ //************************************* int MinimizerRoutines::GetStatus(){ //************************************* return 0; } //************************************* void MinimizerRoutines::SetupCovariance(){ //************************************* // Remove covares if they exist if (fCovar) delete fCovar; if (fCovFree) delete fCovFree; if (fCorrel) delete fCorrel; if (fCorFree) delete fCorFree; if (fDecomp) delete fDecomp; if (fDecFree) delete fDecFree; LOG(FIT) << "Building covariance matrix.." << endl; int NFREE = 0; int NDIM = 0; // Get NFREE from min or from vals (for cases when doing throws) if (fMinimizer){ NFREE = fMinimizer->NFree(); NDIM = fMinimizer->NDim(); } else { NDIM = fParams.size(); for (UInt_t i = 0; i < fParams.size(); i++){ if (!fFixVals[fParams[i]]) NFREE++; } } if (NDIM == 0) return; LOG(FIT) << "NFREE == " << NFREE << endl; fCovar = new TH2D("covariance","covariance",NDIM,0,NDIM,NDIM,0,NDIM); if (NFREE > 0){ fCovFree = new TH2D("covariance_free", "covariance_free", NFREE,0,NFREE, NFREE,0,NFREE); } else { fCovFree = NULL; } // Set Bin Labels int countall = 0; int countfree = 0; for (UInt_t i = 0; i < fParams.size(); i++){ fCovar->GetXaxis()->SetBinLabel(countall+1,fParams[i].c_str()); fCovar->GetYaxis()->SetBinLabel(countall+1,fParams[i].c_str()); countall++; if (!fFixVals[fParams[i]] and NFREE > 0){ fCovFree->GetXaxis()->SetBinLabel(countfree+1,fParams[i].c_str()); fCovFree->GetYaxis()->SetBinLabel(countfree+1,fParams[i].c_str()); countfree++; } } fCorrel = PlotUtils::GetCorrelationPlot(fCovar,"correlation"); fDecomp = PlotUtils::GetDecompPlot(fCovar,"decomposition"); if (NFREE > 0) { fCorFree = PlotUtils::GetCorrelationPlot(fCovFree, "correlation_free"); fDecFree = PlotUtils::GetDecompPlot(fCovFree,"decomposition_free"); } else { fCorFree = NULL; fDecFree = NULL; } return; }; //************************************* void MinimizerRoutines::ThrowCovariance(bool uniformly){ //************************************* std::vector<double> rands; if (!fDecFree) { ERR(WRN) << "Trying to throw 0 free parameters"<<std::endl; return; } // Generate Random Gaussians for (Int_t i = 0; i < fDecFree->GetNbinsX(); i++){ rands.push_back(gRandom->Gaus(0.0,1.0)); } // Reset Thrown Values for (UInt_t i = 0; i < fParams.size(); i++){ fThrownVals[fParams[i]] = fCurVals[fParams[i]]; } // Loop and get decomp for (Int_t i = 0; i < fDecFree->GetNbinsX(); i++){ std::string parname = std::string(fDecFree->GetXaxis()->GetBinLabel(i+1)); double mod = 0.0; if (!uniformly){ for (Int_t j = 0; j < fDecFree->GetNbinsY(); j++){ mod += rands[j] * fDecFree->GetBinContent(j+1,i+1); } } if (fCurVals.find(parname) != fCurVals.end()) { if (uniformly) fThrownVals[parname] = gRandom->Uniform(fMinVals[parname],fMaxVals[parname]); else { fThrownVals[parname] = fCurVals[parname] + mod; } } } // Check Limits for (UInt_t i = 0; i < fParams.size(); i++){ std::string syst = fParams[i]; if (fFixVals[syst]) continue; if (fThrownVals[syst] < fMinVals[syst]) fThrownVals[syst] = fMinVals[syst]; if (fThrownVals[syst] > fMaxVals[syst]) fThrownVals[syst] = fMaxVals[syst]; } return; }; //************************************* void MinimizerRoutines::GenerateErrorBands(){ //************************************* TDirectory* errorDIR = (TDirectory*) fOutputRootFile->mkdir("error_bands"); errorDIR->cd(); - TFile* tempfile = new TFile((fOutputFile + ".throws.root").c_str(),"RECREATE"); + // Make a second file to store throws + std::string tempFileName = fOutputFile; + if (tempFileName.find(".root") != std::string::npos) tempFileName.erase(tempFileName.find(".root"), 5); + tempFileName += ".throws.root"; + TFile* tempfile = new TFile(tempFileName.c_str(),"RECREATE"); + tempfile->cd(); int nthrows = FitPar::Config().GetParI("error_throws"); UpdateRWEngine(fCurVals); fSampleFCN->ReconfigureAllEvents(); TDirectory* nominal = (TDirectory*) tempfile->mkdir("nominal"); nominal->cd(); fSampleFCN->Write(); TDirectory* outnominal = (TDirectory*) fOutputRootFile->mkdir("nominal_throw"); outnominal->cd(); fSampleFCN->Write(); errorDIR->cd(); TTree* parameterTree = new TTree("throws","throws"); double chi2; for (UInt_t i = 0; i < fParams.size(); i++) parameterTree->Branch(fParams[i].c_str(), &fThrownVals[fParams[i]], (fParams[i] + "/D").c_str()); parameterTree->Branch("chi2",&chi2,"chi2/D"); bool uniformly = FitPar::Config().GetParB("error_uniform"); // Run Throws and save for (Int_t i = 0; i < nthrows; i++){ TDirectory* throwfolder = (TDirectory*)tempfile->mkdir(Form("throw_%i",i)); throwfolder->cd(); // Generate Random Parameter Throw ThrowCovariance(uniformly); // Run Eval double *vals = FitUtils::GetArrayFromMap( fParams, fThrownVals ); chi2 = fSampleFCN->DoEval( vals ); delete vals; // Save the FCN fSampleFCN->Write(); parameterTree->Fill(); } errorDIR->cd(); fDecFree->Write(); fCovFree->Write(); parameterTree->Write(); delete parameterTree; // Now go through the keys in the temporary file and look for TH1D, and TH2D plots TIter next(nominal->GetListOfKeys()); TKey *key; while ((key = (TKey*)next())) { TClass *cl = gROOT->GetClass(key->GetClassName()); if (!cl->InheritsFrom("TH1D") and !cl->InheritsFrom("TH2D")) continue; TH1D *baseplot = (TH1D*)key->ReadObj(); std::string plotname = std::string(baseplot->GetName()); int nbins = baseplot->GetNbinsX()*baseplot->GetNbinsY(); // Setup TProfile with RMS option TProfile* tprof = new TProfile((plotname + "_prof").c_str(),(plotname + "_prof").c_str(),nbins, 0, nbins, "S"); // Setup The TTREE double* bincontents; bincontents = new double[nbins]; double* binlowest; binlowest = new double[nbins]; double* binhighest; binhighest = new double[nbins]; errorDIR->cd(); TTree* bintree = new TTree((plotname + "_tree").c_str(), (plotname + "_tree").c_str()); for (Int_t i = 0; i < nbins; i++){ bincontents[i] = 0.0; binhighest[i] = 0.0; binlowest[i] = 0.0; bintree->Branch(Form("content_%i",i),&bincontents[i],Form("content_%i/D",i)); } for (Int_t i = 0; i < nthrows; i++){ TH1* newplot = (TH1*)tempfile->Get(Form(("throw_%i/" + plotname).c_str(),i)); for (Int_t j = 0; j < nbins; j++){ tprof->Fill(j+0.5, newplot->GetBinContent(j+1)); bincontents[j] = newplot->GetBinContent(j+1); if (bincontents[j] < binlowest[j] or i == 0) binlowest[j] = bincontents[j]; if (bincontents[j] > binhighest[j] or i == 0) binhighest[j] = bincontents[j]; } errorDIR->cd(); bintree->Fill(); delete newplot; } errorDIR->cd(); for (Int_t j = 0; j < nbins; j++){ if (!uniformly){ baseplot->SetBinError(j+1,tprof->GetBinError(j+1)); } else { baseplot->SetBinContent(j+1, (binlowest[j] + binhighest[j]) / 2.0); baseplot->SetBinError(j+1, (binhighest[j] - binlowest[j])/2.0); } } errorDIR->cd(); baseplot->Write(); tprof->Write(); bintree->Write(); delete baseplot; delete tprof; delete bintree; delete [] bincontents; } return; }; diff --git a/src/Routines/SystematicRoutines.cxx b/src/Routines/SystematicRoutines.cxx index 3114fcc..fb19410 100755 --- a/src/Routines/SystematicRoutines.cxx +++ b/src/Routines/SystematicRoutines.cxx @@ -1,1182 +1,1187 @@ // Copyright 2016 L. Pickering, P Stowell, R. Terri, C. Wilkinson, C. Wret /******************************************************************************* * This file is part of NUISANCE. * * NUISANCE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * NUISANCE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NUISANCE. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ #include "StatusMessage.h" #include "SystematicRoutines.h" /* Constructor/Destructor */ //************************ void SystematicRoutines::Init(){ //************************ fInputFile = ""; fInputRootFile = NULL; fOutputFile = ""; fOutputRootFile = NULL; fCovar = fCovarFree = NULL; fCorrel = fCorrelFree = NULL; fDecomp = fDecompFree = NULL; fStrategy = "ErrorBands"; fRoutines.clear(); fCardFile = ""; fFakeDataInput = ""; fSampleFCN = NULL; fAllowedRoutines = ("ErrorBands,PlotLimits"); }; //************************************* SystematicRoutines::~SystematicRoutines(){ //************************************* }; /* Input Functions */ //************************************* SystematicRoutines::SystematicRoutines(int argc, char* argv[]){ //************************************* // Set everything to defaults Init(); std::vector<std::string> configs_cmd; std::string maxevents_flag = ""; int verbosity_flag = 0; int error_flag = 0; // If No Arguments print commands for (int i = 1; i< argc; ++i){ if (i+1 != argc){ // Cardfile if (!std::strcmp(argv[i], "-c")) { fCardFile=argv[i+1]; ++i;} else if (!std::strcmp(argv[i], "-o")) { fOutputFile=argv[i+1]; ++i;} else if (!std::strcmp(argv[i], "-f")) { fStrategy=argv[i+1]; ++i;} else if (!std::strcmp(argv[i], "-q")) { configs_cmd.push_back(argv[i+1]); ++i;} else if (!std::strcmp(argv[i], "-n")) { maxevents_flag=argv[i+1]; ++i;} else if (!std::strcmp(argv[i], "-v")) { verbosity_flag -= 1; } else if (!std::strcmp(argv[i], "+v")) { verbosity_flag += 1; } else if (!std::strcmp(argv[i], "-e")) { error_flag -= 1; } else if (!std::strcmp(argv[i], "+e")) { error_flag += 1; } else { ERR(FTL) << "ERROR: unknown command line option given! - '" <<argv[i]<<" "<<argv[i+1]<<"'"<< std::endl; throw; } } } if (fCardFile.empty()){ ERR(FTL) << "ERROR: card file not specified." << std::endl; ERR(FTL) << "Run with '-h' to see options." << std::endl; throw; } if (fCardFile == fOutputFile) { ERR(WRN) << "WARNING: output file and card file are the same file, " "writing: " << fCardFile << ".root" << std::endl; fOutputFile = fCardFile + ".root"; } if(fCardFile == fOutputFile){ std::cerr << "WARNING: output file and card file are the same file, " "writing: " << fCardFile << ".root" << std::endl; fOutputFile = fCardFile + ".root"; } // Fill fit routines and check they are good fRoutines = GeneralUtils::ParseToStr(fStrategy,","); for (UInt_t i = 0; i < fRoutines.size(); i++){ if (fAllowedRoutines.find(fRoutines[i]) == std::string::npos){ ERR(FTL) << "Unknown fit routine given! " << "Must be provided as a comma seperated list." << std::endl; ERR(FTL) << "Allowed Routines: " << fAllowedRoutines << std::endl; throw; } } // CONFIG // --------------------------- std::string par_dir = GeneralUtils::GetTopLevelDir()+"/parameters/"; FitPar::Config().ReadParamFile( par_dir + "config.list.dat" ); FitPar::Config().ReadParamFile( fCardFile ); for (UInt_t iter = 0; iter < configs_cmd.size(); iter++){ FitPar::Config().ForceParam(configs_cmd[iter]); } if (!maxevents_flag.empty()){ FitPar::Config().SetParI("input.maxevents", atoi(maxevents_flag.c_str())); } if (verbosity_flag != 0){ int curverb = FitPar::Config().GetParI("VERBOSITY"); FitPar::Config().SetParI("VERBOSITY", curverb + verbosity_flag); } if (error_flag != 0){ int curwarn = FitPar::Config().GetParI("ERROR"); FitPar::Config().SetParI("ERROR", curwarn + error_flag); } LOG_VERB(FitPar::Config().GetParI("VERBOSITY")); ERR_VERB(FitPar::Config().GetParI("ERROR")); // CARD // --------------------------- // Parse Card Options ReadCard(fCardFile); // Outputs // --------------------------- // Save Configs to output file fOutputRootFile = new TFile(fOutputFile.c_str(),"RECREATE"); FitPar::Config().Write(); // Starting Setup // --------------------------- SetupCovariance(); SetupFCN(); GetCovarFromFCN(); SetupRWEngine(); return; }; //************************************* void SystematicRoutines::ReadCard(std::string cardfile){ //************************************* // Read cardlines into vector std::vector<std::string> cardlines = GeneralUtils::ParseFileToStr(cardfile,"\n"); FitPar::Config().cardLines = cardlines; // Read Samples first (norm params can be overridden) int linecount = 0; for (std::vector<std::string>::iterator iter = cardlines.begin(); iter != cardlines.end(); iter++){ std::string line = (*iter); linecount++; // Skip Empties if (line.empty()) continue; if (line.c_str()[0] == '#') continue; // Read Valid Samples int samstatus = ReadSamples(line); // Show line if bad to help user if (samstatus == kErrorStatus) { ERR(FTL) << "Bad Input in cardfile " << fCardFile << " at line " << linecount << "!" << std::endl; LOG(FIT) << line << std::endl; throw; } } // Read Parameters second linecount = 0; for (std::vector<std::string>::iterator iter = cardlines.begin(); iter != cardlines.end(); iter++){ std::string line = (*iter); linecount++; // Skip Empties if (line.empty()) continue; if (line.c_str()[0] == '#') continue; // Try Parameter Reads int parstatus = ReadParameters(line); int fakstatus = ReadFakeDataPars(line); // Show line if bad to help user if (parstatus == kErrorStatus || fakstatus == kErrorStatus ){ ERR(FTL) << "Bad Parameter Input in cardfile " << fCardFile << " at line " << linecount << "!" << std::endl; LOG(FIT) << line << std::endl; throw; } } return; }; //***************************************** int SystematicRoutines::ReadParameters(std::string parstring){ //****************************************** std::string inputspec = "RW Dial Inputs Syntax \n" "free input w/ limits: TYPE NAME START MIN MAX STEP [STATE] \n" "fix input: TYPE NAME VALUE [STATE] \n" "free input w/o limits: TYPE NAME START FREE,[STATE] \n" "Allowed Types: \n" "neut_parameter,niwg_parameter,t2k_parameter," "nuwro_parameter,gibuu_parameter"; // Check sample input if (parstring.find("parameter") == std::string::npos) return kGoodStatus; // Parse inputs std::vector<std::string> strvct = GeneralUtils::ParseToStr(parstring, " "); // Skip if comment or parameter somewhere later in line if (strvct[0].c_str()[0] == '#' || strvct[0].find("parameter") == std::string::npos){ return kGoodStatus; } // Check length if (strvct.size() < 3){ ERR(FTL) << "Input rw dials need to provide at least 3 inputs." << std::endl; std::cout << inputspec << std::endl; return kErrorStatus; } // Setup default inputs std::string partype = strvct[0]; std::string parname = strvct[1]; double parval = GeneralUtils::StrToDbl(strvct[2]); double minval = parval - 1.0; double maxval = parval + 1.0; double stepval = 1.0; std::string state = "FIX"; //[DEFAULT] // Check Type if (FitBase::ConvDialType(partype) == kUNKNOWN){ ERR(FTL) << "Unknown parameter type! " << partype << std::endl; std::cout << inputspec << std::endl; return kErrorStatus; } // Check Parameter Name if (FitBase::GetDialEnum(partype, parname) == -1){ ERR(FTL) << "Bad RW parameter name! " << partype << " " << parname << std::endl; std::cout << inputspec << std::endl; return kErrorStatus; } // Option Extra (No Limits) if (strvct.size() == 4){ state = strvct[3]; } // Check for weirder inputs if (strvct.size() > 4 && strvct.size() < 6){ ERR(FTL) << "Provided incomplete limits for " << parname << std::endl; std::cout << inputspec << std::endl; return kErrorStatus; } // Option Extra (With limits and steps) if (strvct.size() >= 6){ minval = GeneralUtils::StrToDbl(strvct[3]); maxval = GeneralUtils::StrToDbl(strvct[4]); stepval = GeneralUtils::StrToDbl(strvct[5]); } // Option Extra (dial state after limits) if (strvct.size() == 7){ state = strvct[6]; } // Run Parameter Conversion if needed if (state.find("ABS") != std::string::npos){ parval = FitBase::RWAbsToSigma( partype, parname, parval ); minval = FitBase::RWAbsToSigma( partype, parname, minval ); maxval = FitBase::RWAbsToSigma( partype, parname, maxval ); stepval = FitBase::RWAbsToSigma( partype, parname, stepval ); } else if (state.find("FRAC") != std::string::npos){ parval = FitBase::RWFracToSigma( partype, parname, parval ); minval = FitBase::RWFracToSigma( partype, parname, minval ); maxval = FitBase::RWFracToSigma( partype, parname, maxval ); stepval = FitBase::RWFracToSigma( partype, parname, stepval ); } // Check no repeat params if (std::find(fParams.begin(), fParams.end(), parname) != fParams.end()){ ERR(FTL) << "Duplicate parameter names given for " << parname << std::endl; throw; } // Setup Containers fParams.push_back(parname); fTypeVals[parname] = FitBase::ConvDialType(partype); fStartVals[parname] = parval; fCurVals[parname] = fStartVals[parname]; fErrorVals[parname] = 0.0; fStateVals[parname] = state; bool fixstate = state.find("FIX") != std::string::npos; fFixVals[parname] = fixstate; fStartFixVals[parname] = fFixVals[parname]; fMinVals[parname] = minval; fMaxVals[parname] = maxval; fStepVals[parname] = stepval; // Print the parameter LOG(MIN) << "Read Parameter " << parname << " " << parval << " " << minval << " " << maxval << " " << stepval << " " << state << std::endl; // Tell reader its all good return kGoodStatus; } //******************************************* int SystematicRoutines::ReadFakeDataPars(std::string parstring){ //****************************************** std::string inputspec = "Fake Data Dial Inputs Syntax \n" "fake value: fake_parameter NAME VALUE \n" "Name should match dialnames given in actual dial specification."; // Check sample input if (parstring.find("fake_parameter") == std::string::npos) return kGoodStatus; // Parse inputs std::vector<std::string> strvct = GeneralUtils::ParseToStr(parstring, " "); // Skip if comment or parameter somewhere later in line if (strvct[0].c_str()[0] == '#' || strvct[0] == "fake_parameter"){ return kGoodStatus; } // Check length if (strvct.size() < 3){ ERR(FTL) << "Fake dials need to provide at least 3 inputs." << std::endl; std::cout << inputspec << std::endl; return kErrorStatus; } // Read Inputs std::string parname = strvct[1]; double parval = GeneralUtils::StrToDbl(strvct[2]); // Setup Container fFakeVals[parname] = parval; // Print the fake parameter LOG(MIN) << "Read Fake Parameter " << parname << " " << parval << std::endl; // Tell reader its all good return kGoodStatus; } //****************************************** int SystematicRoutines::ReadSamples(std::string samstring){ //****************************************** const static std::string inputspec = "\tsample <sample_name> <input_type>:inputfile.root [OPTS] " "[norm]\nsample_name: Name " "of sample to include. e.g. MiniBooNE_CCQE_XSec_1DQ2_nu\ninput_type: The " "input event format. e.g. NEUT, GENIE, EVSPLN, ...\nOPTS: Additional, " "optional sample options.\nnorm: Additional, optional sample " "normalisation factor."; // Check sample input if (samstring.find("sample") == std::string::npos) return kGoodStatus; // Parse inputs std::vector<std::string> strvct = GeneralUtils::ParseToStr(samstring, " "); // Skip if comment or parameter somewhere later in line if (strvct[0].c_str()[0] == '#' || strvct[0] != "sample"){ return kGoodStatus; } // Check length if (strvct.size() < 3){ ERR(FTL) << "Sample need to provide at least 3 inputs." << std::endl; return kErrorStatus; } // Setup default inputs std::string samname = strvct[1]; std::string samfile = strvct[2]; if (samfile == "FIX") { ERR(FTL) << "Input filename was \"FIX\", this line is probably malformed " "in the input card file. Line:\'" << samstring << "\'" << std::endl; ERR(FTL) << "Expect sample lines to look like:\n\t" << inputspec << std::endl; throw; } std::string samtype = "DEFAULT"; double samnorm = 1.0; // Optional Type if (strvct.size() > 3) { samtype = strvct[3]; samname += "_"+samtype; // Also get rid of the / and replace it with underscore because it might not be supported character while (samname.find("/") != std::string::npos) { samname.replace(samname.find("/"), 1, std::string("_")); } } // Optional Norm if (strvct.size() > 4) samnorm = GeneralUtils::StrToDbl(strvct[4]); // Add Sample Names as Norm Dials std::string normname = samname + "_norm"; // Check no repeat params if (std::find(fParams.begin(), fParams.end(), normname) != fParams.end()){ ERR(FTL) << "Duplicate samples given for " << samname << std::endl; throw; } fParams.push_back(normname); fTypeVals[normname] = kNORM; fStartVals[normname] = samnorm; fCurVals[normname] = fStartVals[normname]; fErrorVals[normname] = 0.0; fMinVals[normname] = 0.1; fMaxVals[normname] = 10.0; fStepVals[normname] = 0.5; bool state = samtype.find("FREE") == std::string::npos; fFixVals[normname] = state; fStartFixVals[normname] = state; // Print read in LOG(MIN) << "Read sample " << samname << " " << samfile << " " << samtype << " " << samnorm << std::endl; // Tell reader its all good return kGoodStatus; } /* Setup Functions */ //************************************* void SystematicRoutines::SetupRWEngine(){ //************************************* for (UInt_t i = 0; i < fParams.size(); i++){ std::string name = fParams[i]; FitBase::GetRW() -> IncludeDial(name, fTypeVals.at(name) ); } UpdateRWEngine(fStartVals); return; } //************************************* void SystematicRoutines::SetupFCN(){ //************************************* LOG(FIT)<<"Making the jointFCN"<<std::endl; if (fSampleFCN) delete fSampleFCN; fSampleFCN = new JointFCN(fCardFile, fOutputRootFile); SetFakeData(); return; } //************************************* void SystematicRoutines::SetFakeData(){ //************************************* if (fFakeDataInput.empty()) return; if (fFakeDataInput.compare("MC") == 0){ LOG(FIT)<<"Setting fake data from MC starting prediction." <<std::endl; UpdateRWEngine(fFakeVals); FitBase::GetRW()->Reconfigure(); fSampleFCN->ReconfigureAllEvents(); fSampleFCN->SetFakeData("MC"); UpdateRWEngine(fCurVals); LOG(FIT)<<"Set all data to fake MC predictions."<<std::endl; } else { fSampleFCN->SetFakeData(fFakeDataInput); } return; } //***************************************** void SystematicRoutines::GetCovarFromFCN(){ //***************************************** LOG(FIT) << "Loading ParamPull objects from FCN to build covar" << std::endl; // Make helperstring std::ostringstream helperstr; // Keep track of what is being thrown std::map<std::string, std::string> dialthrowhandle; // Get Covariance Objects from FCN std::list<ParamPull*> inputpulls = fSampleFCN->GetPullList(); for (PullListConstIter iter = inputpulls.begin(); iter != inputpulls.end(); iter++){ ParamPull* pull = (*iter); if (pull->GetType().find("THROW")){ fInputThrows.push_back(pull); fInputCovar.push_back(pull->GetFullCovarMatrix()); fInputDials.push_back(pull->GetDataHist()); LOG(FIT) << "Read ParamPull: " << pull->GetName() << " " << pull->GetType() << std::endl; } TH1D dialhist = pull->GetDataHist(); TH1D minhist = pull->GetMinHist(); TH1D maxhist = pull->GetMaxHist(); TH1I typehist = pull->GetDialTypes(); for (int i = 0; i < dialhist.GetNbinsX(); i++){ std::string name = std::string(dialhist.GetXaxis()->GetBinLabel(i+1)); dialthrowhandle[name] = pull->GetName(); if (fCurVals.find(name) == fCurVals.end()){ // Add to Containers fParams.push_back(name); fCurVals[name] = dialhist.GetBinContent(i+1); fStartVals[name] = dialhist.GetBinContent(i+1); fMinVals[name] = minhist.GetBinContent(i+1); fMaxVals[name] = maxhist.GetBinContent(i+1); fStepVals[name] = 1.0; fFixVals[name] = false; fStartFixVals[name] = false; fTypeVals[name] = typehist.GetBinContent(i+1); fStateVals[name] = "FREE" + pull->GetType(); // Maker Helper helperstr << std::string(16, ' ' ) << FitBase::ConvDialType(fTypeVals[name]) << " " << name << " " << fMinVals[name] << " " << fMaxVals[name] << " " << fStepVals[name] << " " << fStateVals[name] << std::endl; } } } // Check if no throws given if (fInputThrows.empty()){ ERR(WRN) << "No covariances given to nuissyst" << std::endl; ERR(WRN) << "Pushing back an uncorrelated gaussian throw error for each free parameter using step size" << std::endl; for (UInt_t i = 0; i < fParams.size(); i++){ std::string syst = fParams[i]; if (fFixVals[syst]) continue; // Make Terms std::string name = syst + "_pull"; std::ostringstream pullterm; pullterm << "DIAL:" << syst << ";" << fStartVals[syst] << ";" << fStepVals[syst]; std::string type = fTypeVals[syst] + "/GAUSTHROW"; // Push Back Pulls ParamPull* pull = new ParamPull( name, pullterm.str(), type ); fInputThrows.push_back(pull); fInputCovar.push_back(pull->GetFullCovarMatrix()); fInputDials.push_back(pull->GetDataHist()); // Print Whats added ERR(WRN) << "Added ParamPull : " << name << " " << pullterm.str() << " " << type << std::endl; // Add helper string for future fits helperstr << std::string(16, ' ' ) << "covar " << name << " " << pullterm.str() << " " << type << std::endl; // Keep Track of Throws dialthrowhandle[syst] = pull->GetName(); } } // Print Helper String if (!helperstr.str().empty()){ LOG(FIT) << "To remove these statements in future studies, add the lines below to your card:" << std::endl; // Can't use the logger properly because this can be multi-line. Use cout and added spaces to look better! std::cout << helperstr.str(); sleep(2); } // Print Throw State for (UInt_t i = 0; i < fParams.size(); i++){ std::string syst = fParams[i]; if (dialthrowhandle.find(syst) != dialthrowhandle.end()){ LOG(FIT) << "Dial " << i << ". " << setw(40) << syst << " = THROWING with " << dialthrowhandle[syst] << std::endl; } else { LOG(FIT) << "Dial " << i << ". " << setw(40) << syst << " = FIXED" << std::endl; } } // Pause anyway sleep(1); return; } /* Fitting Functions */ //************************************* void SystematicRoutines::UpdateRWEngine(std::map<std::string,double>& updateVals){ //************************************* for (UInt_t i = 0; i < fParams.size(); i++){ std::string name = fParams[i]; if (updateVals.find(name) == updateVals.end()) continue; FitBase::GetRW()->SetDialValue(name,updateVals.at(name)); } FitBase::GetRW()->Reconfigure(); return; } //************************************* void SystematicRoutines::Run(){ //************************************* for (UInt_t i = 0; i < fRoutines.size(); i++){ std::string routine = fRoutines.at(i); int fitstate = kFitUnfinished; LOG(FIT)<<"Running Routine: "<<routine<<std::endl; if (routine.find("PlotLimits") != std::string::npos) PlotLimits(); else if (routine.find("ErrorBands") != std::string::npos) GenerateErrorBands(); // If ending early break here if (fitstate == kFitFinished || fitstate == kNoChange){ LOG(FIT) << "Ending fit routines loop." << std::endl; break; } } return; } //************************************* void SystematicRoutines::PrintState(){ //************************************* LOG(FIT)<<"------------"<<std::endl; // Count max size int maxcount = 0; for (UInt_t i = 0; i < fParams.size(); i++){ maxcount = max(int(fParams[i].size()), maxcount); } // Header LOG(FIT) << " # " << left << setw(maxcount) << "Parameter " << " = " << setw(10) << "Value" << " +- " << setw(10) << "Error" << " " << setw(8) << "(Units)" << " " << setw(10) << "Conv. Val" << " +- " << setw(10) << "Conv. Err" << " " << setw(8) << "(Units)" << std::endl; // Parameters for (UInt_t i = 0; i < fParams.size(); i++){ std::string syst = fParams.at(i); std::string typestr = FitBase::ConvDialType(fTypeVals[syst]); std::string curunits = "(sig.)"; double curval = fCurVals[syst]; double curerr = fErrorVals[syst]; if (fStateVals[syst].find("ABS") != std::string::npos){ curval = FitBase::RWSigmaToAbs(typestr, syst, curval); curerr = (FitBase::RWSigmaToAbs(typestr, syst, curerr) - FitBase::RWSigmaToAbs(typestr, syst, 0.0)); curunits = "(Abs.)"; } else if (fStateVals[syst].find("FRAC") != std::string::npos){ curval = FitBase::RWSigmaToFrac(typestr, syst, curval); curerr = (FitBase::RWSigmaToFrac(typestr, syst, curerr) - FitBase::RWSigmaToFrac(typestr, syst, 0.0)); curunits = "(Frac)"; } std::string convunits = "(" + FitBase::GetRWUnits(typestr, syst) + ")"; double convval = FitBase::RWSigmaToAbs(typestr, syst, curval); double converr = (FitBase::RWSigmaToAbs(typestr, syst, curerr) - FitBase::RWSigmaToAbs(typestr, syst, 0.0)); std::ostringstream curparstring; curparstring << " " << setw(3) << left << i << ". " << setw(maxcount) << syst << " = " << setw(10) << curval << " +- " << setw(10) << curerr << " " << setw(8) << curunits << " " << setw(10) << convval << " +- " << setw(10) << converr << " " << setw(8) << convunits; LOG(FIT) << curparstring.str() << std::endl; } LOG(FIT)<<"------------"<<std::endl; double like = fSampleFCN->GetLikelihood(); LOG(FIT) << std::left << std::setw(46) << "Likelihood for JointFCN: " << like << endl; LOG(FIT)<<"------------"<<std::endl; } /* Write Functions */ //************************************* void SystematicRoutines::SaveResults(){ //************************************* fOutputRootFile->cd(); SaveCurrentState(); } //************************************* void SystematicRoutines::SaveCurrentState(std::string subdir){ //************************************* LOG(FIT)<<"Saving current full FCN predictions" <<std::endl; // Setup DIRS TDirectory* curdir = gDirectory; if (!subdir.empty()){ TDirectory* newdir =(TDirectory*) gDirectory->mkdir(subdir.c_str()); newdir->cd(); } FitBase::GetRW()->Reconfigure(); fSampleFCN->ReconfigureAllEvents(); fSampleFCN->Write(); // Change back to current DIR curdir->cd(); return; } //************************************* void SystematicRoutines::SaveNominal(){ //************************************* fOutputRootFile->cd(); LOG(FIT)<<"Saving Nominal Predictions (be cautious with this)" <<std::endl; FitBase::GetRW()->Reconfigure(); SaveCurrentState("nominal"); }; //************************************* void SystematicRoutines::SavePrefit(){ //************************************* fOutputRootFile->cd(); LOG(FIT)<<"Saving Prefit Predictions"<<std::endl; UpdateRWEngine(fStartVals); SaveCurrentState("prefit"); UpdateRWEngine(fCurVals); }; /* MISC Functions */ //************************************* int SystematicRoutines::GetStatus(){ //************************************* return 0; } //************************************* void SystematicRoutines::SetupCovariance(){ //************************************* // Remove covares if they exist if (fCovar) delete fCovar; if (fCovarFree) delete fCovarFree; if (fCorrel) delete fCorrel; if (fCorrelFree) delete fCorrelFree; if (fDecomp) delete fDecomp; if (fDecompFree) delete fDecompFree; int NFREE = 0; int NDIM = 0; // Get NFREE from min or from vals (for cases when doing throws) NDIM = fParams.size(); for (UInt_t i = 0; i < fParams.size(); i++){ if (!fFixVals[fParams[i]]) NFREE++; } if (NDIM == 0) return; fCovar = new TH2D("covariance","covariance",NDIM,0,NDIM,NDIM,0,NDIM); if (NFREE > 0){ fCovarFree = new TH2D("covariance_free", "covariance_free", NFREE,0,NFREE, NFREE,0,NFREE); } // Set Bin Labels int countall = 0; int countfree = 0; for (UInt_t i = 0; i < fParams.size(); i++){ fCovar->GetXaxis()->SetBinLabel(countall+1,fParams[i].c_str()); fCovar->GetYaxis()->SetBinLabel(countall+1,fParams[i].c_str()); countall++; if (!fFixVals[fParams[i]] and NFREE > 0){ fCovarFree->GetXaxis()->SetBinLabel(countfree+1,fParams[i].c_str()); fCovarFree->GetYaxis()->SetBinLabel(countfree+1,fParams[i].c_str()); countfree++; } } fCorrel = PlotUtils::GetCorrelationPlot(fCovar,"correlation"); fDecomp = PlotUtils::GetDecompPlot(fCovar,"decomposition"); if (NFREE > 0)fCorrelFree = PlotUtils::GetCorrelationPlot(fCovarFree, "correlation_free"); if (NFREE > 0)fDecompFree = PlotUtils::GetDecompPlot(fCovarFree,"decomposition_free"); return; }; //************************************* void SystematicRoutines::ThrowCovariance(bool uniformly){ //************************************* // Set fThrownVals to all values in currentVals for (UInt_t i = 0; i < fParams.size(); i++){ std::string name = fParams.at(i); fThrownVals[name] = fCurVals[name]; } for (PullListConstIter iter = fInputThrows.begin(); iter != fInputThrows.end(); iter++){ ParamPull* pull = *iter; pull->ThrowCovariance(); TH1D dialhist = pull->GetDataHist(); for (int i = 0; i < dialhist.GetNbinsX(); i++){ std::string name = std::string(dialhist.GetXaxis()->GetBinLabel(i+1)); if (fCurVals.find(name) != fCurVals.end()){ fThrownVals[name] = dialhist.GetBinContent(i+1); } } // Reset throw incase pulls are calculated. pull->ResetToy(); } return; }; //************************************* void SystematicRoutines::GenerateErrorBands(){ //************************************* TDirectory* errorDIR = (TDirectory*) fOutputRootFile->mkdir("error_bands"); errorDIR->cd(); - TFile* tempfile = new TFile((fOutputFile + ".throws.root").c_str(),"RECREATE"); + // Make a second file to store throws + std::string tempFileName = fOutputFile; + if (tempFileName.find(".root") != std::string::npos) tempFileName.erase(tempFileName.find(".root"), 5); + tempFileName += ".throws.root"; + TFile* tempfile = new TFile(tempFileName.c_str(),"RECREATE"); + tempfile->cd(); int nthrows = FitPar::Config().GetParI("error_throws"); UpdateRWEngine(fCurVals); fSampleFCN->ReconfigureAllEvents(); TDirectory* nominal = (TDirectory*) tempfile->mkdir("nominal"); nominal->cd(); fSampleFCN->Write(); TDirectory* outnominal = (TDirectory*) fOutputRootFile->mkdir("nominal_throw"); outnominal->cd(); fSampleFCN->Write(); fOutputRootFile->cd(); TTree* parameterTree = new TTree("throws","throws"); double chi2; for (UInt_t i = 0; i < fParams.size(); i++) parameterTree->Branch(fParams[i].c_str(), &fThrownVals[fParams[i]], (fParams[i] + "/D").c_str()); parameterTree->Branch("chi2",&chi2,"chi2/D"); fSampleFCN->CreateIterationTree("error_iterations", FitBase::GetRW()); // Would anybody actually want to do uniform throws of any parameter?? bool uniformly = FitPar::Config().GetParB("error_uniform"); // Run Throws and save for (Int_t i = 0; i < nthrows; i++){ TDirectory* throwfolder = (TDirectory*)tempfile->mkdir(Form("throw_%i",i)); throwfolder->cd(); // Generate Random Parameter Throw ThrowCovariance(uniformly); // Run Eval double *vals = FitUtils::GetArrayFromMap( fParams, fThrownVals ); chi2 = fSampleFCN->DoEval( vals ); delete vals; // Save the FCN fSampleFCN->Write(); parameterTree->Fill(); } fOutputRootFile->cd(); fSampleFCN->WriteIterationTree(); // fDecompFree->Write(); // fCovarFree->Write(); // parameterTree->Write(); // delete parameterTree; // Now go through the keys in the temporary file and look for TH1D, and TH2D plots TIter next(nominal->GetListOfKeys()); TKey *key; while ((key = (TKey*)next())) { TClass *cl = gROOT->GetClass(key->GetClassName()); if (!cl->InheritsFrom("TH1D") and !cl->InheritsFrom("TH2D")) continue; TH1D *baseplot = (TH1D*)key->ReadObj(); std::string plotname = std::string(baseplot->GetName()); LOG(FIT) << "Creating error bands for " << plotname; if (LOG_LEVEL(FIT)){ if (!uniformly) std::cout << " : Using COVARIANCE Throws! " << std::endl; else std::cout << " : Using UNIFORM THROWS!!! " << std::endl; } int nbins = baseplot->GetNbinsX()*baseplot->GetNbinsY(); // Setup TProfile with RMS option TProfile* tprof = new TProfile((plotname + "_prof").c_str(),(plotname + "_prof").c_str(),nbins, 0, nbins, "S"); // Setup The TTREE double* bincontents; bincontents = new double[nbins]; double* binlowest; binlowest = new double[nbins]; double* binhighest; binhighest = new double[nbins]; errorDIR->cd(); TTree* bintree = new TTree((plotname + "_tree").c_str(), (plotname + "_tree").c_str()); for (Int_t i = 0; i < nbins; i++){ bincontents[i] = 0.0; binhighest[i] = 0.0; binlowest[i] = 0.0; bintree->Branch(Form("content_%i",i),&bincontents[i],Form("content_%i/D",i)); } for (Int_t i = 0; i < nthrows; i++){ TH1* newplot = (TH1*)tempfile->Get(Form(("throw_%i/" + plotname).c_str(),i)); for (Int_t j = 0; j < nbins; j++){ tprof->Fill(j+0.5, newplot->GetBinContent(j+1)); bincontents[j] = newplot->GetBinContent(j+1); if (bincontents[j] < binlowest[j] or i == 0) binlowest[j] = bincontents[j]; if (bincontents[j] > binhighest[j] or i == 0) binhighest[j] = bincontents[j]; } errorDIR->cd(); bintree->Fill(); delete newplot; } errorDIR->cd(); if (!uniformly){ LOG(FIT) << "Uniformly Calculating Plot Errors!" << std::endl; } for (Int_t j = 0; j < nbins; j++){ if (!uniformly){ baseplot->SetBinError(j+1,tprof->GetBinError(j+1)); } else { baseplot->SetBinContent(j+1, 0.0);//(binlowest[j] + binhighest[j]) / 2.0); baseplot->SetBinError(j+1, 0.0); //(binhighest[j] - binlowest[j])/2.0); } } errorDIR->cd(); baseplot->Write(); tprof->Write(); bintree->Write(); delete baseplot; delete tprof; delete bintree; delete [] bincontents; } return; }; //************************************* void SystematicRoutines::PlotLimits(){ //************************************* TDirectory* limfolder = (TDirectory*) fOutputRootFile->mkdir("Limits"); limfolder->cd(); // Set all parameters at their starting values for (UInt_t i = 0; i < fParams.size(); i++){ fCurVals[fParams[i]] = fStartVals[fParams[i]]; } TDirectory* nomfolder = (TDirectory*) limfolder->mkdir("nominal"); nomfolder->cd(); UpdateRWEngine(fCurVals); fSampleFCN->ReconfigureAllEvents(); fSampleFCN->Write(); limfolder->cd(); std::vector<std::string> allfolders; // Loop through each parameter for (UInt_t i = 0; i < fParams.size(); i++){ std::string syst = fParams[i]; if (fFixVals[syst]) continue; // Loop Downwards while (fCurVals[syst] > fMinVals[syst]){ fCurVals[syst] = fCurVals[syst] - fStepVals[syst]; // Check Limit if (fCurVals[syst] < fMinVals[syst]) fCurVals[syst] = fMinVals[syst]; // Check folder exists std::string curvalstring = std::string( Form( (syst + "_%f").c_str(), fCurVals[syst] ) ); if (std::find(allfolders.begin(), allfolders.end(), curvalstring) != allfolders.end()) break; // Make new folder for variation TDirectory* minfolder = (TDirectory*) limfolder->mkdir(Form( (syst + "_%f").c_str(), fCurVals[syst] ) ); minfolder->cd(); allfolders.push_back(curvalstring); // Update Iterations double *vals = FitUtils::GetArrayFromMap( fParams, fCurVals ); fSampleFCN->DoEval( vals ); delete vals; // Save to folder fSampleFCN->Write(); } // Reset before next loop fCurVals[syst] = fStartVals[syst]; // Loop Upwards now while (fCurVals[syst] < fMaxVals[syst]){ fCurVals[syst] = fCurVals[syst] + fStepVals[syst]; // Check Limit if (fCurVals[syst] > fMaxVals[syst]) fCurVals[syst] = fMaxVals[syst]; // Check folder exists std::string curvalstring = std::string( Form( (syst + "_%f").c_str(), fCurVals[syst] ) ); if (std::find(allfolders.begin(), allfolders.end(), curvalstring) != allfolders.end()) break; // Make new folder TDirectory* maxfolder = (TDirectory*) limfolder->mkdir(Form( (syst + "_%f").c_str(), fCurVals[syst] ) ); maxfolder->cd(); allfolders.push_back(curvalstring); // Update Iterations double *vals = FitUtils::GetArrayFromMap( fParams, fCurVals ); fSampleFCN->DoEval( vals ); delete vals; // Save to file fSampleFCN->Write(); } // Reset before leaving fCurVals[syst] = fStartVals[syst]; UpdateRWEngine(fCurVals); } return; }