/*************************************************************************** PFitter.cpp Author: Andreas Suter e-mail: andreas.suter@psi.ch ***************************************************************************/ /*************************************************************************** * Copyright (C) 2007-2023 by Andreas Suter * * andreas.suter@psi.ch * * * * This program 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 2 of the License, or * * (at your option) any later version. * * * * This program 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 this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #ifdef HAVE_GOMP #include #endif #include #include #include #include #include #include #include #include "Minuit2/FunctionMinimum.h" #include "Minuit2/MnContours.h" #include "Minuit2/MnHesse.h" #include "Minuit2/MnMinimize.h" #include "Minuit2/MnMigrad.h" #include "Minuit2/MnMinos.h" #include "Minuit2/MnPlot.h" #include "Minuit2/MnPrint.h" #include "Minuit2/MnScan.h" #include "Minuit2/MnSimplex.h" #include "Minuit2/MnUserParameterState.h" #include "Minuit2/MinosError.h" #include #include #include #include #include #include #include #include "PFitter.h" //+++ PSectorChisq class +++++++++++++++++++++++++++++++++++++++++++++++++++ //-------------------------------------------------------------------------- // Constructor //-------------------------------------------------------------------------- /** *

Constructor. */ PSectorChisq::PSectorChisq(UInt_t noOfRuns) : fNoOfRuns(noOfRuns) { // init fLast = 0.0; fChisq = 0.0; fExpectedChisq = 0.0; fNDF = 0; fFirst.resize(fNoOfRuns); fChisqRun.resize(fNoOfRuns); fExpectedChisqRun.resize(fNoOfRuns); fNDFRun.resize(fNoOfRuns); for (UInt_t i=0; iSet the time of the fgb of a given RUN * * @param first time stamp of the fgb * @param idx index of the RUN */ void PSectorChisq::SetRunFirstTime(Double_t first, UInt_t idx) { if (idx > fNoOfRuns) { std::cerr << "**WARNING** from PSectorChisq::SetRunFirstTime. It tries to set" << std::endl; std::cerr << " a fgb time stamp with idx=" << idx << " which is larger than #RUNS=" << fNoOfRuns << "." << std::endl; std::cerr << " Will ignore it, but you better check what is going on!" << std::endl; return; } fFirst[idx] = first; } //-------------------------------------------------------------------------- // SetChisq //-------------------------------------------------------------------------- /** *

Set the chisq/maxLH for a given detector with index idx. * * @param chisq chisq/maxLH to be set * @param idx index of the run to be set */ void PSectorChisq::SetChisq(Double_t chisq, UInt_t idx) { if (idx > fNoOfRuns) { std::cerr << "**WARNING** from PSectorChisq::SetChisq. It tries to set" << std::endl; std::cerr << " a chisq with idx=" << idx << " which is larger than #RUNS=" << fNoOfRuns << "." << std::endl; std::cerr << " Will ignore it, but you better check what is going on!" << std::endl; return; } fChisqRun[idx] = chisq; } //-------------------------------------------------------------------------- // SetExpectedChisq //-------------------------------------------------------------------------- /** *

Set the expected chisq/maxLH for a given detector with index idx. * * @param chisq expected chisq/maxLH to be set * @param idx index of the run to be set */ void PSectorChisq::SetExpectedChisq(Double_t chisq, UInt_t idx) { if (idx > fNoOfRuns) { std::cerr << "**WARNING** from PSectorChisq::SetExpectedChisq. It tries to set" << std::endl; std::cerr << " a chisq with idx=" << idx << " which is larger than #RUNS=" << fNoOfRuns << "." << std::endl; std::cerr << " Will ignore it, but you better check what is going on!" << std::endl; return; } fExpectedChisqRun[idx] = chisq; } //-------------------------------------------------------------------------- // SetNDF //-------------------------------------------------------------------------- /** *

Set the NDF for a given detector with index idx. * * @param ndf to be set * @param idx index of the run to be set */ void PSectorChisq::SetNDF(UInt_t ndf, UInt_t idx) { if (idx > fNoOfRuns) { std::cerr << "**WARNING** from PSectorChisq::SetNDF. It tries to set" << std::endl; std::cerr << " a NDF with idx=" << idx << " which is larger than #RUNS=" << fNoOfRuns << "." << std::endl; std::cerr << " Will ignore it, but you better check what is going on!" << std::endl; return; } fNDFRun[idx] = ndf; } //-------------------------------------------------------------------------- // GetTimeRangeFirst //-------------------------------------------------------------------------- /** *

Get the fgb time of RUN with index idx. If idx is out-of-range * PMUSR_UNDEFINED is returned. * * @param idx index of the RUN * * return: return the fgb time of RUN with index idx. */ Double_t PSectorChisq::GetTimeRangeFirst(UInt_t idx) { if (idx > fNoOfRuns) return PMUSR_UNDEFINED; return fFirst[idx]; } //-------------------------------------------------------------------------- // GetChisq //-------------------------------------------------------------------------- /** *

Get chisq/maxLH of the run with index idx * * @param idx index of the run * * return: chisq/maxLH of the requested run or -1.0 if the idx is out-of-range. */ Double_t PSectorChisq::GetChisq(UInt_t idx) { if (idx >= fNoOfRuns) return -1.0; return fChisqRun[idx]; } //-------------------------------------------------------------------------- // GetExpectedChisq //-------------------------------------------------------------------------- /** *

Get expected chisq/maxLH of the run with index idx * * @param idx index of the run * * return: chisq/maxLH of the requested run or -1.0 if the idx is out-of-range. */ Double_t PSectorChisq::GetExpectedChisq(UInt_t idx) { if (idx >= fNoOfRuns) return -1.0; return fExpectedChisqRun[idx]; } //-------------------------------------------------------------------------- // GetNDF //-------------------------------------------------------------------------- /** *

Get NDF of the run with index idx * * @param idx index of the run * * return: NDF of the requested run or 0.0 if the idx is out-of-range. */ UInt_t PSectorChisq::GetNDF(UInt_t idx) { if (idx >= fNoOfRuns) return 0; return fNDFRun[idx]; } //+++ PFitter class ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //-------------------------------------------------------------------------- // Constructor //-------------------------------------------------------------------------- /** *

Constructor. * * \param runInfo pointer of the msr-file handler * \param runListCollection pointer of the run list collection (pre-processed historgrams) * \param chisq_only flag: true=calculate chisq only (no fitting) */ PFitter::PFitter(PMsrHandler *runInfo, PRunListCollection *runListCollection, Bool_t chisq_only) : fChisqOnly(chisq_only), fRunInfo(runInfo), fRunListCollection(runListCollection) { // initialize variables fDKSReady = false; fIsScanOnly = true; fConverged = false; fUseChi2 = true; // chi^2 is the default fStrategy = 1; // 0=low, 1=default, 2=high fSectorFlag = false; fParams = *(runInfo->GetMsrParamList()); fCmdLines = *runInfo->GetMsrCommands(); // init class variables fFitterFcn = nullptr; fFitterFcnDKS = nullptr; fFcnMin = nullptr; fScanAll = true; fScanParameter[0] = 0; fScanParameter[1] = 0; fScanNoPoints = 41; // minuit2 default fScanLow = 0.0; // minuit2 default, i.e. 2 std deviations fScanHigh = 0.0; // minuit2 default, i.e. 2 std deviations fPrintLevel = 1.0; // keep all the fit ranges in case RANGE command is present PDoublePair rangeGlob; PMsrGlobalBlock *global = fRunInfo->GetMsrGlobal(); rangeGlob.first = global->GetFitRange(0); rangeGlob.second = global->GetFitRange(1); PMsrRunList *runs = fRunInfo->GetMsrRunList(); PDoublePair range; for (UInt_t i=0; isize(); i++) { range.first = (*runs)[i].GetFitRange(0); range.second = (*runs)[i].GetFitRange(1); if (range.first == PMUSR_UNDEFINED) fOriginalFitRange.push_back(rangeGlob); else fOriginalFitRange.push_back(range); } // check msr minuit commands if (!CheckCommands()) { return; } // create phase bool array GetPhaseParams(); // get the DKS tag from the commands block fDKSTag = fRunInfo->GetDKSTag(); // check if the theory function can already run on the GPU std::string theo = fRunInfo->GetDKSTheoryString(); if (fDKSTag != DKS_CPU_OPENMP) { if (!theo.compare("??")) { // theory not yet DKS ready std::cout << std::endl << ">> PFitter::PFitter(): **INFO** theory not yet DKS/GPU ready. Will run on the CPU." << std::endl; } else { fDKSReady = true; std::cout << std::endl << ">> PFitter::PFitter(): **INFO** theory DKS/GPU ready. Will run on the GPU." << std::endl; } } // create fit function object depending whether DKS/GPU can be used or not if (fDKSReady && (fDKSTag != DKS_CPU_OPENMP)) { // run on the GPU fFitterFcnDKS = new PFitterFcnDKS(runListCollection, fUseChi2, fDKSTag, theo); if (!fFitterFcnDKS) { fIsValid = false; } if (!fFitterFcnDKS->IsValid()) { fIsValid = false; } } else { // run on the CPU fDKSReady = false; // needed in case dksTag == DKS_CPU_OPENMP fFitterFcn = new PFitterFcn(runListCollection, fUseChi2); if (!fFitterFcn) { fIsValid = false; } } } //-------------------------------------------------------------------------- // Destructor //-------------------------------------------------------------------------- /** *

Destructor. */ PFitter::~PFitter() { fCmdList.clear(); fScanData.clear(); fElapsedTime.clear(); if (fFcnMin) { delete fFcnMin; fFcnMin = nullptr; } if (fFitterFcnDKS) { delete fFitterFcnDKS; fFitterFcnDKS = 0; } if (fFitterFcn) { delete fFitterFcn; fFitterFcn = nullptr; } } //-------------------------------------------------------------------------- // GetPhaseParams (private) //-------------------------------------------------------------------------- /** *

Checks which parameters are phases. This information is needed to * restrict the phases to the intervall -360 to +360 degrees. */ void PFitter::GetPhaseParams() { fPhase.resize(fRunInfo->GetNoOfParams()); for (unsigned int i=0; iGetMsrTheory(); TObjArray *tok = nullptr; TObjString *ostr = nullptr; TString str; int pos = -1; for (unsigned int i=0; isize(); i++) { pos = -1; TString line = theo->at(i).fLine; if (line.Contains("TFieldCos") || line.Contains("tf ") || line.Contains("bessel") || line.Contains("b ") || line.Contains("skewedGss") || line.Contains("skg ") || line.Contains("staticNKTF") || line.Contains("snktf ") || line.Contains("dynamicNKTF") || line.Contains("dnktf ")) { // phase is 1st param pos = 1; } if (line.Contains("internFld") || line.Contains("if ") || line.Contains("internBsl") || line.Contains("ib ")) { // phase is 2nd param pos = 2; } if (line.Contains("muMinusExpTF") || line.Contains("mmsetf ")) { // phase is 5th param pos = 5; } if (pos == -1) continue; // extract phase token tok = line.Tokenize(" \t"); if (tok == nullptr) { std::cerr << "PFitter::GetPhaseParams(): **ERROR** couldn't tokenize theory line string." << std::endl; return; } if (tok->GetEntries() > pos) { ostr = dynamic_cast(tok->At(pos)); str = ostr->GetString(); } // clean up delete tok; tok = nullptr; // decode phase token. It can be funX, mapX, or a number if (str.Contains("fun")) { // function PIntVector parVec = GetParFromFun(str); for (int i=0; iGetNoOfParams()) fPhase[parVec[i]-1] = true; } } else if (str.Contains("map")) { // map PIntVector parVec = GetParFromMap(str); for (int i=0; iGetNoOfParams()) fPhase[parVec[i]-1] = true; } } else { // must be a number int idx = str.Atoi(); if (idx == 0) { // something went wrong, str is not an integer std::cerr << "PFitter::GetPhaseParams(): **ERROR** str=" << str.View() << " is not an integer!" << std::endl; return; } idx -= 1; // param start at 1, vector at 0 if (idx >= fRunInfo->GetNoOfParams()) { // idx is out-of-range std::cerr << "PFitter::GetPhaseParams(): **ERROR** idx=" << idx << " is > #param = " << fRunInfo->GetNoOfParams() << "!" << std::endl; return; } fPhase[idx] = true; } } } //-------------------------------------------------------------------------- // GetParFromFun (private) //-------------------------------------------------------------------------- /** *

Extract from string funX the function number. Base on the function number * the paramter numbers will be collected. * * @param funStr string of the form funX, where X is the function number * @return a vector of all the parameter numbers related to funX */ PIntVector PFitter::GetParFromFun(const TString funStr) { PIntVector parVec; PMsrLines *funList = fRunInfo->GetMsrFunctions(); TObjArray *tok = nullptr; TObjString *ostr = nullptr; TString str; for (int i=0; isize(); i++) { if (funList->at(i).fLine.Contains(funStr)) { // tokenize function string tok = funList->at(i).fLine.Tokenize(" =+-*/"); if (tok == nullptr) { std::cerr << "PFitter::GetParFromFun(): **ERROR** couldn't tokenize function string." << std::endl; return parVec; } for (int j=1; jGetEntries(); j++) { ostr = dynamic_cast(tok->At(j)); str = ostr->GetString(); // parse tok for parX if (str.Contains("par")) { // find start idx of par in token Ssiz_t idx = str.Index("par"); idx += 3; TString parStr(""); do { parStr += str[idx]; } while (isdigit(str[idx++])); parVec.push_back(parStr.Atoi()); } // parse tok for mapX if (str.Contains("map")) { // find start idx of par in token Ssiz_t idx = str.Index("map"); idx += 3; TString mapStr("map"); do { mapStr += str[idx]; } while (isdigit(str[idx++])); PIntVector mapParVec = GetParFromMap(mapStr); for (int k=0; kExtract from string mapX the map number. Based on the map number the * parameter numbers will be collected. * * @param mapStr string of the form mapX, where X is the map number * @return a vector of all the parameter numbers related to mapX */ PIntVector PFitter::GetParFromMap(const TString mapStr) { PIntVector parVec; TString str = mapStr; str.Remove(0,3); // remove map from string int idx=str.Atoi(); if (idx == 0) { std::cerr << "PFitter::GetParFromMap(): **ERROR** couldn't get propper index from mapX!" << std::endl; return parVec; } idx -= 1; // map starts at 1, map vector at 0 // go through all the runs and collect the parameters from the map vectors PMsrRunList *runList = fRunInfo->GetMsrRunList(); if (runList == nullptr) { std::cerr << "PFitter::GetParFromMap(): **ERROR** couldn't get required run list information!" << std::endl; return parVec; } PIntVector *map = nullptr; for (int i=0; isize(); i++) { map = runList->at(i).GetMap(); if (map == nullptr) { std::cerr << "PFitter::GetParFromMap(): **ERROR** couldn't get required map information (idx=" << i << ")!" << std::endl; parVec.clear(); return parVec; } if (idx >= map->size()) { std::cerr << "PFitter::GetParFromMap(): **ERROR** requested map index (idx=" << idx << ") out-of-range (" << map->size() << ")!" << std::endl; parVec.clear(); return parVec; } parVec.push_back(map->at(idx)); } return parVec; } //-------------------------------------------------------------------------- // DoFit //-------------------------------------------------------------------------- /** *

Main calling routine to invoke minuit2, i.e. fitting etc. * * return: true if all commands could be executed successfully, otherwise returns false. */ Bool_t PFitter::DoFit() { // feed minuit parameters SetParameters(); // check if only chisq/maxLH shall be calculated once if (fChisqOnly) { std::vector param = fMnUserParams.Params(); std::vector error = fMnUserParams.Errors(); Int_t usedParams = 0; for (UInt_t i=0; iGetTotalNoOfFittedBins() - static_cast(usedParams); val = (*fFitterFcnDKS)(param); } else { ndf = fFitterFcn->GetTotalNoOfFittedBins() - static_cast(usedParams); val = (*fFitterFcn)(param); } if (fUseChi2) { // calculate expected chisq Double_t totalExpectedChisq = 0.0; PDoubleVector expectedChisqPerRun; if (fDKSReady) fFitterFcnDKS->CalcExpectedChiSquare(param, totalExpectedChisq, expectedChisqPerRun); else fFitterFcn->CalcExpectedChiSquare(param, totalExpectedChisq, expectedChisqPerRun); // calculate chisq per run std::vector chisqPerRun; for (UInt_t i=0; iGetMsrRunList()->size(); i++) { chisqPerRun.push_back(fRunListCollection->GetSingleRunChisq(param, i)); } std::cout << std::endl << std::endl << ">> chisq = " << val << ", NDF = " << ndf << ", chisq/NDF = " << val/ndf; if (totalExpectedChisq != 0.0) { std::cout << std::endl << ">> expected chisq = " << totalExpectedChisq << ", NDF = " << ndf << ", expected chisq/NDF = " << totalExpectedChisq/ndf; UInt_t ndf_run = 0; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); else ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); if (ndf_run > 0) std::cout << std::endl << ">> run block " << i+1 << ": (NDF/red.chisq/red.chisq_e) = (" << ndf_run << "/" << chisqPerRun[i]/ndf_run << "/" << expectedChisqPerRun[i]/ndf_run << ")"; } } else if (chisqPerRun.size() > 0) { // in case expected chisq is not applicable like for asymmetry fits UInt_t ndf_run = 0; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); else ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); if (ndf_run > 0) std::cout << std::endl << ">> run block " << i+1 << ": (NDF/red.chisq) = (" << ndf_run << "/" << chisqPerRun[i]/ndf_run << ")"; } } // clean up chisqPerRun.clear(); expectedChisqPerRun.clear(); if (fSectorFlag) { PDoublePairVector secFitRange; secFitRange.resize(1); for (UInt_t k=0; kSetFitRange(secFitRange); // calculate chisq and NDF if (fDKSReady) { ndf = fFitterFcnDKS->GetTotalNoOfFittedBins() - static_cast(usedParams); val = (*fFitterFcnDKS)(param); } else { ndf = fFitterFcn->GetTotalNoOfFittedBins() - static_cast(usedParams); val = (*fFitterFcn)(param); } // calculate expected chisq totalExpectedChisq = 0.0; if (fDKSReady) fFitterFcnDKS->CalcExpectedChiSquare(param, totalExpectedChisq, expectedChisqPerRun); else fFitterFcn->CalcExpectedChiSquare(param, totalExpectedChisq, expectedChisqPerRun); // calculate chisq per run for (UInt_t i=0; iGetMsrRunList()->size(); i++) { chisqPerRun.push_back(fRunListCollection->GetSingleRunChisq(param, i)); } std::cout << std::endl; std::cout << "++++" << std::endl; std::cout << ">> Sector " << k+1 << ": FitRange: " << secFitRange[0].first << ", " << secFitRange[0].second << std::endl; std::cout << ">> chisq = " << val << ", NDF = " << ndf << ", chisq/NDF = " << val/ndf; if (totalExpectedChisq != 0.0) { std::cout << std::endl << ">> expected chisq = " << totalExpectedChisq << ", NDF = " << ndf << ", expected chisq/NDF = " << totalExpectedChisq/ndf; UInt_t ndf_run = 0; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); else ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); if (ndf_run > 0) std::cout << std::endl << ">> run block " << i+1 << ": (NDF/red.chisq/red.chisq_e) = (" << ndf_run << "/" << chisqPerRun[i]/ndf_run << "/" << expectedChisqPerRun[i]/ndf_run << ")"; } } else if (chisqPerRun.size() > 0) { // in case expected chisq is not applicable like for asymmetry fits UInt_t ndf_run = 0; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); else ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); if (ndf_run > 0) std::cout << std::endl << ">> run block " << i+1 << ": (NDF/red.chisq) = (" << ndf_run << "/" << chisqPerRun[i]/ndf_run << ")"; } } // clean up chisqPerRun.clear(); expectedChisqPerRun.clear(); } } } else { // max. log likelihood // calculate expected maxLH Double_t totalExpectedMaxLH = 0.0; std::vector expectedMaxLHPerRun; if (fDKSReady) fFitterFcnDKS->CalcExpectedChiSquare(param, totalExpectedMaxLH, expectedMaxLHPerRun); else fFitterFcn->CalcExpectedChiSquare(param, totalExpectedMaxLH, expectedMaxLHPerRun); // calculate maxLH per run std::vector maxLHPerRun; for (UInt_t i=0; iGetMsrRunList()->size(); i++) { maxLHPerRun.push_back(fRunListCollection->GetSingleRunMaximumLikelihood(param, i)); } std::cout << std::endl << std::endl << ">> maxLH = " << val << ", NDF = " << ndf << ", maxLH/NDF = " << val/ndf; if (totalExpectedMaxLH != 0.0) { std::cout << std::endl << ">> expected maxLH = " << totalExpectedMaxLH << ", NDF = " << ndf << ", expected maxLH/NDF = " << totalExpectedMaxLH/ndf; UInt_t ndf_run = 0; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); else ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); if (ndf_run > 0) std::cout << std::endl << ">> run block " << i+1 << ": (NDF/maxLH.chisq/maxLH.chisq_e) = (" << ndf_run << "/" << maxLHPerRun[i]/ndf_run << "/" << expectedMaxLHPerRun[i]/ndf_run << ")"; } } // clean up maxLHPerRun.clear(); expectedMaxLHPerRun.clear(); if (fSectorFlag) { PDoublePairVector secFitRange; secFitRange.resize(1); for (UInt_t k=0; kSetFitRange(secFitRange); // calculate chisq and NDF if (fDKSReady) { ndf = static_cast(fFitterFcnDKS->GetTotalNoOfFittedBins()) - usedParams; val = (*fFitterFcnDKS)(param); } else { ndf = static_cast(fFitterFcn->GetTotalNoOfFittedBins()) - usedParams; val = (*fFitterFcn)(param); } // calculate expected maxLH totalExpectedMaxLH = 0.0; if (fDKSReady) fFitterFcnDKS->CalcExpectedChiSquare(param, totalExpectedMaxLH, expectedMaxLHPerRun); else fFitterFcn->CalcExpectedChiSquare(param, totalExpectedMaxLH, expectedMaxLHPerRun); // calculate maxLH per run for (UInt_t i=0; iGetMsrRunList()->size(); i++) { maxLHPerRun.push_back(fRunListCollection->GetSingleRunMaximumLikelihood(param, i)); } std::cout << std::endl; std::cout << "++++" << std::endl; std::cout << ">> Sector " << k+1 << ": FitRange: " << secFitRange[0].first << ", " << secFitRange[0].second << std::endl; std::cout << ">> maxLH = " << val << ", NDF = " << ndf << ", maxLH/NDF = " << val/ndf; if (totalExpectedMaxLH != 0.0) { std::cout << std::endl << ">> expected maxLH = " << totalExpectedMaxLH << ", NDF = " << ndf << ", expected maxLH/NDF = " << totalExpectedMaxLH/ndf; UInt_t ndf_run = 0; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); else ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); if (ndf_run > 0) std::cout << std::endl << ">> run block " << i+1 << ": (NDF/maxLH.chisq/maxLH.chisq_e) = (" << ndf_run << "/" << maxLHPerRun[i]/ndf_run << "/" << expectedMaxLHPerRun[i]/ndf_run << ")"; } } // clean up maxLHPerRun.clear(); expectedMaxLHPerRun.clear(); } } } std::cout << std::endl << std::endl; return true; } // debugging information #ifdef HAVE_GOMP std::cout << std::endl << ">> Number of available threads for the function optimization: " << omp_get_max_threads() << std::endl; #endif // real fit wanted if (fUseChi2) std::cout << std::endl << ">> Chi Square fit will be executed" << std::endl; else std::cout << std::endl << ">> Maximum Likelihood fit will be executed" << std::endl; Bool_t status = true; // init positive errors to default false, if minos is called, it will be set true there for (UInt_t i=0; iSetMsrParamPosErrorPresent(i, false); } // walk through the command list and execute them Bool_t firstSave = true; for (UInt_t i=0; iGetMsrStatistic()->fValid = true; } else { fRunInfo->GetMsrStatistic()->fValid = false; } return true; } //-------------------------------------------------------------------------- // CheckCommands //-------------------------------------------------------------------------- /** *

Check the msr-file COMMAND's, fill the command queue and make sure that given parameters (if present) * do make any sense. * * return: true if the commands are valid, otherwise returns false. */ Bool_t PFitter::CheckCommands() { fIsValid = true; // check if chisq or log max likelihood fit fUseChi2 = fRunInfo->GetMsrStatistic()->fChisq; // walk through the msr-file COMMAND block PIntPair cmd; PMsrLines::iterator it; UInt_t cmdLineNo = 0; TString line; Ssiz_t pos; for (it = fCmdLines.begin(); it != fCmdLines.end(); ++it) { if (it == fCmdLines.begin()) cmdLineNo = 0; else cmdLineNo++; // strip potential comments line = it->fLine; pos = line.First('#'); if (pos > 0) // comment present line.Remove(pos,line.Length()-pos); if (line.Contains("COMMANDS", TString::kIgnoreCase)) { continue; } else if (it->fLine.Contains("OpenMP", TString::kIgnoreCase)) { // run on CPU using OpenMP continue; } else if (it->fLine.Contains("CUDA", TString::kIgnoreCase)) { // try to run DKS/GPU CUDA continue; } else if (it->fLine.Contains("OpenCL-GPU", TString::kIgnoreCase)) { // try to run DKS/GPU OpenCL continue; } else if (it->fLine.Contains("OpenCL-CPU", TString::kIgnoreCase)) { // try to run DKS/CPU OpenCL continue; } else if (it->fLine.Contains("SET BATCH", TString::kIgnoreCase)) { // needed for backward compatibility continue; } else if (line.Contains("END RETURN", TString::kIgnoreCase)) { // needed for backward compatibility continue; } else if (line.Contains("CHI_SQUARE", TString::kIgnoreCase)) { continue; } else if (line.Contains("MAX_LIKELIHOOD", TString::kIgnoreCase)) { continue; } else if (line.Contains("SCALE_N0_BKG", TString::kIgnoreCase)) { continue; } else if (line.Contains("INTERACTIVE", TString::kIgnoreCase)) { cmd.first = PMN_INTERACTIVE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("CONTOURS", TString::kIgnoreCase)) { cmd.first = PMN_CONTOURS; cmd.second = cmdLineNo; fCmdList.push_back(cmd); // filter out possible parameters for scan TObjArray *tokens = nullptr; TObjString *ostr; TString str; UInt_t ival; tokens = line.Tokenize(", \t"); for (Int_t i=0; iGetEntries(); i++) { ostr = dynamic_cast(tokens->At(i)); str = ostr->GetString(); if ((i==1) || (i==2)) { // parX / parY // check that token is a UInt_t if (!str.IsDigit()) { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> parameter number is not number!"; std::cerr << std::endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]"; std::cerr << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } ival = str.Atoi(); // check that parameter is within range if ((ival < 1) || (ival > fParams.size())) { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> parameter number is out of range [1," << fParams.size() << "]!"; std::cerr << std::endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]"; std::cerr << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } // keep parameter fScanParameter[i-1] = ival-1; // internally parameter number starts at 0 fScanAll = false; } if (i==3) { // check that token is a UInt_t if (!str.IsDigit()) { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> number of points is not number!"; std::cerr << std::endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]"; std::cerr << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } ival = str.Atoi(); if ((ival < 1) || (ival > 100)) { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> number of scan points is out of range [1,100]!"; std::cerr << std::endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]"; std::cerr << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } fScanNoPoints = ival; } } if (tokens) { delete tokens; tokens = nullptr; } } else if (line.Contains("EIGEN", TString::kIgnoreCase)) { cmd.first = PMN_EIGEN; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("FIT_RANGE", TString::kIgnoreCase)) { // check the 5 options: // (i) FIT_RANGE RESET, // (ii) FIT_RANGE start end, // (iii) FIT_RANGE start1 end1 start2 end2 ... startN endN // (iv) FIT_RANGE fgb+n0 lgb-n1 // (v) FIT_RANGE fgb+n00 lgb-n01 fgb+n10 lgb-n11 ... fgb+nN0 lgb-nN1 TObjArray *tokens = nullptr; TObjString *ostr; TString str; tokens = line.Tokenize(", \t"); if (tokens->GetEntries() == 2) { // should only be RESET ostr = dynamic_cast(tokens->At(1)); str = ostr->GetString(); if (str.Contains("RESET", TString::kIgnoreCase)) { cmd.first = PMN_FIT_RANGE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> Syntax: FIT_RANGE RESET | FIT_RANGE start end | FIT_RANGE s1 e1 s2 e2 .. sN eN,"; std::cerr << std::endl << ">> with N the number of runs in the msr-file." << std::endl; std::cerr << std::endl << ">> Found " << str.Data() << ", instead of RESET" << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } } else if ((tokens->GetEntries() > 1) && (static_cast(tokens->GetEntries()) % 2) == 1) { if ((tokens->GetEntries() > 3) && ((static_cast(tokens->GetEntries())-1)) != 2*fRunInfo->GetMsrRunList()->size()) { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> Syntax: FIT_RANGE RESET | FIT_RANGE | FIT_RANGE .. |"; std::cerr << std::endl << ">> FIT_RANGE fgb+ lgb- | FIT_RANGE fgb+ lgb- fgb+ lgb- ... fgb+ lgb-,"; std::cerr << std::endl << ">> with N the number of runs in the msr-file."; std::cerr << std::endl << ">> Found N=" << (tokens->GetEntries()-1)/2 << ", # runs in msr-file=" << fRunInfo->GetMsrRunList()->size() << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } else { // check that all range entries are numbers or fgb+n0 / lgb-n1 Bool_t ok = true; for (Int_t n=1; nGetEntries(); n++) { ostr = dynamic_cast(tokens->At(n)); str = ostr->GetString(); if (!str.IsFloat()) { if ((n%2 == 1) && (!str.Contains("fgb", TString::kIgnoreCase))) ok = false; if ((n%2 == 0) && (!str.Contains("lgb", TString::kIgnoreCase))) ok = false; } if (!ok) break; } if (ok) { // everything is fine cmd.first = PMN_FIT_RANGE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> Syntax: FIT_RANGE RESET | FIT_RANGE | FIT_RANGE .. |"; std::cerr << std::endl << ">> FIT_RANGE fgb+ lgb- | FIT_RANGE fgb+ lgb- fgb+ lgb- ... fgb+ lgb-,"; std::cerr << std::endl << ">> with N the number of runs in the msr-file."; std::cerr << std::endl << ">> Found token '" << str.Data() << "', which is not a floating point number." << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } } } else { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> Syntax: FIT_RANGE RESET | FIT_RANGE | FIT_RANGE .. |"; std::cerr << std::endl << ">> FIT_RANGE fgb+ lgb- | FIT_RANGE fgb+ lgb- fgb+ lgb- ... fgb+ lgb-,"; std::cerr << std::endl << ">> with N the number of runs in the msr-file."; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } if (tokens) { delete tokens; tokens = nullptr; } } else if (line.Contains("FIX", TString::kIgnoreCase)) { // check if the given set of parameters (number or names) is present TObjArray *tokens = nullptr; TObjString *ostr; TString str; UInt_t ival; tokens = line.Tokenize(", \t"); for (Int_t i=1; iGetEntries(); i++) { ostr = dynamic_cast(tokens->At(i)); str = ostr->GetString(); if (str.IsDigit()) { // token might be a parameter number ival = str.Atoi(); // check that ival is in the parameter list if (ival > fParams.size()) { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> Parameter " << ival << " is out of the Parameter Range [1," << fParams.size() << "]"; std::cerr << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } } else { // token might be a parameter name // check if token is present as parameter name Bool_t found = false; for (UInt_t j=0; j> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> Parameter '" << str.Data() << "' is NOT present as a parameter name"; std::cerr << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } } } if (tokens) { delete tokens; tokens = nullptr; } // everything looks fine, feed the command list cmd.first = PMN_FIX; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("HESSE", TString::kIgnoreCase)) { fIsScanOnly = false; cmd.first = PMN_HESSE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("MACHINE_PRECISION", TString::kIgnoreCase)) { cmd.first = PMN_MACHINE_PRECISION; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("MIGRAD", TString::kIgnoreCase)) { fIsScanOnly = false; cmd.first = PMN_MIGRAD; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("MINIMIZE", TString::kIgnoreCase)) { fIsScanOnly = false; cmd.first = PMN_MINIMIZE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("MINOS", TString::kIgnoreCase)) { fIsScanOnly = false; cmd.first = PMN_MINOS; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("MNPLOT", TString::kIgnoreCase)) { cmd.first = PMN_PLOT; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("PRINT_LEVEL", TString::kIgnoreCase)) { cmd.first = PMN_PRINT; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("RELEASE", TString::kIgnoreCase)) { // check if the given set of parameters (number or names) is present TObjArray *tokens = nullptr; TObjString *ostr; TString str; UInt_t ival; tokens = line.Tokenize(", \t"); for (Int_t i=1; iGetEntries(); i++) { ostr = dynamic_cast(tokens->At(i)); str = ostr->GetString(); if (str.IsDigit()) { // token might be a parameter number ival = str.Atoi(); // check that ival is in the parameter list if (ival > fParams.size()) { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> Parameter " << ival << " is out of the Parameter Range [1," << fParams.size() << "]"; std::cerr << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } } else { // token might be a parameter name // check if token is present as parameter name Bool_t found = false; for (UInt_t j=0; j> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> Parameter '" << str.Data() << "' is NOT present as a parameter name"; std::cerr << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } } } if (tokens) { delete tokens; tokens = nullptr; } cmd.first = PMN_RELEASE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("RESTORE", TString::kIgnoreCase)) { cmd.first = PMN_RESTORE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("SAVE", TString::kIgnoreCase)) { cmd.first = PMN_SAVE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("SCAN", TString::kIgnoreCase)) { cmd.first = PMN_SCAN; cmd.second = cmdLineNo; fCmdList.push_back(cmd); // filter out possible parameters for scan TObjArray *tokens = nullptr; TObjString *ostr; TString str; UInt_t ival; tokens = line.Tokenize(", \t"); for (Int_t i=0; iGetEntries(); i++) { ostr = dynamic_cast(tokens->At(i)); str = ostr->GetString(); if (i==1) { // get parameter number // check that token is a UInt_t if (!str.IsDigit()) { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> parameter number is not number!"; std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]"; std::cerr << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } ival = str.Atoi(); // check that parameter is within range if ((ival < 1) || (ival > fParams.size())) { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> parameter number is out of range [1," << fParams.size() << "]!"; std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]"; std::cerr << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } // keep parameter fScanParameter[0] = ival-1; // internally parameter number starts at 0 fScanAll = false; } if (i==2) { // get number of points // check that token is a UInt_t if (!str.IsDigit()) { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> number of points is not number!"; std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]"; std::cerr << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } ival = str.Atoi(); if ((ival < 1) || (ival > 100)) { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> number of scan points is out of range [1,100]!"; std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]"; std::cerr << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } fScanNoPoints = ival; } if (i==3) { // get low // check that token is a Double_t if (!str.IsFloat()) { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> low is not a floating point number!"; std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]"; std::cerr << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } fScanLow = str.Atof(); } if (i==4) { // get high // check that token is a Double_t if (!str.IsFloat()) { std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> high is not a floating point number!"; std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]"; std::cerr << std::endl; fIsValid = false; if (tokens) { delete tokens; tokens = nullptr; } break; } fScanHigh = str.Atof(); } } if (tokens) { delete tokens; tokens = nullptr; } } else if (line.Contains("SIMPLEX", TString::kIgnoreCase)) { cmd.first = PMN_SIMPLEX; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("STRATEGY", TString::kIgnoreCase)) { TObjArray *tokens = nullptr; TObjString *ostr; TString str; tokens = line.Tokenize(" \t"); if (tokens->GetEntries() == 2) { ostr = dynamic_cast(tokens->At(1)); str = ostr->GetString(); if (str.CompareTo("0") == 0) { // low fStrategy = 0; } else if (str.CompareTo("1") == 0) { // default fStrategy = 1; } else if (str.CompareTo("2") == 0) { // high fStrategy = 2; } else if (str.CompareTo("LOW") == 0) { // low fStrategy = 0; } else if (str.CompareTo("DEFAULT") == 0) { // default fStrategy = 1; } else if (str.CompareTo("HIGH") == 0) { // high fStrategy = 2; } } if (tokens) { delete tokens; tokens = nullptr; } } else if (line.Contains("USER_COVARIANCE", TString::kIgnoreCase)) { cmd.first = PMN_USER_COVARIANCE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("USER_PARAM_STATE", TString::kIgnoreCase)) { cmd.first = PMN_USER_PARAM_STATE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (line.Contains("SECTOR", TString::kIgnoreCase)) { fSectorFlag = true; cmd.first = PMN_SECTOR; cmd.second = cmdLineNo; fCmdList.push_back(cmd); // check if the given sector arguments are valid time stamps, i.e. doubles and value < lgb time stamp TObjArray *tokens = nullptr; TObjString *ostr; TString str; tokens = line.Tokenize(" ,\t"); if (tokens->GetEntries() == 1) { // no sector time stamps given -> issue an error std::cerr << std::endl << ">> PFitter::CheckCommands(): **FATAL ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> At least one sector time stamp is expected."; std::cerr << std::endl << ">> Will stop ..."; std::cerr << std::endl; // cleanup if (tokens) { delete tokens; tokens = nullptr; } fIsValid = false; fSectorFlag = false; break; } Double_t dval; for (Int_t i=1; iGetEntries(); i++) { // keep time range of sector PSectorChisq sec(fRunInfo->GetNoOfRuns()); // get parse tokens ostr = dynamic_cast(tokens->At(i)); str = ostr->GetString(); if (str.IsFloat()) { dval = str.Atof(); // check that the sector time stamp is smaller than all lgb time stamps for (UInt_t j=0; j fOriginalFitRange[j].second) { std::cerr << std::endl << ">> PFitter::CheckCommands(): **FATAL ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> The sector time stamp " << dval << " is > as the lgb time stamp (" << fOriginalFitRange[j].second << ") of run " << j << "."; std::cerr << std::endl << ">> Will stop ..."; std::cerr << std::endl; // cleanup if (tokens) { delete tokens; tokens = nullptr; } fIsValid = false; fSectorFlag = false; return fIsValid; } sec.SetRunFirstTime(fOriginalFitRange[j].first, j); // keep fgb time stamp for sector } sec.SetSectorTime(dval); fSector.push_back(sec); } else { // sector element is NOT a float std::cerr << std::endl << ">> PFitter::CheckCommands(): **FATAL ERROR** in line " << it->fLineNo; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> The sector time stamp '" << str << "' is not a number."; std::cerr << std::endl << ">> Will stop ..."; std::cerr << std::endl; // cleanup if (tokens) { delete tokens; tokens = nullptr; } fIsValid = false; fSectorFlag = false; break; } } if (tokens) { delete tokens; tokens = nullptr; } } else { // unkown command std::cerr << std::endl << ">> PFitter::CheckCommands(): **FATAL ERROR** in line " << it->fLineNo << " an unkown command is found:"; std::cerr << std::endl << ">> " << line.Data(); std::cerr << std::endl << ">> Will stop ..."; std::cerr << std::endl; fIsValid = false; break; } } // Check that in case release/restore is present, that it is followed by a minimizer before minos is called. // If this is not the case, place a warning Bool_t fixFlag = false; Bool_t releaseFlag = false; Bool_t minimizerFlag = false; for (it = fCmdLines.begin(); it != fCmdLines.end(); ++it) { if (line.Contains("FIX", TString::kIgnoreCase)) fixFlag = true; else if (line.Contains("RELEASE", TString::kIgnoreCase) || line.Contains("RESTORE", TString::kIgnoreCase)) releaseFlag = true; else if (line.Contains("MINIMIZE", TString::kIgnoreCase) || line.Contains("MIGRAD", TString::kIgnoreCase) || line.Contains("SIMPLEX", TString::kIgnoreCase)) { if (releaseFlag) minimizerFlag = true; } else if (line.Contains("MINOS", TString::kIgnoreCase)) { if (fixFlag && releaseFlag && !minimizerFlag) { std::cerr << std::endl << ">> PFitter::CheckCommands(): **WARNING** RELEASE/RESTORE command present"; std::cerr << std::endl << ">> without minimizer command (MINIMIZE/MIGRAD/SIMPLEX) between"; std::cerr << std::endl << ">> RELEASE/RESTORE and MINOS. Behaviour might be different to the"; std::cerr << std::endl << ">> expectation of the user ?!?" << std::endl; } fixFlag = false; releaseFlag = false; minimizerFlag = false; } } return fIsValid; } //-------------------------------------------------------------------------- // SetParameters //-------------------------------------------------------------------------- /** *

Feeds the internal minuit2 fit parameters. It also makes sure that unused parameters * are fixed. * * return: true. */ Bool_t PFitter::SetParameters() { for (UInt_t i=0; i 5) { // boundaries given if (fParams[i].fLowerBoundaryPresent && fParams[i].fUpperBoundaryPresent) { // upper and lower boundaries given fMnUserParams.Add(fParams[i].fName.Data(), fParams[i].fValue, fParams[i].fStep, fParams[i].fLowerBoundary, fParams[i].fUpperBoundary); } else if (fParams[i].fLowerBoundaryPresent && !fParams[i].fUpperBoundaryPresent) { // lower boundary limited fMnUserParams.Add(fParams[i].fName.Data(), fParams[i].fValue, fParams[i].fStep); fMnUserParams.SetLowerLimit(fParams[i].fName.Data(), fParams[i].fLowerBoundary); } else { // upper boundary limited fMnUserParams.Add(fParams[i].fName.Data(), fParams[i].fValue, fParams[i].fStep); fMnUserParams.SetUpperLimit(fParams[i].fName.Data(), fParams[i].fUpperBoundary); } } else { // no boundaries given fMnUserParams.Add(fParams[i].fName.Data(), fParams[i].fValue, fParams[i].fStep); } } } // check if there is an unused parameter, if so, fix it for (UInt_t i=0; iParameterInUse(i) == 0) && (fParams[i].fStep != 0.0)) { fMnUserParams.Fix(i); // fix the unused parameter so that minuit will not vary it std::cerr << std::endl << "**WARNING** : Parameter No " << i+1 << " is not used at all, will fix it"; std::cerr << std::endl; } } return true; } //-------------------------------------------------------------------------- // ExecuteContours //-------------------------------------------------------------------------- /** *

Execute the minuit2 contour command. Makes sure that a valid minuit2 minimum is present. * * return: true if the contour command could be executed successfully, otherwise returns false. */ Bool_t PFitter::ExecuteContours() { std::cout << ">> PFitter::ExecuteContours() ..." << std::endl; // if already some minimization is done use the minuit2 output as input if (!fFcnMin) { std::cerr << std::endl << "**WARNING**: CONTOURS musn't be called before any minimization (MINIMIZE/MIGRAD/SIMPLEX) is done!!"; std::cerr << std::endl; return false; } // check if minimum was valid if (!fFcnMin->IsValid()) { std::cerr << std::endl << "**ERROR**: CONTOURS cannot started since the previous minimization failed :-("; std::cerr << std::endl; return false; } ROOT::Minuit2::FCNBase *fcn = 0; if (fDKSReady) fcn = fFitterFcnDKS; else fcn = fFitterFcn; ROOT::Minuit2::MnContours contours((*fcn), *fFcnMin); fScanData = contours(fScanParameter[0], fScanParameter[1], fScanNoPoints); return true; } //-------------------------------------------------------------------------- // ExecuteFitRange //-------------------------------------------------------------------------- /** *

Change the fit range via command block. * * \param lineNo the line number of the command block * * return: true if done, otherwise returns false. */ Bool_t PFitter::ExecuteFitRange(UInt_t lineNo) { std::cout << ">> PFitter::ExecuteFitRange(): " << fCmdLines[lineNo].fLine.Data() << std::endl; if (fCmdLines[lineNo].fLine.Contains("fgb", TString::kIgnoreCase)) { // fit range given in bins fRunListCollection->SetFitRange(fCmdLines[lineNo].fLine); return true; } TObjArray *tokens = nullptr; TObjString *ostr; TString str; tokens = fCmdLines[lineNo].fLine.Tokenize(", \t"); PMsrRunList *runList = fRunInfo->GetMsrRunList(); // execute command, no error checking needed since this has been already carried out in CheckCommands() if (tokens->GetEntries() == 2) { // reset command fRunListCollection->SetFitRange(fOriginalFitRange); } else if (tokens->GetEntries() == 3) { // single fit range for all runs Double_t start = 0.0, end = 0.0; PDoublePair fitRange; PDoublePairVector fitRangeVector; ostr = dynamic_cast(tokens->At(1)); str = ostr->GetString(); start = str.Atof(); ostr = dynamic_cast(tokens->At(2)); str = ostr->GetString(); end = str.Atof(); fitRange.first = start; fitRange.second = end; fitRangeVector.push_back(fitRange); fRunListCollection->SetFitRange(fitRangeVector); } else { // individual fit ranges for each run Double_t start = 0.0, end = 0.0; PDoublePair fitRange; PDoublePairVector fitRangeVector; for (UInt_t i=0; isize(); i++) { ostr = dynamic_cast(tokens->At(2*i+1)); str = ostr->GetString(); start = str.Atof(); ostr = dynamic_cast(tokens->At(2*i+2)); str = ostr->GetString(); end = str.Atof(); fitRange.first = start; fitRange.second = end; fitRangeVector.push_back(fitRange); } fRunListCollection->SetFitRange(fitRangeVector); } return true; } //-------------------------------------------------------------------------- // ExecuteFix //-------------------------------------------------------------------------- /** *

Fix parameter list given at lineNo of the command block. * * \param lineNo the line number of the command block * * return: true if done, otherwise returns false. */ Bool_t PFitter::ExecuteFix(UInt_t lineNo) { std::cout << ">> PFitter::ExecuteFix(): " << fCmdLines[lineNo].fLine.Data() << std::endl; TObjArray *tokens = nullptr; TObjString *ostr; TString str; tokens = fCmdLines[lineNo].fLine.Tokenize(", \t"); for (Int_t i=1; iGetEntries(); i++) { ostr = dynamic_cast(tokens->At(i)); str = ostr->GetString(); if (str.IsDigit()) { // token is a parameter number fMnUserParams.Fix(static_cast(str.Atoi())-1); } else { // token is a parameter name fMnUserParams.Fix(str.Data()); } } // clean up if (tokens) { delete tokens; tokens = nullptr; } return true; } //-------------------------------------------------------------------------- // ExecuteHesse //-------------------------------------------------------------------------- /** *

Execute the minuit2 hesse command. * * return: true if the hesse command could be executed successfully, otherwise returns false. */ Bool_t PFitter::ExecuteHesse() { std::cout << ">> PFitter::ExecuteHesse(): will call hesse ..." << std::endl; // create the hesse object ROOT::Minuit2::MnHesse hesse; // specify maximal number of function calls UInt_t maxfcn = std::numeric_limits::max(); // call hesse Double_t start=0.0, end=0.0; ROOT::Minuit2::FCNBase *fcn = 0; if (fDKSReady) fcn = fFitterFcnDKS; else fcn = fFitterFcn; start=MilliTime(); ROOT::Minuit2::MnUserParameterState mnState = hesse((*fcn), fMnUserParams, maxfcn); end=MilliTime(); std::cout << ">> PFitter::ExecuteMinimize(): execution time for Hesse = " << std::setprecision(3) << (end-start)/1.0e3 << " sec." << std::endl; TString str = TString::Format("Hesse: %.3f sec", (end-start)/1.0e3); fElapsedTime.push_back(str); if (!mnState.IsValid()) { std::cerr << std::endl << ">> PFitter::ExecuteHesse(): **WARNING** Hesse encountered a problem! The state found is invalid."; std::cerr << std::endl; return false; } if (!mnState.HasCovariance()) { std::cerr << std::endl << ">> PFitter::ExecuteHesse(): **WARNING** Hesse encountered a problem! No covariance matrix available."; std::cerr << std::endl; return false; } // fill parabolic errors for (UInt_t i=0; iSetMsrParamStep(i, mnState.Error(i)); fRunInfo->SetMsrParamPosErrorPresent(i, false); } if (fPrintLevel >= 2) std::cout << mnState << std::endl; return true; } //-------------------------------------------------------------------------- // ExecuteMigrad //-------------------------------------------------------------------------- /** *

Execute the minuit2 migrad command. * * return: true if the migrad command could be executed successfully, otherwise returns false. */ Bool_t PFitter::ExecuteMigrad() { std::cout << ">> PFitter::ExecuteMigrad(): will call migrad ..." << std::endl; // create migrad object // strategy is by default = 'default' ROOT::Minuit2::FCNBase *fcn = 0; if (fDKSReady) fcn = fFitterFcnDKS; else fcn = fFitterFcn; ROOT::Minuit2::MnMigrad migrad((*fcn), fMnUserParams, fStrategy); // minimize // maxfcn is MINUIT2 Default maxfcn UInt_t maxfcn = std::numeric_limits::max(); // tolerance = MINUIT2 Default tolerance Double_t tolerance = 0.1; // keep track of elapsed time Double_t start=0.0, end=0.0; start=MilliTime(); ROOT::Minuit2::FunctionMinimum min = migrad(maxfcn, tolerance); end=MilliTime(); std::cout << ">> PFitter::ExecuteMinimize(): execution time for Migrad = " << std::setprecision(3) << (end-start)/1.0e3 << " sec." << std::endl; TString str = TString::Format("Migrad: %.3f sec", (end-start)/1.0e3); fElapsedTime.push_back(str); if (!min.IsValid()) { std::cerr << std::endl << ">> PFitter::ExecuteMigrad(): **WARNING**: Fit did not converge, sorry ..."; std::cerr << std::endl; fIsValid = false; return false; } // keep FunctionMinimum object if (fFcnMin) { // fFcnMin exist hence clean up first delete fFcnMin; fFcnMin = nullptr; } fFcnMin = new ROOT::Minuit2::FunctionMinimum(min); // keep user parameters if (fFcnMin) fMnUserParams = fFcnMin->UserParameters(); // fill run info for (UInt_t i=0; iSetMsrParamValue(i, dval); fRunInfo->SetMsrParamStep(i, min.UserState().Error(i)); fRunInfo->SetMsrParamPosErrorPresent(i, false); } // handle statistics Double_t minVal = min.Fval(); UInt_t ndf = 0.0; if (fDKSReady) ndf = fFitterFcnDKS->GetTotalNoOfFittedBins(); else ndf = fFitterFcn->GetTotalNoOfFittedBins(); // subtract number of varied parameters from total no of fitted bins -> ndf for (UInt_t i=0; iSetMsrStatisticMin(minVal); fRunInfo->SetMsrStatisticNdf(ndf); fConverged = true; if (fPrintLevel >= 2) std::cout << *fFcnMin << std::endl; return true; } //-------------------------------------------------------------------------- // ExecuteMinimize //-------------------------------------------------------------------------- /** *

Execute the minuit2 minimize command. * * return: true if the minimize command could be executed successfully, otherwise returns false. */ Bool_t PFitter::ExecuteMinimize() { std::cout << ">> PFitter::ExecuteMinimize(): will call minimize ..." << std::endl; // create minimizer object // strategy is by default = 'default' ROOT::Minuit2::FCNBase *fcn = 0; if (fDKSReady) fcn = fFitterFcnDKS; else fcn = fFitterFcn; ROOT::Minuit2::MnMinimize minimize((*fcn), fMnUserParams, fStrategy); // minimize // maxfcn is MINUIT2 Default maxfcn UInt_t maxfcn = std::numeric_limits::max(); // tolerance = MINUIT2 Default tolerance Double_t tolerance = 0.1; // keep track of elapsed time Double_t start=0.0, end=0.0; start = MilliTime(); ROOT::Minuit2::FunctionMinimum min = minimize(maxfcn, tolerance); end = MilliTime(); std::cout << ">> PFitter::ExecuteMinimize(): execution time for Minimize = " << std::setprecision(3) << (end-start)/1.0e3 << " sec." << std::endl; TString str = TString::Format("Minimize: %.3f sec", (end-start)/1.0e3); fElapsedTime.push_back(str); if (!min.IsValid()) { std::cerr << std::endl << ">> PFitter::ExecuteMinimize(): **WARNING**: Fit did not converge, sorry ..."; std::cerr << std::endl; fIsValid = false; return false; } // keep FunctionMinimum object if (fFcnMin) { // fFcnMin exist hence clean up first delete fFcnMin; fFcnMin = nullptr; } fFcnMin = new ROOT::Minuit2::FunctionMinimum(min); // keep user parameters if (fFcnMin) fMnUserParams = fFcnMin->UserParameters(); // fill run info for (UInt_t i=0; iSetMsrParamValue(i, dval); fRunInfo->SetMsrParamStep(i, min.UserState().Error(i)); fRunInfo->SetMsrParamPosErrorPresent(i, false); } // handle statistics Double_t minVal = min.Fval(); UInt_t ndf = 0.0; if (fDKSReady) ndf = fFitterFcnDKS->GetTotalNoOfFittedBins(); else ndf = fFitterFcn->GetTotalNoOfFittedBins(); // subtract number of varied parameters from total no of fitted bins -> ndf for (UInt_t i=0; iSetMsrStatisticMin(minVal); fRunInfo->SetMsrStatisticNdf(ndf); fConverged = true; if (fPrintLevel >= 2) std::cout << *fFcnMin << std::endl; return true; } //-------------------------------------------------------------------------- // ExecuteMinos //-------------------------------------------------------------------------- /** *

Execute the minuit2 minos command. * * return: true if the minos command could be executed successfully, otherwise returns false. */ Bool_t PFitter::ExecuteMinos() { std::cout << ">> PFitter::ExecuteMinos(): will call minos ..." << std::endl; // if already some minimization is done use the minuit2 output as input if (!fFcnMin) { std::cerr << std::endl << "**ERROR**: MINOS musn't be called before any minimization (MINIMIZE/MIGRAD/SIMPLEX) is done!!"; std::cerr << std::endl; return false; } // check if minimum was valid if (!fFcnMin->IsValid()) { std::cerr << std::endl << "**ERROR**: MINOS cannot started since the previous minimization failed :-("; std::cerr << std::endl; return false; } // make minos analysis Double_t start=0.0, end=0.0; ROOT::Minuit2::FCNBase *fcn = 0; if (fDKSReady) fcn = fFitterFcnDKS; else fcn = fFitterFcn; start=MilliTime(); ROOT::Minuit2::MnMinos minos((*fcn), (*fFcnMin)); for (UInt_t i=0; iParameterInUse(i) != 0) && (!fMnUserParams.Parameters().at(i).IsFixed())) { std::cout << ">> PFitter::ExecuteMinos(): calculate errors for " << fParams[i].fName << std::endl; // 1-sigma MINOS errors ROOT::Minuit2::MinosError err = minos.Minos(i); if (err.IsValid()) { // fill msr-file structure fRunInfo->SetMsrParamStep(i, err.Lower()); fRunInfo->SetMsrParamPosError(i, err.Upper()); fRunInfo->SetMsrParamPosErrorPresent(i, true); } else { fRunInfo->SetMsrParamPosErrorPresent(i, false); } } if (fMnUserParams.Parameters().at(i).IsFixed()) { std::cerr << std::endl << ">> PFitter::ExecuteMinos(): **WARNING** Parameter " << fMnUserParams.Name(i) << " (ParamNo " << i+1 << ") is fixed!"; std::cerr << std::endl << ">> Will set STEP to zero, i.e. making it a constant parameter"; std::cerr << std::endl; fRunInfo->SetMsrParamStep(i, 0.0); fRunInfo->SetMsrParamPosErrorPresent(i, false); } } end=MilliTime(); std::cout << ">> PFitter::ExecuteMinimize(): execution time for Minos = " << std::setprecision(3) << (end-start)/1.0e3 << " sec." << std::endl; TString str = TString::Format("Minos: %.3f sec", (end-start)/1.0e3); fElapsedTime.push_back(str); return true; } //-------------------------------------------------------------------------- // ExecutePlot //-------------------------------------------------------------------------- /** *

Execute the minuit2 plot command. * * return: true. */ Bool_t PFitter::ExecutePlot() { std::cout << ">> PFitter::ExecutePlot() ..." << std::endl; ROOT::Minuit2::MnPlot plot; plot(fScanData); return true; } //-------------------------------------------------------------------------- // ExecutePrintLevel //-------------------------------------------------------------------------- /** *

Set the print level. * * \param lineNo the line number of the command block * * return: true if done, otherwise returns false. */ Bool_t PFitter::ExecutePrintLevel(UInt_t lineNo) { std::cout << ">> PFitter::ExecutePrintLevel(): " << fCmdLines[lineNo].fLine.Data() << std::endl; TObjArray *tokens = nullptr; TObjString *ostr; TString str; tokens = fCmdLines[lineNo].fLine.Tokenize(", \t"); if (tokens->GetEntries() < 2) { std::cerr << std::endl << "**ERROR** from PFitter::ExecutePrintLevel(): SYNTAX: PRINT_LEVEL , where =0-3" << std::endl << std::endl; return false; } ostr = (TObjString*)tokens->At(1); str = ostr->GetString(); Int_t ival; if (str.IsDigit()) { ival = str.Atoi(); if ((ival >=0) && (ival <= 3)) { fPrintLevel = (UInt_t) ival; } else { std::cerr << std::endl << "**ERROR** from PFitter::ExecutePrintLevel(): SYNTAX: PRINT_LEVEL , where =0-3"; std::cerr << std::endl << " found =" << ival << std::endl << std::endl; return false; } } else { std::cerr << std::endl << "**ERROR** from PFitter::ExecutePrintLevel(): SYNTAX: PRINT_LEVEL , where =0-3" << std::endl << std::endl; return false; } #ifdef ROOT_GRTEQ_24 ROOT::Minuit2::MnPrint::SetGlobalLevel(fPrintLevel); #else ROOT::Minuit2::MnPrint::SetLevel(fPrintLevel); #endif // clean up if (tokens) { delete tokens; tokens = nullptr; } return true; } //-------------------------------------------------------------------------- // ExecuteRelease //-------------------------------------------------------------------------- /** *

Release parameter list given at lineNo of the command block. * * \param lineNo the line number of the command block * * return: true if done, otherwise returns false. */ Bool_t PFitter::ExecuteRelease(UInt_t lineNo) { TObjArray *tokens = nullptr; TObjString *ostr; TString str; tokens = fCmdLines[lineNo].fLine.Tokenize(", \t"); std::cout << ">> PFitter::ExecuteRelease(): " << fCmdLines[lineNo].fLine.Data() << std::endl; for (Int_t i=1; iGetEntries(); i++) { ostr = dynamic_cast(tokens->At(i)); str = ostr->GetString(); if (str.IsDigit()) { // token is a parameter number fMnUserParams.Release(static_cast(str.Atoi())-1); // set the error to 2% of the value when releasing fMnUserParams.SetError(static_cast(str.Atoi())-1, 0.02*fMnUserParams.Value(static_cast(str.Atoi())-1)); } else { // token is a parameter name fMnUserParams.Release(str.Data()); // set the error to 2% of the value when releasing fMnUserParams.SetError(str.Data(), 0.02*fMnUserParams.Value(str.Data())); } } // clean up if (tokens) { delete tokens; tokens = nullptr; } return true; } //-------------------------------------------------------------------------- // ExecuteRestore //-------------------------------------------------------------------------- /** *

Release all fixed parameters * * return: true. */ Bool_t PFitter::ExecuteRestore() { std::cout << "PFitter::ExecuteRestore(): release all fixed parameters (RESTORE) ..." << std::endl; for (UInt_t i=0; iExecute the minuit2 scan command. * * return: true. */ Bool_t PFitter::ExecuteScan() { std::cout << ">> PFitter::ExecuteScan(): will call scan ..." << std::endl; ROOT::Minuit2::FCNBase *fcn = 0; if (fDKSReady) fcn = fFitterFcnDKS; else fcn = fFitterFcn; ROOT::Minuit2::MnScan scan((*fcn), fMnUserParams); if (fScanAll) { // not clear at the moment what to be done here // TO BE IMPLEMENTED } else { // single parameter scan fScanData = scan.Scan(fScanParameter[0], fScanNoPoints, fScanLow, fScanHigh); } fConverged = true; return true; } //-------------------------------------------------------------------------- // ExecuteSave //-------------------------------------------------------------------------- /** *

Execute the save command. * * \param firstSave flag indication if this is the first save call and hence write a fresh MINUIT2.OUTPUT * * return: true if the valid minuit2 state is found, otherwise returns false. */ Bool_t PFitter::ExecuteSave(Bool_t firstSave) { // if any minimization was done, otherwise get out immediately if (!fFcnMin) { std::cout << std::endl << ">> PFitter::ExecuteSave(): nothing to be saved ..."; return false; } ROOT::Minuit2::MnUserParameterState mnState = fFcnMin->UserState(); // check if the user parameter state is valid if (!mnState.IsValid()) { std::cerr << std::endl << ">> PFitter::ExecuteSave: **WARNING** Minuit2 User Parameter State is not valid, i.e. nothing to be saved"; std::cerr << std::endl; return false; } // handle expected chisq if applicable fParams = *(fRunInfo->GetMsrParamList()); // get the update parameters back // calculate expected chisq std::vector param; Double_t totalExpectedChisq = 0.0; std::vector expectedchisqPerRun; std::vector ndfPerHisto; for (UInt_t i=0; iCalcExpectedChiSquare(param, totalExpectedChisq, expectedchisqPerRun); else fFitterFcn->CalcExpectedChiSquare(param, totalExpectedChisq, expectedchisqPerRun); // calculate chisq per run std::vector chisqPerRun; for (UInt_t i=0; iGetMsrRunList()->size(); i++) { if (fUseChi2) chisqPerRun.push_back(fRunListCollection->GetSingleRunChisq(param, i)); else chisqPerRun.push_back(fRunListCollection->GetSingleRunMaximumLikelihood(param, i)); } if (totalExpectedChisq != 0.0) { // i.e. applicable for single histogram fits only // get the ndf's of the histos UInt_t ndf_run; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); else ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); ndfPerHisto.push_back(ndf_run); } // feed the msr-file handler PMsrStatisticStructure *statistics = fRunInfo->GetMsrStatistic(); if (statistics) { statistics->fMinPerHisto = chisqPerRun; statistics->fMinExpected = totalExpectedChisq; statistics->fMinExpectedPerHisto = expectedchisqPerRun; statistics->fNdfPerHisto = ndfPerHisto; } } else if (chisqPerRun.size() > 1) { // in case expected chisq is not applicable like for asymmetry fits UInt_t ndf_run = 0; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); else ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); ndfPerHisto.push_back(ndf_run); } } // check if sector command has been requested if (fSectorFlag) { PDoubleVector error; for (UInt_t i=0; i> PFitter::ExecuteSave(): will write minuit2 output file ..." << std::endl; std::ofstream fout; // open minuit2 output file if (firstSave) fout.open("MINUIT2.OUTPUT", std::iostream::out); else fout.open("MINUIT2.OUTPUT", std::iostream::out | std::iostream::app); if (!fout.is_open()) { std::cerr << std::endl << "**ERROR** PFitter::ExecuteSave() couldn't open MINUIT2.OUTPUT file"; std::cerr << std::endl; return false; } // write header TDatime dt; fout << std::endl << "*************************************************************************"; fout << std::endl << " musrfit MINUIT2 output file from " << fRunInfo->GetFileName().Data() << " - " << dt.AsSQLString(); fout << std::endl << "*************************************************************************"; fout << std::endl; // write CPU/GPU info std::string hwInfo("??"); int status=0; switch (fDKSTag) { case DKS_CPU_OPENMP: fout << std::endl << " CPU info : " << GetCPUInfo(); #ifdef HAVE_GOMP fout << std::endl << " OpenMP" << std::endl; #else fout << std::endl << " CPU, i.e. single threaded" << std::endl; #endif break; case DKS_CPU_OPENCL: if (fFitterFcnDKS) status = fFitterFcnDKS->GetDeviceName(hwInfo); fout << std::endl << " CPU info : " << hwInfo; fout << std::endl << " OpenCL" << std::endl; break; case DKS_GPU_CUDA: if (fFitterFcnDKS) status = fFitterFcnDKS->GetDeviceName(hwInfo); fout << std::endl << " GPU info : " << hwInfo; fout << std::endl << " Cuda" << std::endl; break; case DKS_GPU_OPENCL: if (fFitterFcnDKS) status = fFitterFcnDKS->GetDeviceName(hwInfo); fout << std::endl << " GPU info : " << hwInfo; fout << std::endl << " OpenCL" << std::endl; break; default: fout << std::endl << " CPU/GPU info : unkown" << std::endl; break; } fout << std::endl << "*************************************************************************"; fout << std::endl; // write elapsed times fout << std::endl << " elapsed times:"; for (UInt_t i=0; i maxLength) maxLength = fParams[i].fName.Length() + 1; } // write parameters fParams = *(fRunInfo->GetMsrParamList()); // get the update parameters back fout << std::endl << " PARAMETERS"; fout << std::endl << "-------------------------------------------------------------------------"; fout << std::endl << " "; for (Int_t j=0; j<=maxLength-4; j++) fout << " "; fout << "Parabolic Minos"; fout << std::endl << " No Name"; for (Int_t j=0; j<=maxLength-4; j++) fout << " "; fout << "Value Error Negative Positive Limits"; for (UInt_t i=0; i 5) { fout.setf(std::ios::left, std::ios::adjustfield); fout.width(7); if (fParams[i].fLowerBoundaryPresent) fout << fParams[i].fLowerBoundary; else fout << "---"; fout.setf(std::ios::left, std::ios::adjustfield); fout.width(7); if (fParams[i].fUpperBoundaryPresent) fout << fParams[i].fUpperBoundary; else fout << "---"; } else { fout.setf(std::ios::left, std::ios::adjustfield); fout.width(7); fout << "---"; fout.setf(std::ios::left, std::ios::adjustfield); fout.width(7); fout << "---"; } } fout << std::endl; fout << std::endl << "*************************************************************************"; // write covariance matrix fout << std::endl << " COVARIANCE MATRIX"; fout << std::endl << "-------------------------------------------------------------------------"; if (mnState.HasCovariance()) { ROOT::Minuit2::MnUserCovariance cov = mnState.Covariance(); fout << std::endl << "from " << cov.Nrow() << " free parameters"; for (UInt_t i=0; i 0.0) { fout << " "; fout.width(13); } else { fout.width(14); } fout << cov(i,j); } } } else { fout << std::endl << " no covariance matrix available"; } fout << std::endl; fout << std::endl << "*************************************************************************"; // write correlation matrix fout << std::endl << " CORRELATION COEFFICIENTS"; fout << std::endl << "-------------------------------------------------------------------------"; if (mnState.HasGlobalCC() && mnState.HasCovariance()) { ROOT::Minuit2::MnGlobalCorrelationCoeff corr = mnState.GlobalCC(); ROOT::Minuit2::MnUserCovariance cov = mnState.Covariance(); PIntVector parNo; fout << std::endl << " No Global "; for (UInt_t i=0; iParameterInUse(i) > 0) && (!fMnUserParams.Parameters().at(i).IsFixed())) { fout.setf(std::ios::left, std::ios::adjustfield); fout.width(9); fout << i+1; parNo.push_back(i); } } // check that there is a correspondens between minuit2 and musrfit book keeping if (parNo.size() != cov.Nrow()) { std::cerr << std::endl << "**SEVERE ERROR** in PFitter::ExecuteSave(): minuit2 and musrfit book keeping to not correspond! Unable to write correlation matrix."; std::cerr << std::endl; } else { // book keeping is OK TString title("Minuit2 Output Correlation Matrix for "); title += fRunInfo->GetFileName(); title += " - "; title += dt.AsSQLString(); TCanvas *ccorr = new TCanvas("ccorr", "title", 500, 500); TH2D *hcorr = new TH2D("hcorr", title, cov.Nrow(), 0.0, cov.Nrow(), cov.Nrow(), 0.0, cov.Nrow()); Double_t dval; for (UInt_t i=0; iFill((Double_t)i,(Double_t)i,1.0); } else { // check that errors are none zero if (fMnUserParams.Error(parNo[i]) == 0.0) { std::cerr << std::endl << "**SEVERE ERROR** in PFitter::ExecuteSave(): parameter no " << parNo[i]+1 << " has an error == 0. Cannot correctly handle the correlation matrix."; std::cerr << std::endl; dval = 0.0; } else if (fMnUserParams.Error(parNo[j]) == 0.0) { std::cerr << std::endl << "**SEVERE ERROR** in PFitter::ExecuteSave(): parameter no " << parNo[j]+1 << " has an error == 0. Cannot correctly handle the correlation matrix."; std::cerr << std::endl; dval = 0.0; } else { dval = cov(i,j)/(fMnUserParams.Error(parNo[i])*fMnUserParams.Error(parNo[j])); } hcorr->Fill((Double_t)i,(Double_t)j,dval); // handle precision, ugly but ... if (dval < 1.0e-2) { fout.precision(2); } else { fout.precision(4); } // handle sign if (dval > 0.0) { fout << " "; fout.width(7); } else { fout.width(8); } fout << dval << " "; } } } // write correlation matrix into a root file TFile ff("MINUIT2.root", "recreate"); ccorr->Draw(); if (cov.Nrow() <= 6) hcorr->Draw("COLZTEXT"); else hcorr->Draw("COLZ"); ccorr->Write("ccorr", TObject::kOverwrite, sizeof(ccorr)); hcorr->Write("hcorr", TObject::kOverwrite, sizeof(hcorr)); ff.Close(); // clean up if (ccorr) { delete ccorr; ccorr = nullptr; } if (hcorr) { delete hcorr; hcorr = nullptr; } } parNo.clear(); // clean up } else { fout << std::endl << " no correlation coefficients available"; } fout << std::endl; fout << std::endl << "*************************************************************************"; fout << std::endl << " chisq/maxLH RESULT "; fout << std::endl << "*************************************************************************"; PMsrStatisticStructure *statistics = fRunInfo->GetMsrStatistic(); // get time range and write it Double_t fitStartTime = PMUSR_UNDEFINED, fitEndTime = PMUSR_UNDEFINED; // first check if there is a global block with a valid time range PMsrGlobalBlock *global = fRunInfo->GetMsrGlobal(); fitStartTime = global->GetFitRange(0); fitEndTime = global->GetFitRange(1); if (fitStartTime == PMUSR_UNDEFINED) { // no global time range, hence take the one from the first run block PMsrRunList *run = fRunInfo->GetMsrRunList(); fitStartTime = run->at(0).GetFitRange(0); fitEndTime = run->at(0).GetFitRange(1); } fout.setf(std::ios::floatfield); fout << std::endl << " Time Range: " << fitStartTime << ", " << fitEndTime << std::endl; if (fUseChi2) { fout.setf(std::ios::fixed, std::ios::floatfield); fout << std::endl << " chisq = " << std::setprecision(4) << statistics->fMin << ", NDF = " << statistics->fNdf << ", chisq/NDF = " << std::setprecision(6) << statistics->fMin/statistics->fNdf; if (statistics->fMinExpected > 0) fout << std::endl << " chisq_e = " << std::setprecision(4) << statistics->fMinExpected << ", NDF = " << statistics->fNdf << ", chisq_e/NDF = " << std::setprecision(6) << statistics->fMinExpected/statistics->fNdf; } else { // maxLH fout.setf(std::ios::fixed, std::ios::floatfield); fout << std::endl << " maxLH = " << std::setprecision(4) << statistics->fMin << ", NDF = " << statistics->fNdf << ", maxLH/NDF = " << std::setprecision(6) << statistics->fMin/statistics->fNdf; if (statistics->fMinExpected > 0) fout << std::endl << " maxLH_e = " << std::setprecision(4) << statistics->fMinExpected << ", NDF = " << statistics->fNdf << ", maxLH_e/NDF = " << std::setprecision(6) << statistics->fMinExpected/statistics->fNdf; } if (fSectorFlag) ExecuteSector(fout); fout << std::endl; fout << std::endl << "*************************************************************************"; fout << std::endl << " DONE "; fout << std::endl << "*************************************************************************"; fout << std::endl << std::endl; // close MINUIT2.OUTPUT file fout.close(); return true; } //-------------------------------------------------------------------------- // ExecuteSimplex //-------------------------------------------------------------------------- /** *

Execute the minuit2 simplex command. * * return: true if the simplex command could be executed successfully, otherwise returns false. */ Bool_t PFitter::ExecuteSimplex() { std::cout << ">> PFitter::ExecuteSimplex(): will call simplex ..." << std::endl; // create minimizer object // strategy is by default = 'default' ROOT::Minuit2::FCNBase *fcn = 0; if (fDKSReady) fcn = fFitterFcnDKS; else fcn = fFitterFcn; ROOT::Minuit2::MnSimplex simplex((*fcn), fMnUserParams, fStrategy); // minimize // maxfcn is 10*MINUIT2 Default maxfcn UInt_t maxfcn = std::numeric_limits::max(); // tolerance = MINUIT2 Default tolerance Double_t tolerance = 0.1; // keep track of elapsed time Double_t start=0.0, end=0.0; start=MilliTime(); ROOT::Minuit2::FunctionMinimum min = simplex(maxfcn, tolerance); end=MilliTime(); std::cout << ">> PFitter::ExecuteMinimize(): execution time for Simplex = " << std::setprecision(3) << (end-start)/1.0e3 << " sec." << std::endl; TString str = TString::Format("Simplex: %.3f sec", (end-start)/1.0e3); fElapsedTime.push_back(str); if (!min.IsValid()) { std::cerr << std::endl << ">> PFitter::ExecuteSimplex(): **WARNING**: Fit did not converge, sorry ..."; std::cerr << std::endl; fIsValid = false; return false; } // keep FunctionMinimum object if (fFcnMin) { // fFcnMin exist hence clean up first delete fFcnMin; fFcnMin = nullptr; } fFcnMin = new ROOT::Minuit2::FunctionMinimum(min); // keep user parameters if (fFcnMin) fMnUserParams = fFcnMin->UserParameters(); // fill run info for (UInt_t i=0; iSetMsrParamValue(i, dval); fRunInfo->SetMsrParamStep(i, min.UserState().Error(i)); fRunInfo->SetMsrParamPosErrorPresent(i, false); } // handle statistics Double_t minVal = min.Fval(); UInt_t ndf = 0.0; if (fDKSReady) fFitterFcnDKS->GetTotalNoOfFittedBins(); else fFitterFcn->GetTotalNoOfFittedBins(); // subtract number of varied parameters from total no of fitted bins -> ndf for (UInt_t i=0; iSetMsrStatisticMin(minVal); fRunInfo->SetMsrStatisticNdf(ndf); fConverged = true; if (fPrintLevel >= 2) std::cout << *fFcnMin << std::endl; return true; } //-------------------------------------------------------------------------- // PrepareSector //-------------------------------------------------------------------------- /** *

Collect all the necessary chisq/maxLH sector information. * * @param param parameter value vector of the converged fit. * @param error step value vector of the converged fit. */ void PFitter::PrepareSector(PDoubleVector ¶m, PDoubleVector &error) { Double_t val; UInt_t ndf; Int_t usedParams = 0; for (UInt_t i=0; iSetFitRange(secFitRange); // calculate chisq if (fDKSReady) val = (*fFitterFcnDKS)(param); else val = (*fFitterFcn)(param); fSector[k].SetChisq(val); // calculate NDF if (fDKSReady) ndf = fFitterFcnDKS->GetTotalNoOfFittedBins() - static_cast(usedParams); else ndf = fFitterFcn->GetTotalNoOfFittedBins() - static_cast(usedParams); fSector[k].SetNDF(ndf); // calculate expected chisq totalExpectedChisq = 0.0; if (fDKSReady) fFitterFcnDKS->CalcExpectedChiSquare(param, totalExpectedChisq, expectedChisqPerRun); else fFitterFcn->CalcExpectedChiSquare(param, totalExpectedChisq, expectedChisqPerRun); fSector[k].SetExpectedChisq(totalExpectedChisq); // calculate chisq per run for (UInt_t i=0; iGetMsrRunList()->size(); i++) { chisqPerRun.push_back(fRunListCollection->GetSingleRunChisq(param, i)); fSector[k].SetChisq(chisqPerRun[i], i); fSector[k].SetExpectedChisq(expectedChisqPerRun[i], i); } if (totalExpectedChisq != 0.0) { UInt_t ndf_run = 0; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); else ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); if (ndf_run > 0) { fSector[k].SetNDF(ndf_run, i); } } } else if (chisqPerRun.size() > 0) { // in case expected chisq is not applicable like for asymmetry fits UInt_t ndf_run = 0; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); else ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); if (ndf_run > 0) { fSector[k].SetNDF(ndf_run, i); } } } // clean up chisqPerRun.clear(); expectedChisqPerRun.clear(); } } else { Double_t totalExpectedMaxLH = 0.0; PDoubleVector expectedMaxLHPerRun; PDoubleVector maxLHPerRun; for (UInt_t k=0; kSetFitRange(secFitRange); // calculate maxLH if (fDKSReady) val = (*fFitterFcnDKS)(param); else val = (*fFitterFcn)(param); fSector[k].SetChisq(val); // calculate NDF if (fDKSReady) ndf = fFitterFcnDKS->GetTotalNoOfFittedBins() - static_cast(usedParams); else ndf = fFitterFcn->GetTotalNoOfFittedBins() - static_cast(usedParams); fSector[k].SetNDF(ndf); // calculate expected maxLH totalExpectedMaxLH = 0.0; if (fDKSReady) fFitterFcnDKS->CalcExpectedChiSquare(param, totalExpectedMaxLH, expectedMaxLHPerRun); else fFitterFcn->CalcExpectedChiSquare(param, totalExpectedMaxLH, expectedMaxLHPerRun); fSector[k].SetExpectedChisq(totalExpectedMaxLH); // calculate maxLH per run for (UInt_t i=0; iGetMsrRunList()->size(); i++) { maxLHPerRun.push_back(fRunListCollection->GetSingleRunMaximumLikelihood(param, i)); fSector[k].SetChisq(maxLHPerRun[i], i); fSector[k].SetExpectedChisq(expectedMaxLHPerRun[i], i); } if (totalExpectedMaxLH != 0.0) { UInt_t ndf_run = 0; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); else ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); if (ndf_run > 0) { fSector[k].SetNDF(ndf_run, i); } } } // clean up maxLHPerRun.clear(); expectedMaxLHPerRun.clear(); } } } //-------------------------------------------------------------------------- // ExecuteSector //-------------------------------------------------------------------------- /** *

Write all chisq/maxLH sector information to MINUIT.OUTPUT and dump it * to stdout. * * return: if the sector command was successful, otherwise return flase. */ Bool_t PFitter::ExecuteSector(std::ofstream &fout) { fout << std::endl; fout << std::endl << "*************************************************************************"; fout << std::endl << " SECTOR RESULTS"; fout << std::endl << "*************************************************************************"; if (fUseChi2) { for (UInt_t i=0; i 0) { // in case expected chisq is not applicable like for asymmetry fits for (UInt_t j=0; j 0) { // in case expected chisq is not applicable like for asymmetry fits for (UInt_t j=0; j * * return: */ Double_t PFitter::MilliTime() { struct timeval now; gettimeofday(&now, nullptr); return ((Double_t)now.tv_sec * 1.0e6 + (Double_t)now.tv_usec)/1.0e3; } //-------------------------------------------------------------------------- // GetCPUInfo (private) //-------------------------------------------------------------------------- /** *

extract CPU information from the system. * * @return the CPU information or ?? if this was not possible. */ std::string PFitter::GetCPUInfo() { std::string cpuInfo = "??"; // find out if linux or Mac OS X struct utsname sys_info; uname(&sys_info); if (strstr(sys_info.sysname, "Linux")) { char result[128]; strcpy(result, "??"); char line[128], str[128], *pos; bool done = false; std::ifstream fin("/proc/cpuinfo", std::ifstream::in); while (fin.good() && !done) { fin.getline(line, 128); if (strstr(line, "model name")) { pos = strstr(line, ":"); strcpy(str, pos+2); strncpy(result, str, sizeof(result)); done = true; } } fin.close(); cpuInfo = result; } else if (strstr(sys_info.sysname, "Darwin")) { system("sysctl -n machdep.cpu.brand_string >> /tmp/_musrfit_cpu_info.txt"); sleep(1); char line[128], result[128]; std::ifstream fin("/tmp/_musrfit_cpu_info.txt", std::ifstream::in); while (fin.good()) { fin.getline(line, 128); strncat(result, line, sizeof(result) - strlen(result) - 1); } fin.close(); system("rm /tmp/_musrfit_cpu_info.txt"); cpuInfo = result; } return cpuInfo; } //------------------------------------------------------------------------------------------------- // end //-------------------------------------------------------------------------------------------------