/*************************************************************************** PFitter.cpp Author: Andreas Suter e-mail: andreas.suter@psi.ch $Id$ ***************************************************************************/ /*************************************************************************** * Copyright (C) 2007 by Andreas Suter * * andreas.suter@psi.c * * * * 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. * ***************************************************************************/ #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/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) { // 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; fMnUserParamState = 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 // 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(); if (fMnUserParamState) { delete fMnUserParamState; fMnUserParamState = 0; } 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) { cout << endl << endl << ">> chisq = " << val << ", NDF = " << ndf << ", chisq/NDF = " << val/ndf; } else { // max. log likelihood cout << endl << endl << ">> maxLH = " << val << ", NDF = " << ndf << ", maxLH/NDF = " << val/ndf; } cout << endl << endl; return true; } // 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 for (UInt_t i=0; iSetMsrParamPosErrorPresent(i, true); } } break; case PMN_PLOT: status = ExecutePlot(); break; case PMN_SAVE: status = ExecuteSave(); break; case PMN_SCAN: status = ExecuteScan(); break; case PMN_SIMPLEX: status = ExecuteSimplex(); break; case PMN_USER_COVARIANCE: cerr << endl << "**WARNING** from PFitter::DoFit() : the command USER_COVARIANCE is not yet implemented."; cerr << endl; break; case PMN_USER_PARAM_STATE: cerr << endl << "**WARNING** from PFitter::DoFit() : the command USER_PARAM_STATE is not yet implemented."; cerr << endl; break; case PMN_PRINT: cerr << endl << "**WARNING** from PFitter::DoFit() : the command PRINT is not yet implemented."; cerr << endl; break; default: cerr << endl << "**PANIC ERROR**: PFitter::DoFit(): You should never have reached this point"; cerr << endl; exit(0); break; } // check if command has been successful if (!status) break; } if (IsValid()) { fRunInfo->GetMsrStatistic()->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; // walk through the msr-file COMMAND block PMsrLines::iterator it; for (it = fCmdLines.begin(); it != fCmdLines.end(); ++it) { it->fLine.ToUpper(); if (it->fLine.Contains("COMMANDS")) { continue; } else if (it->fLine.Contains("SET BATCH")) { // needed for backward compatibility continue; } else if (it->fLine.Contains("END RETURN")) { // needed for backward compatibility continue; } else if (it->fLine.Contains("CHI_SQUARE")) { fUseChi2 = true; } else if (it->fLine.Contains("MAX_LIKELIHOOD")) { fUseChi2 = false; } else if (it->fLine.Contains("INTERACTIVE")) { fCmdList.push_back(PMN_INTERACTIVE); } else if (it->fLine.Contains("CONTOURS")) { fCmdList.push_back(PMN_CONTOURS); // 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; 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; 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; 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; break; } fScanNoPoints = ival; } } if (tokens) { delete tokens; tokens = 0; } } else if (it->fLine.Contains("EIGEN")) { fCmdList.push_back(PMN_EIGEN); } else if (it->fLine.Contains("HESSE")) { fIsScanOnly = false; fCmdList.push_back(PMN_HESSE); } else if (it->fLine.Contains("MACHINE_PRECISION")) { fCmdList.push_back(PMN_MACHINE_PRECISION); } else if (it->fLine.Contains("MIGRAD")) { fIsScanOnly = false; fCmdList.push_back(PMN_MIGRAD); } else if (it->fLine.Contains("MINIMIZE")) { fIsScanOnly = false; fCmdList.push_back(PMN_MINIMIZE); } else if (it->fLine.Contains("MINOS")) { fIsScanOnly = false; fCmdList.push_back(PMN_MINOS); } else if (it->fLine.Contains("MNPLOT")) { fCmdList.push_back(PMN_PLOT); } else if (it->fLine.Contains("SAVE")) { fCmdList.push_back(PMN_SAVE); } else if (it->fLine.Contains("SCAN")) { fCmdList.push_back(PMN_SCAN); // 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; 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; 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; 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; 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; 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; break; } fScanHigh = str.Atof(); } } if (tokens) { delete tokens; tokens = 0; } } else if (it->fLine.Contains("SIMPLEX")) { fCmdList.push_back(PMN_SIMPLEX); } else if (it->fLine.Contains("STRATEGY")) { 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")) { fCmdList.push_back(PMN_USER_COVARIANCE); } else if (it->fLine.Contains("USER_PARAM_STATE")) { fCmdList.push_back(PMN_USER_PARAM_STATE); } else if (it->fLine.Contains("PRINT")) { fCmdList.push_back(PMN_PRINT); } else { // unkown command cerr << endl << ">> **FATAL ERROR**"; cerr << endl << ">> PFitter::CheckCommands(): In line " << it->fLineNo << " an unkown command is found:"; cerr << endl << ">> " << it->fLine.Data(); cerr << endl << ">> Will stop ..."; cerr << endl; fIsValid = 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; } //-------------------------------------------------------------------------- // 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; // if already some minimization is done use the minuit2 output as input if (fFcnMin) fMnUserParams = fFcnMin->UserParameters(); // create the hesse object ROOT::Minuit2::MnHesse hesse; // specify maximal number of function calls UInt_t maxfcn = numeric_limits::max(); // call hesse ROOT::Minuit2::MnUserParameterState mnState = hesse((*fFitterFcn), fMnUserParams, maxfcn); if (!mnState.IsValid()) { cerr << endl << "**WARNING** PFitter::ExecuteHesse(): Hesse encountered some problems!"; cerr << endl; return false; } // keep the user parameter state if (fMnUserParamState) { delete fMnUserParamState; } fMnUserParamState = new ROOT::Minuit2::MnUserParameterState(mnState); // fill parabolic errors for (UInt_t i=0; iSetMsrParamStep(i, mnState.Error(i)); fRunInfo->SetMsrParamPosErrorPresent(i, false); } 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; // if already some minimization is done use the minuit2 output as input if (fFcnMin) fMnUserParams = fFcnMin->UserParameters(); // 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; ROOT::Minuit2::FunctionMinimum min = migrad(maxfcn, tolerance); if (!min.IsValid()) { cerr << endl << "**WARNING**: PFitter::ExecuteMigrad(): 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 = new ROOT::Minuit2::FunctionMinimum(min); // keep user parameter state if (fMnUserParamState) { delete fMnUserParamState; } fMnUserParamState = new ROOT::Minuit2::MnUserParameterState(min.UserState()); // 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; 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; // if already some minimization is done use the minuit2 output as input if (fFcnMin) fMnUserParams = fFcnMin->UserParameters(); // 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(); //cout << endl << "maxfcn=" << maxfcn << endl; // tolerance = MINUIT2 Default tolerance Double_t tolerance = 0.1; ROOT::Minuit2::FunctionMinimum min = minimize(maxfcn, tolerance); if (!min.IsValid()) { cerr << endl << "**WARNING**: PFitter::ExecuteMinimize(): 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 = new ROOT::Minuit2::FunctionMinimum(min); // keep user parameter state if (fMnUserParamState) { delete fMnUserParamState; } fMnUserParamState = new ROOT::Minuit2::MnUserParameterState(min.UserState()); // 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; 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; } fMnUserParams = fFcnMin->UserParameters(); // make minos analysis ROOT::Minuit2::MnMinos minos((*fFitterFcn), (*fFcnMin)); for (UInt_t i=0; iParameterInUse(i) != 0)) { // 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()); } else { fRunInfo->SetMsrParamPosErrorPresent(i, false); } } } 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; } //-------------------------------------------------------------------------- // ExecuteScan //-------------------------------------------------------------------------- /** *

Execute 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. * * return: true if the valid minuit2 state is found, otherwise returns false. */ Bool_t PFitter::ExecuteSave() { // 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 << "**WARNING** Minuit2 User Parameter State is not valid, i.e. nothing to be saved"; cerr << endl; return false; } cout << ">> PFitter::ExecuteSave(): will write minuit2 output file ..." << endl; ofstream fout; // open minuit2 output file fout.open("MINUIT2.OUTPUT", iostream::out); 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 global informations fout << endl << " Fval() = " << mnState.Fval() << ", Edm() = " << mnState.Edm() << ", NFcn() = " << mnState.NFcn(); fout << endl; fout << endl << "*************************************************************************"; // identifiy the longest variable name for proper formating reasons Int_t maxLength = 10; 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; iError(i) << " "; else fout << "---"; // write minos errors if (fParams[i].fPosErrorPresent) { fout.setf(ios::left, ios::adjustfield); fout.precision(6); fout.width(12); fout << fParams[i].fStep; fout.setf(ios::left, ios::adjustfield); fout.precision(6); fout.width(11); fout << fParams[i].fPosError << " "; } else { fout.setf(ios::left, ios::adjustfield); fout.width(12); fout << "---"; fout.setf(ios::left, ios::adjustfield); fout.width(12); fout << "---"; } // write limits if (fParams[i].fNoOfParams > 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) { 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"; } // 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; // if already some minimization is done use the minuit2 output as input if (fFcnMin) fMnUserParams = fFcnMin->UserParameters(); // 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; ROOT::Minuit2::FunctionMinimum min = simplex(maxfcn, tolerance); if (!min.IsValid()) { cerr << endl << "**WARNING**: PFitter::ExecuteSimplex(): 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 = new ROOT::Minuit2::FunctionMinimum(min); // 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; return true; } //------------------------------------------------------------------------------------------------- // end //-------------------------------------------------------------------------------------------------