/*************************************************************************** PFitter.cpp Author: Andreas Suter e-mail: andreas.suter@psi.ch ***************************************************************************/ /*************************************************************************** * Copyright (C) 2007-2016 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 #ifdef HAVE_GOMP #include #endif #include #include #include #include #include using namespace std; #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" //-------------------------------------------------------------------------- // 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 fIsScanOnly = true; fConverged = false; fUseChi2 = true; // chi^2 is the default fStrategy = 1; // 0=low, 1=default, 2=high fParams = *(runInfo->GetMsrParamList()); fCmdLines = *runInfo->GetMsrCommands(); // init class variables fFitterFcn = 0; fFcnMin = 0; 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 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); fOriginalFitRange.push_back(range); } // check msr minuit commands if (!CheckCommands()) { return; } // create fit function object fFitterFcn = new PFitterFcn(runListCollection, fUseChi2); if (!fFitterFcn) { fIsValid = false; return; } } //-------------------------------------------------------------------------- // Destructor //-------------------------------------------------------------------------- /** *

Destructor. */ PFitter::~PFitter() { fCmdList.clear(); fScanData.clear(); fElapsedTime.clear(); if (fFcnMin) { delete fFcnMin; fFcnMin = 0; } if (fFitterFcn) { delete fFitterFcn; fFitterFcn = 0; } } //-------------------------------------------------------------------------- // 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() - usedParams; Double_t val = (*fFitterFcn)(param); if (fUseChi2) { // calculate expected chisq Double_t totalExpectedChisq = 0.0; std::vector expectedChisqPerHisto; fFitterFcn->CalcExpectedChiSquare(param, totalExpectedChisq, expectedChisqPerHisto); // calculate chisq per run std::vector chisqPerHisto; for (UInt_t i=0; iGetMsrRunList()->size(); i++) { chisqPerHisto.push_back(fRunListCollection->GetSingleRunChisq(param, i)); } cout << endl << endl << ">> chisq = " << val << ", NDF = " << ndf << ", chisq/NDF = " << val/ndf; if (totalExpectedChisq != 0.0) { cout << endl << ">> expected chisq = " << totalExpectedChisq << ", NDF = " << ndf << ", expected chisq/NDF = " << totalExpectedChisq/ndf; UInt_t ndf_histo = 0; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); if (ndf_histo > 0) cout << endl << ">> run block " << i+1 << ": (NDF/red.chisq/red.chisq_e) = (" << ndf_histo << "/" << chisqPerHisto[i]/ndf_histo << "/" << expectedChisqPerHisto[i]/ndf_histo << ")"; } } else if (chisqPerHisto.size() > 0) { // in case expected chisq is not applicable like for asymmetry fits UInt_t ndf_histo = 0; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); if (ndf_histo > 0) cout << endl << ">> run block " << i+1 << ": (NDF/red.chisq) = (" << ndf_histo << "/" << chisqPerHisto[i]/ndf_histo << ")"; } } // clean up chisqPerHisto.clear(); expectedChisqPerHisto.clear(); } else { // max. log likelihood cout << endl << endl << ">> maxLH = " << val << ", NDF = " << ndf << ", maxLH/NDF = " << val/ndf; } cout << endl << endl; return true; } // debugging information #ifdef HAVE_GOMP cout << endl << ">> Number of available threads for the function optimization: " << omp_get_num_procs() << endl; #endif // real fit wanted if (fUseChi2) cout << endl << ">> Chi Square fit will be executed" << endl; else cout << endl << ">> Maximum Likelihood fit will be executed" << 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; for (it = fCmdLines.begin(); it != fCmdLines.end(); ++it) { if (it == fCmdLines.begin()) cmdLineNo = 0; else cmdLineNo++; if (it->fLine.Contains("COMMANDS", TString::kIgnoreCase)) { continue; } else if (it->fLine.Contains("SET BATCH", TString::kIgnoreCase)) { // needed for backward compatibility continue; } else if (it->fLine.Contains("END RETURN", TString::kIgnoreCase)) { // needed for backward compatibility continue; } else if (it->fLine.Contains("CHI_SQUARE", TString::kIgnoreCase)) { continue; } else if (it->fLine.Contains("MAX_LIKELIHOOD", TString::kIgnoreCase)) { continue; } else if (it->fLine.Contains("SCALE_N0_BKG", TString::kIgnoreCase)) { continue; } else if (it->fLine.Contains("INTERACTIVE", TString::kIgnoreCase)) { cmd.first = PMN_INTERACTIVE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.Contains("CONTOURS", TString::kIgnoreCase)) { cmd.first = PMN_CONTOURS; cmd.second = cmdLineNo; fCmdList.push_back(cmd); // filter out possible parameters for scan TObjArray *tokens = 0; TObjString *ostr; TString str; UInt_t ival; tokens = it->fLine.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()) { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> parameter number is not number!"; cerr << endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]"; cerr << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } break; } ival = str.Atoi(); // check that parameter is within range if ((ival < 1) || (ival > fParams.size())) { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> parameter number is out of range [1," << fParams.size() << "]!"; cerr << endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]"; cerr << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } 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()) { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> number of points is not number!"; cerr << endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]"; cerr << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } break; } ival = str.Atoi(); if ((ival < 1) || (ival > 100)) { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> number of scan points is out of range [1,100]!"; cerr << endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]"; cerr << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } break; } fScanNoPoints = ival; } } if (tokens) { delete tokens; tokens = 0; } } else if (it->fLine.Contains("EIGEN", TString::kIgnoreCase)) { cmd.first = PMN_EIGEN; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.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 = 0; TObjString *ostr; TString str; tokens = it->fLine.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 { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> Syntax: FIT_RANGE RESET | FIT_RANGE start end | FIT_RANGE s1 e1 s2 e2 .. sN eN,"; cerr << endl << ">> with N the number of runs in the msr-file." << endl; cerr << endl << ">> Found " << str.Data() << ", instead of RESET" << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } 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()) { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> Syntax: FIT_RANGE RESET | FIT_RANGE | FIT_RANGE .. |"; cerr << endl << ">> FIT_RANGE fgb+ lgb- | FIT_RANGE fgb+ lgb- fgb+ lgb- ... fgb+ lgb-,"; cerr << endl << ">> with N the number of runs in the msr-file."; cerr << endl << ">> Found N=" << (tokens->GetEntries()-1)/2 << ", # runs in msr-file=" << fRunInfo->GetMsrRunList()->size() << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } 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 { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> Syntax: FIT_RANGE RESET | FIT_RANGE | FIT_RANGE .. |"; cerr << endl << ">> FIT_RANGE fgb+ lgb- | FIT_RANGE fgb+ lgb- fgb+ lgb- ... fgb+ lgb-,"; cerr << endl << ">> with N the number of runs in the msr-file."; cerr << endl << ">> Found token '" << str.Data() << "', which is not a floating point number." << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } break; } } } else { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> Syntax: FIT_RANGE RESET | FIT_RANGE | FIT_RANGE .. |"; cerr << endl << ">> FIT_RANGE fgb+ lgb- | FIT_RANGE fgb+ lgb- fgb+ lgb- ... fgb+ lgb-,"; cerr << endl << ">> with N the number of runs in the msr-file."; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } break; } if (tokens) { delete tokens; tokens = 0; } } else if (it->fLine.Contains("FIX", TString::kIgnoreCase)) { // check if the given set of parameters (number or names) is present TObjArray *tokens = 0; TObjString *ostr; TString str; UInt_t ival; tokens = it->fLine.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()) { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> Parameter " << ival << " is out of the Parameter Range [1," << fParams.size() << "]"; cerr << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } 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; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> Parameter '" << str.Data() << "' is NOT present as a parameter name"; cerr << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } break; } } } if (tokens) { delete tokens; tokens = 0; } // everything looks fine, feed the command list cmd.first = PMN_FIX; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.Contains("HESSE", TString::kIgnoreCase)) { fIsScanOnly = false; cmd.first = PMN_HESSE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.Contains("MACHINE_PRECISION", TString::kIgnoreCase)) { cmd.first = PMN_MACHINE_PRECISION; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.Contains("MIGRAD", TString::kIgnoreCase)) { fIsScanOnly = false; cmd.first = PMN_MIGRAD; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.Contains("MINIMIZE", TString::kIgnoreCase)) { fIsScanOnly = false; cmd.first = PMN_MINIMIZE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.Contains("MINOS", TString::kIgnoreCase)) { fIsScanOnly = false; cmd.first = PMN_MINOS; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.Contains("MNPLOT", TString::kIgnoreCase)) { cmd.first = PMN_PLOT; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.Contains("PRINT_LEVEL", TString::kIgnoreCase)) { cmd.first = PMN_PRINT; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.Contains("RELEASE", TString::kIgnoreCase)) { // check if the given set of parameters (number or names) is present TObjArray *tokens = 0; TObjString *ostr; TString str; UInt_t ival; tokens = it->fLine.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()) { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> Parameter " << ival << " is out of the Parameter Range [1," << fParams.size() << "]"; cerr << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } 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; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> Parameter '" << str.Data() << "' is NOT present as a parameter name"; cerr << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } break; } } } if (tokens) { delete tokens; tokens = 0; } cmd.first = PMN_RELEASE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.Contains("RESTORE", TString::kIgnoreCase)) { cmd.first = PMN_RESTORE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.Contains("SAVE", TString::kIgnoreCase)) { cmd.first = PMN_SAVE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.Contains("SCAN", TString::kIgnoreCase)) { cmd.first = PMN_SCAN; cmd.second = cmdLineNo; fCmdList.push_back(cmd); // filter out possible parameters for scan TObjArray *tokens = 0; TObjString *ostr; TString str; UInt_t ival; tokens = it->fLine.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()) { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> parameter number is not number!"; cerr << endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]"; cerr << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } break; } ival = str.Atoi(); // check that parameter is within range if ((ival < 1) || (ival > fParams.size())) { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> parameter number is out of range [1," << fParams.size() << "]!"; cerr << endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]"; cerr << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } 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()) { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> number of points is not number!"; cerr << endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]"; cerr << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } break; } ival = str.Atoi(); if ((ival < 1) || (ival > 100)) { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> number of scan points is out of range [1,100]!"; cerr << endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]"; cerr << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } break; } fScanNoPoints = ival; } if (i==3) { // get low // check that token is a Double_t if (!str.IsFloat()) { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> low is not a floating point number!"; cerr << endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]"; cerr << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } break; } fScanLow = str.Atof(); } if (i==4) { // get high // check that token is a Double_t if (!str.IsFloat()) { cerr << endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> high is not a floating point number!"; cerr << endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]"; cerr << endl; fIsValid = false; if (tokens) { delete tokens; tokens = 0; } break; } fScanHigh = str.Atof(); } } if (tokens) { delete tokens; tokens = 0; } } else if (it->fLine.Contains("SIMPLEX", TString::kIgnoreCase)) { cmd.first = PMN_SIMPLEX; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.Contains("STRATEGY", TString::kIgnoreCase)) { TObjArray *tokens = 0; TObjString *ostr; TString str; tokens = it->fLine.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 = 0; } } else if (it->fLine.Contains("USER_COVARIANCE", TString::kIgnoreCase)) { cmd.first = PMN_USER_COVARIANCE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else if (it->fLine.Contains("USER_PARAM_STATE", TString::kIgnoreCase)) { cmd.first = PMN_USER_PARAM_STATE; cmd.second = cmdLineNo; fCmdList.push_back(cmd); } else { // unkown command cerr << endl << ">> PFitter::CheckCommands(): **FATAL ERROR** in line " << it->fLineNo << " an unkown command is found:"; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> Will stop ..."; cerr << 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 (it->fLine.Contains("FIX", TString::kIgnoreCase)) fixFlag = true; else if (it->fLine.Contains("RELEASE", TString::kIgnoreCase) || it->fLine.Contains("RESTORE", TString::kIgnoreCase)) releaseFlag = true; else if (it->fLine.Contains("MINIMIZE", TString::kIgnoreCase) || it->fLine.Contains("MIGRAD", TString::kIgnoreCase) || it->fLine.Contains("SIMPLEX", TString::kIgnoreCase)) { if (releaseFlag) minimizerFlag = true; } else if (it->fLine.Contains("MINOS", TString::kIgnoreCase)) { if (fixFlag && releaseFlag && !minimizerFlag) { cerr << endl << ">> PFitter::CheckCommands(): **WARNING** RELEASE/RESTORE command present"; cerr << endl << ">> without minimizer command (MINIMIZE/MIGRAD/SIMPLEX) between"; cerr << endl << ">> RELEASE/RESTORE and MINOS. Behaviour might be different to the"; cerr << endl << ">> expectation of the user ?!?" << 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 cerr << endl << "**WARNING** : Parameter No " << i+1 << " is not used at all, will fix it"; cerr << 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() { cout << ">> PFitter::ExecuteContours() ..." << endl; // if already some minimization is done use the minuit2 output as input if (!fFcnMin) { cerr << endl << "**WARNING**: CONTOURS musn't be called before any minimization (MINIMIZE/MIGRAD/SIMPLEX) is done!!"; cerr << endl; return false; } // check if minimum was valid if (!fFcnMin->IsValid()) { cerr << endl << "**ERROR**: CONTOURS cannot started since the previous minimization failed :-("; cerr << endl; return false; } ROOT::Minuit2::MnContours contours((*fFitterFcn), *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) { cout << ">> PFitter::ExecuteFitRange(): " << fCmdLines[lineNo].fLine.Data() << endl; if (fCmdLines[lineNo].fLine.Contains("fgb", TString::kIgnoreCase)) { // fit range given in bins fRunListCollection->SetFitRange(fCmdLines[lineNo].fLine); return true; } TObjArray *tokens = 0; 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) { cout << ">> PFitter::ExecuteFix(): " << fCmdLines[lineNo].fLine.Data() << endl; TObjArray *tokens = 0; 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 = 0; } 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() { cout << ">> PFitter::ExecuteHesse(): will call hesse ..." << endl; // create the hesse object ROOT::Minuit2::MnHesse hesse; // specify maximal number of function calls UInt_t maxfcn = numeric_limits::max(); // call hesse Double_t start=0.0, end=0.0; start=MilliTime(); ROOT::Minuit2::MnUserParameterState mnState = hesse((*fFitterFcn), fMnUserParams, maxfcn); end=MilliTime(); cout << ">> PFitter::ExecuteMinimize(): execution time for Hesse = " << setprecision(3) << (end-start)/1.0e3 << " sec." << endl; TString str = TString::Format("Hesse: %.3f sec", (end-start)/1.0e3); fElapsedTime.push_back(str); if (!mnState.IsValid()) { cerr << endl << ">> PFitter::ExecuteHesse(): **WARNING** Hesse encountered some problems!"; cerr << endl; return false; } // fill parabolic errors for (UInt_t i=0; iSetMsrParamStep(i, mnState.Error(i)); fRunInfo->SetMsrParamPosErrorPresent(i, false); } if (fPrintLevel >= 2) cout << mnState << 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() { cout << ">> PFitter::ExecuteMigrad(): will call migrad ..." << endl; // create migrad object // strategy is by default = 'default' ROOT::Minuit2::MnMigrad migrad((*fFitterFcn), fMnUserParams, fStrategy); // minimize // maxfcn is MINUIT2 Default maxfcn UInt_t maxfcn = 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(); cout << ">> PFitter::ExecuteMinimize(): execution time for Migrad = " << setprecision(3) << (end-start)/1.0e3 << " sec." << endl; TString str = TString::Format("Migrad: %.3f sec", (end-start)/1.0e3); fElapsedTime.push_back(str); if (!min.IsValid()) { cerr << endl << ">> PFitter::ExecuteMigrad(): **WARNING**: Fit did not converge, sorry ..."; cerr << endl; fIsValid = false; return false; } // keep FunctionMinimum object if (fFcnMin) { // fFcnMin exist hence clean up first delete fFcnMin; fFcnMin = 0; } fFcnMin = new ROOT::Minuit2::FunctionMinimum(min); // keep user parameters if (fFcnMin) fMnUserParams = fFcnMin->UserParameters(); // fill run info for (UInt_t i=0; iSetMsrParamValue(i, min.UserState().Value(i)); fRunInfo->SetMsrParamStep(i, min.UserState().Error(i)); fRunInfo->SetMsrParamPosErrorPresent(i, false); } // handle statistics Double_t minVal = min.Fval(); UInt_t 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) cout << *fFcnMin << 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() { cout << ">> PFitter::ExecuteMinimize(): will call minimize ..." << endl; // create minimizer object // strategy is by default = 'default' ROOT::Minuit2::MnMinimize minimize((*fFitterFcn), fMnUserParams, fStrategy); // minimize // maxfcn is MINUIT2 Default maxfcn UInt_t maxfcn = 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(); cout << ">> PFitter::ExecuteMinimize(): execution time for Minimize = " << setprecision(3) << (end-start)/1.0e3 << " sec." << endl; TString str = TString::Format("Minimize: %.3f sec", (end-start)/1.0e3); fElapsedTime.push_back(str); if (!min.IsValid()) { cerr << endl << ">> PFitter::ExecuteMinimize(): **WARNING**: Fit did not converge, sorry ..."; cerr << endl; fIsValid = false; return false; } // keep FunctionMinimum object if (fFcnMin) { // fFcnMin exist hence clean up first delete fFcnMin; fFcnMin = 0; } fFcnMin = new ROOT::Minuit2::FunctionMinimum(min); // keep user parameters if (fFcnMin) fMnUserParams = fFcnMin->UserParameters(); // fill run info for (UInt_t i=0; iSetMsrParamValue(i, min.UserState().Value(i)); fRunInfo->SetMsrParamStep(i, min.UserState().Error(i)); fRunInfo->SetMsrParamPosErrorPresent(i, false); } // handle statistics Double_t minVal = min.Fval(); UInt_t 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) cout << *fFcnMin << 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() { cout << ">> PFitter::ExecuteMinos(): will call minos ..." << endl; // if already some minimization is done use the minuit2 output as input if (!fFcnMin) { cerr << endl << "**ERROR**: MINOS musn't be called before any minimization (MINIMIZE/MIGRAD/SIMPLEX) is done!!"; cerr << endl; return false; } // check if minimum was valid if (!fFcnMin->IsValid()) { cerr << endl << "**ERROR**: MINOS cannot started since the previous minimization failed :-("; cerr << endl; return false; } // make minos analysis Double_t start=0.0, end=0.0; start=MilliTime(); ROOT::Minuit2::MnMinos minos((*fFitterFcn), (*fFcnMin)); for (UInt_t i=0; iParameterInUse(i) != 0) && (!fMnUserParams.Parameters().at(i).IsFixed())) { cout << ">> PFitter::ExecuteMinos(): calculate errors for " << fParams[i].fName << 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()) { cerr << endl << ">> PFitter::ExecuteMinos(): **WARNING** Parameter " << fMnUserParams.Name(i) << " (ParamNo " << i+1 << ") is fixed!"; cerr << endl << ">> Will set STEP to zero, i.e. making it a constant parameter"; cerr << endl; fRunInfo->SetMsrParamStep(i, 0.0); fRunInfo->SetMsrParamPosErrorPresent(i, false); } } end=MilliTime(); cout << ">> PFitter::ExecuteMinimize(): execution time for Minos = " << setprecision(3) << (end-start)/1.0e3 << " sec." << 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() { cout << ">> PFitter::ExecutePlot() ..." << 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) { cout << ">> PFitter::ExecutePrintLevel(): " << fCmdLines[lineNo].fLine.Data() << endl; TObjArray *tokens = 0; TObjString *ostr; TString str; tokens = fCmdLines[lineNo].fLine.Tokenize(", \t"); if (tokens->GetEntries() < 2) { cerr << endl << "**ERROR** from PFitter::ExecutePrintLevel(): SYNTAX: PRINT_LEVEL , where =0-3" << endl << 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 { cerr << endl << "**ERROR** from PFitter::ExecutePrintLevel(): SYNTAX: PRINT_LEVEL , where =0-3"; cerr << endl << " found =" << ival << endl << endl; return false; } } else { cerr << endl << "**ERROR** from PFitter::ExecutePrintLevel(): SYNTAX: PRINT_LEVEL , where =0-3" << endl << endl; return false; } ROOT::Minuit2::MnPrint::SetLevel(fPrintLevel); // clean up if (tokens) { delete tokens; tokens = 0; } 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 = 0; TObjString *ostr; TString str; tokens = fCmdLines[lineNo].fLine.Tokenize(", \t"); cout << ">> PFitter::ExecuteRelease(): " << fCmdLines[lineNo].fLine.Data() << 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 = 0; } return true; } //-------------------------------------------------------------------------- // ExecuteRestore //-------------------------------------------------------------------------- /** *

Release all fixed parameters * * return: true. */ Bool_t PFitter::ExecuteRestore() { cout << "PFitter::ExecuteRestore(): release all fixed parameters (RESTORE) ..." << endl; for (UInt_t i=0; iExecute the minuit2 scan command. * * return: true. */ Bool_t PFitter::ExecuteScan() { cout << ">> PFitter::ExecuteScan(): will call scan ..." << endl; ROOT::Minuit2::MnScan scan((*fFitterFcn), 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) { cout << 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()) { cerr << endl << ">> PFitter::ExecuteSave: **WARNING** Minuit2 User Parameter State is not valid, i.e. nothing to be saved"; cerr << 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 expectedChisqPerHisto; std::vector ndfPerHisto; for (UInt_t i=0; iCalcExpectedChiSquare(param, totalExpectedChisq, expectedChisqPerHisto); // calculate chisq per run std::vector chisqPerHisto; for (UInt_t i=0; iGetMsrRunList()->size(); i++) { if (fUseChi2) chisqPerHisto.push_back(fRunListCollection->GetSingleRunChisq(param, i)); else chisqPerHisto.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_histo; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); ndfPerHisto.push_back(ndf_histo); } // feed the msr-file handler PMsrStatisticStructure *statistics = fRunInfo->GetMsrStatistic(); if (statistics) { statistics->fMinPerHisto = chisqPerHisto; statistics->fMinExpected = totalExpectedChisq; statistics->fMinExpectedPerHisto = expectedChisqPerHisto; statistics->fNdfPerHisto = ndfPerHisto; } } else if (chisqPerHisto.size() > 1) { // in case expected chisq is not applicable like for asymmetry fits UInt_t ndf_histo = 0; for (UInt_t i=0; iGetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i); ndfPerHisto.push_back(ndf_histo); } // feed the msr-file handler PMsrStatisticStructure *statistics = fRunInfo->GetMsrStatistic(); if (statistics) { statistics->fMinPerHisto = chisqPerHisto; statistics->fNdfPerHisto = ndfPerHisto; } } // clean up param.clear(); expectedChisqPerHisto.clear(); ndfPerHisto.clear(); chisqPerHisto.clear(); cout << ">> PFitter::ExecuteSave(): will write minuit2 output file ..." << endl; ofstream fout; // open minuit2 output file if (firstSave) fout.open("MINUIT2.OUTPUT", iostream::out); else fout.open("MINUIT2.OUTPUT", iostream::out | iostream::app); if (!fout.is_open()) { cerr << endl << "**ERROR** PFitter::ExecuteSave() couldn't open MINUIT2.OUTPUT file"; cerr << endl; return false; } // write header TDatime dt; fout << endl << "*************************************************************************"; fout << endl << " musrfit MINUIT2 output file from " << fRunInfo->GetFileName().Data() << " - " << dt.AsSQLString(); fout << endl << "*************************************************************************"; fout << endl; // write elapsed times fout << 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 << endl << " PARAMETERS"; fout << endl << "-------------------------------------------------------------------------"; fout << endl << " "; for (Int_t j=0; j<=maxLength-4; j++) fout << " "; fout << "Parabolic Minos"; fout << 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(ios::left, ios::adjustfield); fout.width(7); if (fParams[i].fLowerBoundaryPresent) fout << fParams[i].fLowerBoundary; else fout << "---"; fout.setf(ios::left, ios::adjustfield); fout.width(7); if (fParams[i].fUpperBoundaryPresent) fout << fParams[i].fUpperBoundary; else fout << "---"; } else { fout.setf(ios::left, ios::adjustfield); fout.width(7); fout << "---"; fout.setf(ios::left, ios::adjustfield); fout.width(7); fout << "---"; } } fout << endl; fout << endl << "*************************************************************************"; // write covariance matrix fout << endl << " COVARIANCE MATRIX"; fout << endl << "-------------------------------------------------------------------------"; if (mnState.HasCovariance()) { ROOT::Minuit2::MnUserCovariance cov = mnState.Covariance(); fout << 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 << endl << " no covariance matrix available"; } fout << endl; fout << endl << "*************************************************************************"; // write correlation matrix fout << endl << " CORRELATION COEFFICIENTS"; fout << endl << "-------------------------------------------------------------------------"; if (mnState.HasGlobalCC() && mnState.HasCovariance()) { ROOT::Minuit2::MnGlobalCorrelationCoeff corr = mnState.GlobalCC(); ROOT::Minuit2::MnUserCovariance cov = mnState.Covariance(); PIntVector parNo; fout << endl << " No Global "; for (UInt_t i=0; iParameterInUse(i) > 0) && (!fMnUserParams.Parameters().at(i).IsFixed())) { fout.setf(ios::left, 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()) { cerr << endl << "**SEVERE ERROR** in PFitter::ExecuteSave(): minuit2 and musrfit book keeping to not correspond! Unable to write correlation matrix."; cerr << 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) { cerr << endl << "**SEVERE ERROR** in PFitter::ExecuteSave(): parameter no " << parNo[i]+1 << " has an error == 0. Cannot correctly handle the correlation matrix."; cerr << endl; dval = 0.0; } else if (fMnUserParams.Error(parNo[j]) == 0.0) { cerr << endl << "**SEVERE ERROR** in PFitter::ExecuteSave(): parameter no " << parNo[j]+1 << " has an error == 0. Cannot correctly handle the correlation matrix."; cerr << 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 = 0; } if (hcorr) { delete hcorr; hcorr = 0; } } parNo.clear(); // clean up } else { fout << endl << " no correlation coefficients available"; } fout << endl; fout << endl << "*************************************************************************"; fout << endl << " DONE "; fout << endl << "*************************************************************************"; fout << endl << 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() { cout << ">> PFitter::ExecuteSimplex(): will call simplex ..." << endl; // create minimizer object // strategy is by default = 'default' ROOT::Minuit2::MnSimplex simplex((*fFitterFcn), fMnUserParams, fStrategy); // minimize // maxfcn is 10*MINUIT2 Default maxfcn UInt_t maxfcn = 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(); cout << ">> PFitter::ExecuteMinimize(): execution time for Simplex = " << setprecision(3) << (end-start)/1.0e3 << " sec." << endl; TString str = TString::Format("Simplex: %.3f sec", (end-start)/1.0e3); fElapsedTime.push_back(str); if (!min.IsValid()) { cerr << endl << ">> PFitter::ExecuteSimplex(): **WARNING**: Fit did not converge, sorry ..."; cerr << endl; fIsValid = false; return false; } // keep FunctionMinimum object if (fFcnMin) { // fFcnMin exist hence clean up first delete fFcnMin; fFcnMin = 0; } fFcnMin = new ROOT::Minuit2::FunctionMinimum(min); // keep user parameters if (fFcnMin) fMnUserParams = fFcnMin->UserParameters(); // fill run info for (UInt_t i=0; iSetMsrParamValue(i, min.UserState().Value(i)); fRunInfo->SetMsrParamStep(i, min.UserState().Error(i)); fRunInfo->SetMsrParamPosErrorPresent(i, false); } // handle statistics Double_t minVal = min.Fval(); UInt_t 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) cout << *fFcnMin << endl; return true; } //-------------------------------------------------------------------------- // MilliTime //-------------------------------------------------------------------------- /** *

* * return: */ Double_t PFitter::MilliTime() { struct timeval now; gettimeofday(&now, 0); return ((Double_t)now.tv_sec * 1.0e6 + (Double_t)now.tv_usec)/1.0e3; } //------------------------------------------------------------------------------------------------- // end //-------------------------------------------------------------------------------------------------