musrfit 1.10.0
PFitter.cpp
Go to the documentation of this file.
1/***************************************************************************
2
3 PFitter.cpp
4
5 Author: Andreas Suter
6 e-mail: andreas.suter@psi.ch
7
8***************************************************************************/
9
10/***************************************************************************
11 * Copyright (C) 2007-2026 by Andreas Suter *
12 * andreas.suter@psi.ch *
13 * *
14 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
18 * *
19 * This program is distributed in the hope that it will be useful, *
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
22 * GNU General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU General Public License *
25 * along with this program; if not, write to the *
26 * Free Software Foundation, Inc., *
27 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
28 ***************************************************************************/
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#ifdef HAVE_GOMP
35#include <omp.h>
36#endif
37
38#include <iostream>
39#include <iomanip>
40#include <fstream>
41#include <limits>
42#include <cmath>
43
44#include <boost/variant/variant.hpp>
45
46#include <sys/time.h>
47
48#include "Minuit2/FunctionMinimum.h"
49#include "Minuit2/MnContours.h"
50#include "Minuit2/MnHesse.h"
51#include "Minuit2/MnMinimize.h"
52#include "Minuit2/MnMigrad.h"
53#include "Minuit2/MnMinos.h"
54#include "Minuit2/MnPlot.h"
55#include "Minuit2/MnPrint.h"
56#include "Minuit2/MnScan.h"
57#include "Minuit2/MnSimplex.h"
58#include "Minuit2/MnStrategy.h"
59#include "Minuit2/MnUserParameterState.h"
60#include "Minuit2/MinosError.h"
61
62#include <TCanvas.h>
63#include <TH2.h>
64#include <TFile.h>
65#include <TDatime.h>
66#include <TString.h>
67#include <TObjArray.h>
68#include <TObjString.h>
69
70#include "PFitter.h"
71
72
73//+++ PSectorChisq class +++++++++++++++++++++++++++++++++++++++++++++++++++
74
75//--------------------------------------------------------------------------
76// Constructor
77//--------------------------------------------------------------------------
81PSectorChisq::PSectorChisq(UInt_t noOfRuns) : fNoOfRuns(noOfRuns)
82{
83 // init
84 fLast = 0.0;
85 fChisq = 0.0;
86 fExpectedChisq = 0.0;
87 fNDF = 0;
88 fFirst.resize(fNoOfRuns);
89 fChisqRun.resize(fNoOfRuns);
91 fNDFRun.resize(fNoOfRuns);
92 for (UInt_t i=0; i<fNoOfRuns; i++) {
93 fFirst[i] = 0.0;
94 fChisqRun[i] = 0.0;
95 fExpectedChisqRun[i] = 0.0;
96 fNDFRun[i] = 0;
97 }
98}
99
100//--------------------------------------------------------------------------
101// SetRunFirstTime
102//--------------------------------------------------------------------------
109void PSectorChisq::SetRunFirstTime(Double_t first, UInt_t idx)
110{
111 if (idx > fNoOfRuns) {
112 std::cerr << "**WARNING** from PSectorChisq::SetRunFirstTime. It tries to set" << std::endl;
113 std::cerr << " a fgb time stamp with idx=" << idx << " which is larger than #RUNS=" << fNoOfRuns << "." << std::endl;
114 std::cerr << " Will ignore it, but you better check what is going on!" << std::endl;
115 return;
116 }
117
118 fFirst[idx] = first;
119}
120
121//--------------------------------------------------------------------------
122// SetChisq
123//--------------------------------------------------------------------------
130void PSectorChisq::SetChisq(Double_t chisq, UInt_t idx)
131{
132 if (idx > fNoOfRuns) {
133 std::cerr << "**WARNING** from PSectorChisq::SetChisq. It tries to set" << std::endl;
134 std::cerr << " a chisq with idx=" << idx << " which is larger than #RUNS=" << fNoOfRuns << "." << std::endl;
135 std::cerr << " Will ignore it, but you better check what is going on!" << std::endl;
136 return;
137 }
138
139 fChisqRun[idx] = chisq;
140}
141
142//--------------------------------------------------------------------------
143// SetExpectedChisq
144//--------------------------------------------------------------------------
151void PSectorChisq::SetExpectedChisq(Double_t chisq, UInt_t idx)
152{
153 if (idx > fNoOfRuns) {
154 std::cerr << "**WARNING** from PSectorChisq::SetExpectedChisq. It tries to set" << std::endl;
155 std::cerr << " a chisq with idx=" << idx << " which is larger than #RUNS=" << fNoOfRuns << "." << std::endl;
156 std::cerr << " Will ignore it, but you better check what is going on!" << std::endl;
157 return;
158 }
159
160 fExpectedChisqRun[idx] = chisq;
161}
162
163//--------------------------------------------------------------------------
164// SetNDF
165//--------------------------------------------------------------------------
172void PSectorChisq::SetNDF(UInt_t ndf, UInt_t idx)
173{
174 if (idx > fNoOfRuns) {
175 std::cerr << "**WARNING** from PSectorChisq::SetNDF. It tries to set" << std::endl;
176 std::cerr << " a NDF with idx=" << idx << " which is larger than #RUNS=" << fNoOfRuns << "." << std::endl;
177 std::cerr << " Will ignore it, but you better check what is going on!" << std::endl;
178 return;
179 }
180
181 fNDFRun[idx] = ndf;
182}
183
184//--------------------------------------------------------------------------
185// GetTimeRangeFirst
186//--------------------------------------------------------------------------
196{
197 if (idx > fNoOfRuns)
198 return PMUSR_UNDEFINED;
199
200 return fFirst[idx];
201}
202
203//--------------------------------------------------------------------------
204// GetChisq
205//--------------------------------------------------------------------------
213Double_t PSectorChisq::GetChisq(UInt_t idx)
214{
215 if (idx >= fNoOfRuns)
216 return -1.0;
217
218 return fChisqRun[idx];
219}
220
221//--------------------------------------------------------------------------
222// GetExpectedChisq
223//--------------------------------------------------------------------------
232{
233 if (idx >= fNoOfRuns)
234 return -1.0;
235
236 return fExpectedChisqRun[idx];
237}
238
239//--------------------------------------------------------------------------
240// GetNDF
241//--------------------------------------------------------------------------
249UInt_t PSectorChisq::GetNDF(UInt_t idx)
250{
251 if (idx >= fNoOfRuns)
252 return 0;
253
254 return fNDFRun[idx];
255}
256
257//+++ PFitter class ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
258
259//--------------------------------------------------------------------------
260// Constructor
261//--------------------------------------------------------------------------
290PFitter::PFitter(PMsrHandler *runInfo, PRunListCollection *runListCollection, Bool_t chisq_only, Bool_t yaml_out) :
291 fChisqOnly(chisq_only), fYamlOut(yaml_out), fRunInfo(runInfo), fRunListCollection(runListCollection)
292{
293 // initialize variables
294 fIsScanOnly = true;
295 fConverged = false;
296 fUseChi2 = true; // chi^2 is the default
297
298 fStrategy = 1; // 0=low, 1=default, 2=high
299
300 fSectorFlag = false;
301
302 fParams = *(runInfo->GetMsrParamList());
303 fCmdLines = *runInfo->GetMsrCommands();
304
305 // init class variables
306 fScanAll = true;
307 fScanParameter[0] = 0;
308 fScanParameter[1] = 0;
309 fScanNoPoints = 41; // minuit2 default
310 fScanLow = 0.0; // minuit2 default, i.e. 2 std deviations
311 fScanHigh = 0.0; // minuit2 default, i.e. 2 std deviations
312 fPrintLevel = 1.0;
313
314 // keep all the fit ranges in case RANGE command is present
315 PDoublePair rangeGlob;
316 PMsrGlobalBlock *global = fRunInfo->GetMsrGlobal();
317 rangeGlob.first = global->GetFitRange(0);
318 rangeGlob.second = global->GetFitRange(1);
319
320 PMsrRunList *runs = fRunInfo->GetMsrRunList();
321 PDoublePair range;
322 for (UInt_t i=0; i<runs->size(); i++) {
323 range.first = (*runs)[i].GetFitRange(0);
324 range.second = (*runs)[i].GetFitRange(1);
325 if (range.first == PMUSR_UNDEFINED)
326 fOriginalFitRange.push_back(rangeGlob);
327 else
328 fOriginalFitRange.push_back(range);
329 }
330
331 // check msr minuit commands
332 if (!CheckCommands()) {
333 return;
334 }
335
336 // create phase bool array
338
339 // create fit function object
340 fFitterFcn = std::make_unique<PFitterFcn>(runListCollection, fUseChi2);
341}
342
343//--------------------------------------------------------------------------
344// Destructor
345//--------------------------------------------------------------------------
353{
354 fCmdList.clear();
355
356 fScanData.clear();
357
358 fElapsedTime.clear();
359}
360
361//--------------------------------------------------------------------------
362// GetPhaseParams (private)
363//--------------------------------------------------------------------------
391{
392 fPhase.resize(fRunInfo->GetNoOfParams());
393 for (unsigned int i=0; i<fPhase.size(); i++)
394 fPhase[i] = false;
395
396 // analyze theory block for parameters. Phases are present in the following
397 // default functions:
398 // user functions cannot be checked!
399 PMsrLines *theo = fRunInfo->GetMsrTheory();
400 TObjArray *tok = nullptr;
401 TObjString *ostr = nullptr;
402 TString str;
403 int pos = -1;
404 for (unsigned int i=0; i<theo->size(); i++) {
405 pos = -1;
406 TString line = theo->at(i).fLine;
407 if (line.Contains("TFieldCos") || line.Contains("tf ") ||
408 line.Contains("bessel") || line.Contains("b ") ||
409 line.Contains("skewedGss") || line.Contains("skg ") ||
410 line.Contains("staticNKTF") || line.Contains("snktf ") ||
411 line.Contains("dynamicNKTF") || line.Contains("dnktf ")) { // phase is 1st param
412 pos = 1;
413 }
414 if (line.Contains("internFld") || line.Contains("if ") ||
415 line.Contains("internBsl") || line.Contains("ib ")) { // phase is 2nd param
416 pos = 2;
417 }
418 if (line.Contains("muMinusExpTF") || line.Contains("mmsetf ")) { // phase is 5th param
419 pos = 5;
420 }
421
422 if (pos == -1)
423 continue;
424
425 // extract phase token
426 tok = line.Tokenize(" \t");
427 if (tok == nullptr) {
428 std::cerr << "PFitter::GetPhaseParams(): **ERROR** couldn't tokenize theory line string." << std::endl;
429 return;
430 }
431 if (tok->GetEntries() > pos) {
432 ostr = dynamic_cast<TObjString*>(tok->At(pos));
433 str = ostr->GetString();
434 }
435 // clean up
436 delete tok;
437 tok = nullptr;
438
439 // decode phase token. It can be funX, mapX, or a number
440 if (str.Contains("fun")) { // function
441 PIntVector parVec = GetParFromFun(str);
442 for (int i=0; i<parVec.size(); i++) {
443 if (parVec[i] <= fRunInfo->GetNoOfParams())
444 fPhase[parVec[i]-1] = true;
445 }
446 } else if (str.Contains("map")) { // map
447 PIntVector parVec = GetParFromMap(str);
448 for (int i=0; i<parVec.size(); i++) {
449 if (parVec[i] <= fRunInfo->GetNoOfParams())
450 fPhase[parVec[i]-1] = true;
451 }
452 } else { // must be a number
453 int idx = str.Atoi();
454 if (idx == 0) { // something went wrong, str is not an integer
455 std::cerr << "PFitter::GetPhaseParams(): **ERROR** str=" << str.View() << " is not an integer!" << std::endl;
456 return;
457 }
458 idx -= 1; // param start at 1, vector at 0
459 if (idx >= fRunInfo->GetNoOfParams()) { // idx is out-of-range
460 std::cerr << "PFitter::GetPhaseParams(): **ERROR** idx=" << idx << " is > #param = " << fRunInfo->GetNoOfParams() << "!" << std::endl;
461 return;
462 }
463 fPhase[idx] = true;
464 }
465 }
466}
467
468//--------------------------------------------------------------------------
469// GetParFromFun (private)
470//--------------------------------------------------------------------------
490{
491 PIntVector parVec;
492
493 PMsrLines *funList = fRunInfo->GetMsrFunctions();
494 TObjArray *tok = nullptr;
495 TObjString *ostr = nullptr;
496 TString str;
497
498 for (int i=0; i<funList->size(); i++) {
499 if (funList->at(i).fLine.Contains(funStr)) {
500 // tokenize function string
501 tok = funList->at(i).fLine.Tokenize(" =+-*/");
502 if (tok == nullptr) {
503 std::cerr << "PFitter::GetParFromFun(): **ERROR** couldn't tokenize function string." << std::endl;
504 return parVec;
505 }
506
507 for (int j=1; j<tok->GetEntries(); j++) {
508 ostr = dynamic_cast<TObjString*>(tok->At(j));
509 str = ostr->GetString();
510 // parse tok for parX
511 if (str.Contains("par")) {
512 // find start idx of par in token
513 Ssiz_t idx = str.Index("par");
514 idx += 3;
515 TString parStr("");
516 do {
517 parStr += str[idx];
518 } while (isdigit(str[idx++]));
519 parVec.push_back(parStr.Atoi());
520 }
521 // parse tok for mapX
522 if (str.Contains("map")) {
523 // find start idx of par in token
524 Ssiz_t idx = str.Index("map");
525 idx += 3;
526 TString mapStr("map");
527 do {
528 mapStr += str[idx];
529 } while (isdigit(str[idx++]));
530 PIntVector mapParVec = GetParFromMap(mapStr);
531 for (int k=0; k<mapParVec.size(); k++) {
532 parVec.push_back(mapParVec[k]);
533 }
534 }
535 }
536
537 // clean up
538 delete tok;
539 tok = nullptr;
540 }
541 }
542
543 return parVec;
544}
545
546//--------------------------------------------------------------------------
547// GetParFromMap (private)
548//--------------------------------------------------------------------------
571{
572 PIntVector parVec;
573
574 TString str = mapStr;
575 str.Remove(0,3); // remove map from string
576
577 int idx=str.Atoi();
578 if (idx == 0) {
579 std::cerr << "PFitter::GetParFromMap(): **ERROR** couldn't get propper index from mapX!" << std::endl;
580 return parVec;
581 }
582
583 idx -= 1; // map starts at 1, map vector at 0
584
585 // go through all the runs and collect the parameters from the map vectors
586 PMsrRunList *runList = fRunInfo->GetMsrRunList();
587 if (runList == nullptr) {
588 std::cerr << "PFitter::GetParFromMap(): **ERROR** couldn't get required run list information!" << std::endl;
589 return parVec;
590 }
591
592 PIntVector *map = nullptr;
593 for (int i=0; i<runList->size(); i++) {
594 map = runList->at(i).GetMap();
595 if (map == nullptr) {
596 std::cerr << "PFitter::GetParFromMap(): **ERROR** couldn't get required map information (idx=" << i << ")!" << std::endl;
597 parVec.clear();
598 return parVec;
599 }
600 if (idx >= map->size()) {
601 std::cerr << "PFitter::GetParFromMap(): **ERROR** requested map index (idx=" << idx << ") out-of-range (" << map->size() << ")!" << std::endl;
602 parVec.clear();
603 return parVec;
604 }
605 parVec.push_back(map->at(idx));
606 }
607
608 return parVec;
609}
610
611//--------------------------------------------------------------------------
612// DoFit
613//--------------------------------------------------------------------------
648{
649 // feed minuit parameters
651
652 // check if only chisq/maxLH shall be calculated once
653 if (fChisqOnly) {
654 std::vector<Double_t> param = fMnUserParams.Params();
655 std::vector<Double_t> error = fMnUserParams.Errors();
656 Int_t usedParams = 0;
657 for (UInt_t i=0; i<error.size(); i++) {
658 if (error[i] != 0.0)
659 usedParams++;
660 }
661 UInt_t ndf = static_cast<int>(fFitterFcn->GetTotalNoOfFittedBins()) - usedParams;
662 Double_t val = (*fFitterFcn)(param);
663 if (fUseChi2) {
664 // calculate expected chisq
665 Double_t totalExpectedChisq = 0.0;
666 PDoubleVector expectedChisqPerRun;
667 fFitterFcn->CalcExpectedChiSquare(param, totalExpectedChisq, expectedChisqPerRun);
668 // calculate chisq per run
669 std::vector<Double_t> chisqPerRun;
670 for (UInt_t i=0; i<fRunInfo->GetMsrRunList()->size(); i++) {
671 chisqPerRun.push_back(fRunListCollection->GetSingleRunChisq(param, i));
672 }
673
674 std::cout << std::endl << std::endl << ">> chisq = " << val << ", NDF = " << ndf << ", chisq/NDF = " << val/ndf;
675
676 if (totalExpectedChisq != 0.0) {
677 std::cout << std::endl << ">> expected chisq = " << totalExpectedChisq << ", NDF = " << ndf << ", expected chisq/NDF = " << totalExpectedChisq/ndf;
678 UInt_t ndf_run = 0;
679 for (UInt_t i=0; i<expectedChisqPerRun.size(); i++) {
680 ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i);
681 if (ndf_run > 0)
682 std::cout << std::endl << ">> run block " << i+1 << ": (NDF/red.chisq/red.chisq_e) = (" << ndf_run << "/" << chisqPerRun[i]/ndf_run << "/" << expectedChisqPerRun[i]/ndf_run << ")";
683 }
684 } else if (chisqPerRun.size() > 0) { // in case expected chisq is not applicable like for asymmetry fits
685 UInt_t ndf_run = 0;
686 for (UInt_t i=0; i<chisqPerRun.size(); i++) {
687 ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i);
688 if (ndf_run > 0)
689 std::cout << std::endl << ">> run block " << i+1 << ": (NDF/red.chisq) = (" << ndf_run << "/" << chisqPerRun[i]/ndf_run << ")";
690 }
691 }
692
693 // clean up
694 chisqPerRun.clear();
695 expectedChisqPerRun.clear();
696
697 if (fSectorFlag) {
698 PDoublePairVector secFitRange;
699 secFitRange.resize(1);
700 for (UInt_t k=0; k<fSector.size(); k++) {
701 // set sector fit range
702 secFitRange[0].first = fSector[k].GetTimeRangeFirst(0);
703 secFitRange[0].second = fSector[k].GetTimeRangeLast();
704 fRunListCollection->SetFitRange(secFitRange);
705 // calculate chisq
706 val = (*fFitterFcn)(param);
707 // calculate NDF
708 ndf = static_cast<UInt_t>(fFitterFcn->GetTotalNoOfFittedBins()) - usedParams;
709 // calculate expected chisq
710 totalExpectedChisq = 0.0;
711 fFitterFcn->CalcExpectedChiSquare(param, totalExpectedChisq, expectedChisqPerRun);
712 // calculate chisq per run
713 for (UInt_t i=0; i<fRunInfo->GetMsrRunList()->size(); i++) {
714 chisqPerRun.push_back(fRunListCollection->GetSingleRunChisq(param, i));
715 }
716
717 std::cout << std::endl;
718 std::cout << "++++" << std::endl;
719 std::cout << ">> Sector " << k+1 << ": FitRange: " << secFitRange[0].first << ", " << secFitRange[0].second << std::endl;
720 std::cout << ">> chisq = " << val << ", NDF = " << ndf << ", chisq/NDF = " << val/ndf;
721
722 if (totalExpectedChisq != 0.0) {
723 std::cout << std::endl << ">> expected chisq = " << totalExpectedChisq << ", NDF = " << ndf << ", expected chisq/NDF = " << totalExpectedChisq/ndf;
724 UInt_t ndf_run = 0;
725 for (UInt_t i=0; i<expectedChisqPerRun.size(); i++) {
726 ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i);
727 if (ndf_run > 0)
728 std::cout << std::endl << ">> run block " << i+1 << ": (NDF/red.chisq/red.chisq_e) = (" << ndf_run << "/" << chisqPerRun[i]/ndf_run << "/" << expectedChisqPerRun[i]/ndf_run << ")";
729 }
730 } else if (chisqPerRun.size() > 0) { // in case expected chisq is not applicable like for asymmetry fits
731 UInt_t ndf_run = 0;
732 for (UInt_t i=0; i<chisqPerRun.size(); i++) {
733 ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i);
734 if (ndf_run > 0)
735 std::cout << std::endl << ">> run block " << i+1 << ": (NDF/red.chisq) = (" << ndf_run << "/" << chisqPerRun[i]/ndf_run << ")";
736 }
737 }
738 // clean up
739 chisqPerRun.clear();
740 expectedChisqPerRun.clear();
741 }
742 }
743 } else { // max. log likelihood
744 // calculate expected maxLH
745 Double_t totalExpectedMaxLH = 0.0;
746 std::vector<Double_t> expectedMaxLHPerRun;
747 fFitterFcn->CalcExpectedChiSquare(param, totalExpectedMaxLH, expectedMaxLHPerRun);
748 // calculate maxLH per run
749 std::vector<Double_t> maxLHPerRun;
750 for (UInt_t i=0; i<fRunInfo->GetMsrRunList()->size(); i++) {
751 maxLHPerRun.push_back(fRunListCollection->GetSingleRunMaximumLikelihood(param, i));
752 }
753
754 std::cout << std::endl << std::endl << ">> maxLH = " << val << ", NDF = " << ndf << ", maxLH/NDF = " << val/ndf;
755
756 if (totalExpectedMaxLH != 0.0) {
757 std::cout << std::endl << ">> expected maxLH = " << totalExpectedMaxLH << ", NDF = " << ndf << ", expected maxLH/NDF = " << totalExpectedMaxLH/ndf;
758 UInt_t ndf_run = 0;
759 for (UInt_t i=0; i<expectedMaxLHPerRun.size(); i++) {
760 ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i);
761 if (ndf_run > 0)
762 std::cout << std::endl << ">> run block " << i+1 << ": (NDF/red.maxLH/red.maxLH_e) = (" << ndf_run << "/" << maxLHPerRun[i]/ndf_run << "/" << expectedMaxLHPerRun[i]/ndf_run << ")";
763 }
764 }
765
766 // clean up
767 maxLHPerRun.clear();
768 expectedMaxLHPerRun.clear();
769
770 if (fSectorFlag) {
771 PDoublePairVector secFitRange;
772 secFitRange.resize(1);
773 for (UInt_t k=0; k<fSector.size(); k++) {
774 // set sector fit range
775 secFitRange[0].first = fSector[k].GetTimeRangeFirst(0);
776 secFitRange[0].second = fSector[k].GetTimeRangeLast();
777 fRunListCollection->SetFitRange(secFitRange);
778 // calculate maxLH
779 val = (*fFitterFcn)(param);
780 // calculate NDF
781 ndf = static_cast<int>(fFitterFcn->GetTotalNoOfFittedBins()) - usedParams;
782 // calculate expected maxLH
783 totalExpectedMaxLH = 0.0;
784 fFitterFcn->CalcExpectedChiSquare(param, totalExpectedMaxLH, expectedMaxLHPerRun);
785 // calculate maxLH per run
786 for (UInt_t i=0; i<fRunInfo->GetMsrRunList()->size(); i++) {
787 maxLHPerRun.push_back(fRunListCollection->GetSingleRunMaximumLikelihood(param, i));
788 }
789
790 std::cout << std::endl;
791 std::cout << "++++" << std::endl;
792 std::cout << ">> Sector " << k+1 << ": FitRange: " << secFitRange[0].first << ", " << secFitRange[0].second << std::endl;
793 std::cout << ">> maxLH = " << val << ", NDF = " << ndf << ", maxLH/NDF = " << val/ndf;
794
795 if (totalExpectedMaxLH != 0.0) {
796 std::cout << std::endl << ">> expected maxLH = " << totalExpectedMaxLH << ", NDF = " << ndf << ", expected maxLH/NDF = " << totalExpectedMaxLH/ndf;
797 UInt_t ndf_run = 0;
798 for (UInt_t i=0; i<expectedMaxLHPerRun.size(); i++) {
799 ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i);
800 if (ndf_run > 0)
801 std::cout << std::endl << ">> run block " << i+1 << ": (NDF/red.maxLH/red.maxLH_e) = (" << ndf_run << "/" << maxLHPerRun[i]/ndf_run << "/" << expectedMaxLHPerRun[i]/ndf_run << ")";
802 }
803 }
804
805 // clean up
806 maxLHPerRun.clear();
807 expectedMaxLHPerRun.clear();
808 }
809 }
810 }
811 std::cout << std::endl << std::endl;
812 return true;
813 }
814
815 // debugging information
816 #ifdef HAVE_GOMP
817 std::cout << std::endl << ">> Number of available threads for the function optimization: " << omp_get_max_threads() << std::endl;
818 #endif
819
820 // real fit wanted
821 if (fUseChi2)
822 std::cout << std::endl << ">> Chi Square fit will be executed" << std::endl;
823 else
824 std::cout << std::endl << ">> Maximum Likelihood fit will be executed" << std::endl;
825
826 Bool_t status = true;
827 // init positive errors to default false, if minos is called, it will be set true there
828 for (UInt_t i=0; i<fParams.size(); i++) {
829 fRunInfo->SetMsrParamPosErrorPresent(i, false);
830 }
831
832 // walk through the command list and execute them
833 Bool_t firstSave = true;
834 for (UInt_t i=0; i<fCmdList.size(); i++) {
835 switch (fCmdList[i].first) {
836 case PMN_INTERACTIVE:
837 std::cerr << std::endl << "**WARNING** from PFitter::DoFit() : the command INTERACTIVE is not yet implemented.";
838 std::cerr << std::endl;
839 break;
840 case PMN_CONTOURS:
842 break;
843 case PMN_FIT_RANGE:
844 status = ExecuteFitRange(fCmdList[i].second);
845 break;
846 case PMN_FIX:
847 status = ExecuteFix(fCmdList[i].second);
848 break;
849 case PMN_EIGEN:
850 std::cerr << std::endl << "**WARNING** from PFitter::DoFit() : the command EIGEN is not yet implemented.";
851 std::cerr << std::endl;
852 break;
853 case PMN_HESSE:
855 break;
857 std::cerr << std::endl << "**WARNING** from PFitter::DoFit() : the command MACHINE_PRECISION is not yet implemented.";
858 std::cerr << std::endl;
859 break;
860 case PMN_MIGRAD:
862 break;
863 case PMN_MINIMIZE:
865 break;
866 case PMN_MINOS:
868 break;
869 case PMN_PLOT:
871 break;
872 case PMN_RELEASE:
873 status = ExecuteRelease(fCmdList[i].second);
874 break;
875 case PMN_RESTORE:
877 break;
878 case PMN_SAVE:
879 status = ExecuteSave(firstSave);
880 if (firstSave)
881 firstSave = false;
882 break;
883 case PMN_SCAN:
885 break;
886 case PMN_SECTOR:
887 // nothing to be done here
888 break;
889 case PMN_SIMPLEX:
891 break;
893 std::cerr << std::endl << "**WARNING** from PFitter::DoFit() : the command USER_COVARIANCE is not yet implemented.";
894 std::cerr << std::endl;
895 break;
897 std::cerr << std::endl << "**WARNING** from PFitter::DoFit() : the command USER_PARAM_STATE is not yet implemented.";
898 std::cerr << std::endl;
899 break;
900 case PMN_PRINT:
901 status = ExecutePrintLevel(fCmdList[i].second);
902 break;
903 default:
904 std::cerr << std::endl << "**PANIC ERROR**: PFitter::DoFit(): You should never have reached this point";
905 std::cerr << std::endl;
906 exit(0);
907 }
908
909 // check if command has been successful
910 if (!status)
911 break;
912 }
913
914 if (IsValid()) {
915 fRunInfo->GetMsrStatistic()->fValid = true;
916 } else {
917 fRunInfo->GetMsrStatistic()->fValid = false;
918 }
919
920 return true;
921}
922
923//--------------------------------------------------------------------------
924// CheckCommands
925//--------------------------------------------------------------------------
954{
955 fIsValid = true;
956
957 // check if chisq or log max likelihood fit
958 fUseChi2 = fRunInfo->GetMsrStatistic()->fChisq;
959
960 // walk through the msr-file COMMAND block
961 PIntPair cmd;
962 PMsrLines::iterator it;
963 UInt_t cmdLineNo = 0;
964 TString line;
965 Ssiz_t pos;
966 for (it = fCmdLines.begin(); it != fCmdLines.end(); ++it) {
967 if (it == fCmdLines.begin())
968 cmdLineNo = 0;
969 else
970 cmdLineNo++;
971
972 // strip potential comments
973 line = it->fLine;
974 pos = line.First('#');
975 if (pos > 0) // comment present
976 line.Remove(pos,line.Length()-pos);
977
978 if (line.Contains("COMMANDS", TString::kIgnoreCase)) {
979 continue;
980 } else if (line.Contains("SET BATCH", TString::kIgnoreCase)) { // needed for backward compatibility
981 continue;
982 } else if (line.Contains("END RETURN", TString::kIgnoreCase)) { // needed for backward compatibility
983 continue;
984 } else if (line.Contains("CHI_SQUARE", TString::kIgnoreCase)) {
985 continue;
986 } else if (line.Contains("MAX_LIKELIHOOD", TString::kIgnoreCase)) {
987 continue;
988 } else if (line.Contains("SCALE_N0_BKG", TString::kIgnoreCase)) {
989 continue;
990 } else if (line.Contains("INTERACTIVE", TString::kIgnoreCase)) {
991 cmd.first = PMN_INTERACTIVE;
992 cmd.second = cmdLineNo;
993 fCmdList.push_back(cmd);
994 } else if (line.Contains("CONTOURS", TString::kIgnoreCase)) {
995 cmd.first = PMN_CONTOURS;
996 cmd.second = cmdLineNo;
997 fCmdList.push_back(cmd);
998 // filter out possible parameters for scan
999 TObjArray *tokens = nullptr;
1000 TObjString *ostr;
1001 TString str;
1002 UInt_t ival;
1003
1004 tokens = line.Tokenize(", \t");
1005
1006 for (Int_t i=0; i<tokens->GetEntries(); i++) {
1007 ostr = dynamic_cast<TObjString*>(tokens->At(i));
1008 str = ostr->GetString();
1009
1010 if ((i==1) || (i==2)) { // parX / parY
1011 // check that token is a UInt_t
1012 if (!str.IsDigit()) {
1013 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1014 std::cerr << std::endl << ">> " << line.Data();
1015 std::cerr << std::endl << ">> parameter number is not number!";
1016 std::cerr << std::endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]";
1017 std::cerr << std::endl;
1018 fIsValid = false;
1019 if (tokens) {
1020 delete tokens;
1021 tokens = nullptr;
1022 }
1023 break;
1024 }
1025 ival = str.Atoi();
1026 // check that parameter is within range
1027 if ((ival < 1) || (ival > fParams.size())) {
1028 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1029 std::cerr << std::endl << ">> " << line.Data();
1030 std::cerr << std::endl << ">> parameter number is out of range [1," << fParams.size() << "]!";
1031 std::cerr << std::endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]";
1032 std::cerr << std::endl;
1033 fIsValid = false;
1034 if (tokens) {
1035 delete tokens;
1036 tokens = nullptr;
1037 }
1038 break;
1039 }
1040 // keep parameter
1041 fScanParameter[i-1] = ival-1; // internally parameter number starts at 0
1042 fScanAll = false;
1043 }
1044
1045 if (i==3) {
1046 // check that token is a UInt_t
1047 if (!str.IsDigit()) {
1048 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1049 std::cerr << std::endl << ">> " << line.Data();
1050 std::cerr << std::endl << ">> number of points is not number!";
1051 std::cerr << std::endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]";
1052 std::cerr << std::endl;
1053 fIsValid = false;
1054 if (tokens) {
1055 delete tokens;
1056 tokens = nullptr;
1057 }
1058 break;
1059 }
1060 ival = str.Atoi();
1061 if ((ival < 1) || (ival > 100)) {
1062 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1063 std::cerr << std::endl << ">> " << line.Data();
1064 std::cerr << std::endl << ">> number of scan points is out of range [1,100]!";
1065 std::cerr << std::endl << ">> command syntax for CONTOURS is: CONTOURS parameter-X parameter-Y [# of points]";
1066 std::cerr << std::endl;
1067 fIsValid = false;
1068 if (tokens) {
1069 delete tokens;
1070 tokens = nullptr;
1071 }
1072 break;
1073 }
1074 fScanNoPoints = ival;
1075 }
1076 }
1077
1078 if (tokens) {
1079 delete tokens;
1080 tokens = nullptr;
1081 }
1082 } else if (line.Contains("EIGEN", TString::kIgnoreCase)) {
1083 cmd.first = PMN_EIGEN;
1084 cmd.second = cmdLineNo;
1085 fCmdList.push_back(cmd);
1086 } else if (line.Contains("FIT_RANGE", TString::kIgnoreCase)) {
1087 // check the 5 options:
1088 // (i) FIT_RANGE RESET,
1089 // (ii) FIT_RANGE start end,
1090 // (iii) FIT_RANGE start1 end1 start2 end2 ... startN endN
1091 // (iv) FIT_RANGE fgb+n0 lgb-n1
1092 // (v) FIT_RANGE fgb+n00 lgb-n01 fgb+n10 lgb-n11 ... fgb+nN0 lgb-nN1
1093 TObjArray *tokens = nullptr;
1094 TObjString *ostr;
1095 TString str;
1096
1097 tokens = line.Tokenize(", \t");
1098
1099 if (tokens->GetEntries() == 2) { // should only be RESET
1100 ostr = dynamic_cast<TObjString*>(tokens->At(1));
1101 str = ostr->GetString();
1102 if (str.Contains("RESET", TString::kIgnoreCase)) {
1103 cmd.first = PMN_FIT_RANGE;
1104 cmd.second = cmdLineNo;
1105 fCmdList.push_back(cmd);
1106 } else {
1107 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1108 std::cerr << std::endl << ">> " << line.Data();
1109 std::cerr << std::endl << ">> Syntax: FIT_RANGE RESET | FIT_RANGE start end | FIT_RANGE s1 e1 s2 e2 .. sN eN,";
1110 std::cerr << std::endl << ">> with N the number of runs in the msr-file." << std::endl;
1111 std::cerr << std::endl << ">> Found " << str.Data() << ", instead of RESET" << std::endl;
1112 fIsValid = false;
1113 if (tokens) {
1114 delete tokens;
1115 tokens = nullptr;
1116 }
1117 break;
1118 }
1119 } else if ((tokens->GetEntries() > 1) && (static_cast<UInt_t>(tokens->GetEntries()) % 2) == 1) {
1120 if ((tokens->GetEntries() > 3) && ((static_cast<UInt_t>(tokens->GetEntries())-1)) != 2*fRunInfo->GetMsrRunList()->size()) {
1121 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1122 std::cerr << std::endl << ">> " << line.Data();
1123 std::cerr << std::endl << ">> Syntax: FIT_RANGE RESET | FIT_RANGE <start> <end> | FIT_RANGE <s1> <e1> <s2> <e2> .. <sN> <eN> |";
1124 std::cerr << std::endl << ">> FIT_RANGE fgb+<n0> lgb-<n1> | FIT_RANGE fgb+<n00> lgb-<n01> fgb+<n10> lgb-<n11> ... fgb+<nN0> lgb-<nN1>,";
1125 std::cerr << std::endl << ">> with N the number of runs in the msr-file.";
1126 std::cerr << std::endl << ">> Found N=" << (tokens->GetEntries()-1)/2 << ", # runs in msr-file=" << fRunInfo->GetMsrRunList()->size() << std::endl;
1127 fIsValid = false;
1128 if (tokens) {
1129 delete tokens;
1130 tokens = nullptr;
1131 }
1132 break;
1133 } else {
1134 // check that all range entries are numbers or fgb+n0 / lgb-n1
1135 Bool_t ok = true;
1136 for (Int_t n=1; n<tokens->GetEntries(); n++) {
1137 ostr = dynamic_cast<TObjString*>(tokens->At(n));
1138 str = ostr->GetString();
1139 if (!str.IsFloat()) {
1140 if ((n%2 == 1) && (!str.Contains("fgb", TString::kIgnoreCase)))
1141 ok = false;
1142 if ((n%2 == 0) && (!str.Contains("lgb", TString::kIgnoreCase)))
1143 ok = false;
1144 }
1145 if (!ok)
1146 break;
1147 }
1148
1149 if (ok) { // everything is fine
1150 cmd.first = PMN_FIT_RANGE;
1151 cmd.second = cmdLineNo;
1152 fCmdList.push_back(cmd);
1153 } else {
1154 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1155 std::cerr << std::endl << ">> " << line.Data();
1156 std::cerr << std::endl << ">> Syntax: FIT_RANGE RESET | FIT_RANGE <start> <end> | FIT_RANGE <s1> <e1> <s2> <e2> .. <sN> <eN> |";
1157 std::cerr << std::endl << ">> FIT_RANGE fgb+<n0> lgb-<n1> | FIT_RANGE fgb+<n00> lgb-<n01> fgb+<n10> lgb-<n11> ... fgb+<nN0> lgb-<nN1>,";
1158 std::cerr << std::endl << ">> with N the number of runs in the msr-file.";
1159 std::cerr << std::endl << ">> Found token '" << str.Data() << "', which is not a floating point number." << std::endl;
1160 fIsValid = false;
1161 if (tokens) {
1162 delete tokens;
1163 tokens = nullptr;
1164 }
1165 break;
1166 }
1167 }
1168 } else {
1169 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1170 std::cerr << std::endl << ">> " << line.Data();
1171 std::cerr << std::endl << ">> Syntax: FIT_RANGE RESET | FIT_RANGE <start> <end> | FIT_RANGE <s1> <e1> <s2> <e2> .. <sN> <eN> |";
1172 std::cerr << std::endl << ">> FIT_RANGE fgb+<n0> lgb-<n1> | FIT_RANGE fgb+<n00> lgb-<n01> fgb+<n10> lgb-<n11> ... fgb+<nN0> lgb-<nN1>,";
1173 std::cerr << std::endl << ">> with N the number of runs in the msr-file.";
1174 fIsValid = false;
1175 if (tokens) {
1176 delete tokens;
1177 tokens = nullptr;
1178 }
1179 break;
1180 }
1181
1182 if (tokens) {
1183 delete tokens;
1184 tokens = nullptr;
1185 }
1186 } else if (line.Contains("FIX", TString::kIgnoreCase)) {
1187 // check if the given set of parameters (number or names) is present
1188 TObjArray *tokens = nullptr;
1189 TObjString *ostr;
1190 TString str;
1191 UInt_t ival;
1192
1193 tokens = line.Tokenize(", \t");
1194
1195 for (Int_t i=1; i<tokens->GetEntries(); i++) {
1196 ostr = dynamic_cast<TObjString*>(tokens->At(i));
1197 str = ostr->GetString();
1198
1199 if (str.IsDigit()) { // token might be a parameter number
1200 ival = str.Atoi();
1201 // check that ival is in the parameter list
1202 if (ival > fParams.size()) {
1203 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1204 std::cerr << std::endl << ">> " << line.Data();
1205 std::cerr << std::endl << ">> Parameter " << ival << " is out of the Parameter Range [1," << fParams.size() << "]";
1206 std::cerr << std::endl;
1207 fIsValid = false;
1208 if (tokens) {
1209 delete tokens;
1210 tokens = nullptr;
1211 }
1212 break;
1213 }
1214 } else { // token might be a parameter name
1215 // check if token is present as parameter name
1216 Bool_t found = false;
1217 for (UInt_t j=0; j<fParams.size(); j++) {
1218 if (fParams[j].fName.CompareTo(str, TString::kIgnoreCase) == 0) { // found
1219 found = true;
1220 break;
1221 }
1222 }
1223 if (!found) {
1224 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1225 std::cerr << std::endl << ">> " << line.Data();
1226 std::cerr << std::endl << ">> Parameter '" << str.Data() << "' is NOT present as a parameter name";
1227 std::cerr << std::endl;
1228 fIsValid = false;
1229 if (tokens) {
1230 delete tokens;
1231 tokens = nullptr;
1232 }
1233 break;
1234 }
1235 }
1236 }
1237
1238 if (tokens) {
1239 delete tokens;
1240 tokens = nullptr;
1241 }
1242
1243 // everything looks fine, feed the command list
1244 cmd.first = PMN_FIX;
1245 cmd.second = cmdLineNo;
1246 fCmdList.push_back(cmd);
1247 } else if (line.Contains("HESSE", TString::kIgnoreCase)) {
1248 fIsScanOnly = false;
1249 cmd.first = PMN_HESSE;
1250 cmd.second = cmdLineNo;
1251 fCmdList.push_back(cmd);
1252 } else if (line.Contains("MACHINE_PRECISION", TString::kIgnoreCase)) {
1253 cmd.first = PMN_MACHINE_PRECISION;
1254 cmd.second = cmdLineNo;
1255 fCmdList.push_back(cmd);
1256 } else if (line.Contains("MIGRAD", TString::kIgnoreCase)) {
1257 fIsScanOnly = false;
1258 cmd.first = PMN_MIGRAD;
1259 cmd.second = cmdLineNo;
1260 fCmdList.push_back(cmd);
1261 } else if (line.Contains("MINIMIZE", TString::kIgnoreCase)) {
1262 fIsScanOnly = false;
1263 cmd.first = PMN_MINIMIZE;
1264 cmd.second = cmdLineNo;
1265 fCmdList.push_back(cmd);
1266 } else if (line.Contains("MINOS", TString::kIgnoreCase)) {
1267 fIsScanOnly = false;
1268 cmd.first = PMN_MINOS;
1269 cmd.second = cmdLineNo;
1270 fCmdList.push_back(cmd);
1271 } else if (line.Contains("MNPLOT", TString::kIgnoreCase)) {
1272 cmd.first = PMN_PLOT;
1273 cmd.second = cmdLineNo;
1274 fCmdList.push_back(cmd);
1275 } else if (line.Contains("PRINT_LEVEL", TString::kIgnoreCase)) {
1276 cmd.first = PMN_PRINT;
1277 cmd.second = cmdLineNo;
1278 fCmdList.push_back(cmd);
1279 } else if (line.Contains("RELEASE", TString::kIgnoreCase)) {
1280 // check if the given set of parameters (number or names) is present
1281 TObjArray *tokens = nullptr;
1282 TObjString *ostr;
1283 TString str;
1284 UInt_t ival;
1285
1286 tokens = line.Tokenize(", \t");
1287
1288 for (Int_t i=1; i<tokens->GetEntries(); i++) {
1289 ostr = dynamic_cast<TObjString*>(tokens->At(i));
1290 str = ostr->GetString();
1291
1292 if (str.IsDigit()) { // token might be a parameter number
1293 ival = str.Atoi();
1294 // check that ival is in the parameter list
1295 if (ival > fParams.size()) {
1296 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1297 std::cerr << std::endl << ">> " << line.Data();
1298 std::cerr << std::endl << ">> Parameter " << ival << " is out of the Parameter Range [1," << fParams.size() << "]";
1299 std::cerr << std::endl;
1300 fIsValid = false;
1301 if (tokens) {
1302 delete tokens;
1303 tokens = nullptr;
1304 }
1305 break;
1306 }
1307 } else { // token might be a parameter name
1308 // check if token is present as parameter name
1309 Bool_t found = false;
1310 for (UInt_t j=0; j<fParams.size(); j++) {
1311 if (fParams[j].fName.CompareTo(str, TString::kIgnoreCase) == 0) { // found
1312 found = true;
1313 break;
1314 }
1315 }
1316 if (!found) {
1317 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1318 std::cerr << std::endl << ">> " << line.Data();
1319 std::cerr << std::endl << ">> Parameter '" << str.Data() << "' is NOT present as a parameter name";
1320 std::cerr << std::endl;
1321 fIsValid = false;
1322 if (tokens) {
1323 delete tokens;
1324 tokens = nullptr;
1325 }
1326 break;
1327 }
1328 }
1329 }
1330
1331 if (tokens) {
1332 delete tokens;
1333 tokens = nullptr;
1334 }
1335 cmd.first = PMN_RELEASE;
1336 cmd.second = cmdLineNo;
1337 fCmdList.push_back(cmd);
1338 } else if (line.Contains("RESTORE", TString::kIgnoreCase)) {
1339 cmd.first = PMN_RESTORE;
1340 cmd.second = cmdLineNo;
1341 fCmdList.push_back(cmd);
1342 } else if (line.Contains("SAVE", TString::kIgnoreCase)) {
1343 cmd.first = PMN_SAVE;
1344 cmd.second = cmdLineNo;
1345 fCmdList.push_back(cmd);
1346 } else if (line.Contains("SCAN", TString::kIgnoreCase)) {
1347 cmd.first = PMN_SCAN;
1348 cmd.second = cmdLineNo;
1349 fCmdList.push_back(cmd);
1350 // filter out possible parameters for scan
1351 TObjArray *tokens = nullptr;
1352 TObjString *ostr;
1353 TString str;
1354 UInt_t ival;
1355
1356 tokens = line.Tokenize(", \t");
1357
1358 for (Int_t i=0; i<tokens->GetEntries(); i++) {
1359 ostr = dynamic_cast<TObjString*>(tokens->At(i));
1360 str = ostr->GetString();
1361 if (i==1) { // get parameter number
1362 // check that token is a UInt_t
1363 if (!str.IsDigit()) {
1364 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1365 std::cerr << std::endl << ">> " << line.Data();
1366 std::cerr << std::endl << ">> parameter number is not number!";
1367 std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]";
1368 std::cerr << std::endl;
1369 fIsValid = false;
1370 if (tokens) {
1371 delete tokens;
1372 tokens = nullptr;
1373 }
1374 break;
1375 }
1376 ival = str.Atoi();
1377 // check that parameter is within range
1378 if ((ival < 1) || (ival > fParams.size())) {
1379 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1380 std::cerr << std::endl << ">> " << line.Data();
1381 std::cerr << std::endl << ">> parameter number is out of range [1," << fParams.size() << "]!";
1382 std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]";
1383 std::cerr << std::endl;
1384 fIsValid = false;
1385 if (tokens) {
1386 delete tokens;
1387 tokens = nullptr;
1388 }
1389 break;
1390 }
1391 // keep parameter
1392 fScanParameter[0] = ival-1; // internally parameter number starts at 0
1393 fScanAll = false;
1394 }
1395
1396 if (i==2) { // get number of points
1397 // check that token is a UInt_t
1398 if (!str.IsDigit()) {
1399 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1400 std::cerr << std::endl << ">> " << line.Data();
1401 std::cerr << std::endl << ">> number of points is not number!";
1402 std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]";
1403 std::cerr << std::endl;
1404 fIsValid = false;
1405 if (tokens) {
1406 delete tokens;
1407 tokens = nullptr;
1408 }
1409 break;
1410 }
1411 ival = str.Atoi();
1412 if ((ival < 1) || (ival > 100)) {
1413 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1414 std::cerr << std::endl << ">> " << line.Data();
1415 std::cerr << std::endl << ">> number of scan points is out of range [1,100]!";
1416 std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]";
1417 std::cerr << std::endl;
1418 fIsValid = false;
1419 if (tokens) {
1420 delete tokens;
1421 tokens = nullptr;
1422 }
1423 break;
1424 }
1425 fScanNoPoints = ival;
1426 }
1427
1428 if (i==3) { // get low
1429 // check that token is a Double_t
1430 if (!str.IsFloat()) {
1431 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1432 std::cerr << std::endl << ">> " << line.Data();
1433 std::cerr << std::endl << ">> low is not a floating point number!";
1434 std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]";
1435 std::cerr << std::endl;
1436 fIsValid = false;
1437 if (tokens) {
1438 delete tokens;
1439 tokens = nullptr;
1440 }
1441 break;
1442 }
1443 fScanLow = str.Atof();
1444 }
1445
1446 if (i==4) { // get high
1447 // check that token is a Double_t
1448 if (!str.IsFloat()) {
1449 std::cerr << std::endl << ">> PFitter::CheckCommands: **ERROR** in line " << it->fLineNo;
1450 std::cerr << std::endl << ">> " << line.Data();
1451 std::cerr << std::endl << ">> high is not a floating point number!";
1452 std::cerr << std::endl << ">> command syntax for SCAN is: SCAN [parameter no [# of points [low high]]]";
1453 std::cerr << std::endl;
1454 fIsValid = false;
1455 if (tokens) {
1456 delete tokens;
1457 tokens = nullptr;
1458 }
1459 break;
1460 }
1461 fScanHigh = str.Atof();
1462 }
1463 }
1464
1465 if (tokens) {
1466 delete tokens;
1467 tokens = nullptr;
1468 }
1469 } else if (line.Contains("SIMPLEX", TString::kIgnoreCase)) {
1470 cmd.first = PMN_SIMPLEX;
1471 cmd.second = cmdLineNo;
1472 fCmdList.push_back(cmd);
1473 } else if (line.Contains("STRATEGY", TString::kIgnoreCase)) {
1474 TObjArray *tokens = nullptr;
1475 TObjString *ostr;
1476 TString str;
1477
1478 tokens = line.Tokenize(" \t");
1479 if (tokens->GetEntries() == 2) {
1480 ostr = dynamic_cast<TObjString*>(tokens->At(1));
1481 str = ostr->GetString();
1482 if (str.CompareTo("0") == 0) { // low
1483 fStrategy = 0;
1484 } else if (str.CompareTo("1") == 0) { // default
1485 fStrategy = 1;
1486 } else if (str.CompareTo("2") == 0) { // high
1487 fStrategy = 2;
1488 } else if (str.CompareTo("LOW") == 0) { // low
1489 fStrategy = 0;
1490 } else if (str.CompareTo("DEFAULT") == 0) { // default
1491 fStrategy = 1;
1492 } else if (str.CompareTo("HIGH") == 0) { // high
1493 fStrategy = 2;
1494 }
1495 }
1496
1497 if (tokens) {
1498 delete tokens;
1499 tokens = nullptr;
1500 }
1501 } else if (line.Contains("USER_COVARIANCE", TString::kIgnoreCase)) {
1502 cmd.first = PMN_USER_COVARIANCE;
1503 cmd.second = cmdLineNo;
1504 fCmdList.push_back(cmd);
1505 } else if (line.Contains("USER_PARAM_STATE", TString::kIgnoreCase)) {
1506 cmd.first = PMN_USER_PARAM_STATE;
1507 cmd.second = cmdLineNo;
1508 fCmdList.push_back(cmd);
1509 } else if (line.Contains("SECTOR", TString::kIgnoreCase)) {
1510 fSectorFlag = true;
1511 cmd.first = PMN_SECTOR;
1512 cmd.second = cmdLineNo;
1513 fCmdList.push_back(cmd);
1514
1515 // check if the given sector arguments are valid time stamps, i.e. doubles and value < lgb time stamp
1516 TObjArray *tokens = nullptr;
1517 TObjString *ostr;
1518 TString str;
1519
1520 tokens = line.Tokenize(" ,\t");
1521
1522 if (tokens->GetEntries() == 1) { // no sector time stamps given -> issue an error
1523 std::cerr << std::endl << ">> PFitter::CheckCommands(): **FATAL ERROR** in line " << it->fLineNo;
1524 std::cerr << std::endl << ">> " << line.Data();
1525 std::cerr << std::endl << ">> At least one sector time stamp is expected.";
1526 std::cerr << std::endl << ">> Will stop ...";
1527 std::cerr << std::endl;
1528 // cleanup
1529 if (tokens) {
1530 delete tokens;
1531 tokens = nullptr;
1532 }
1533 fIsValid = false;
1534 fSectorFlag = false;
1535 break;
1536 }
1537
1538 Double_t dval;
1539 for (Int_t i=1; i<tokens->GetEntries(); i++) {
1540 // keep time range of sector
1541 PSectorChisq sec(fRunInfo->GetNoOfRuns());
1542 // get parse tokens
1543 ostr = dynamic_cast<TObjString*>(tokens->At(i));
1544 str = ostr->GetString();
1545 if (str.IsFloat()) {
1546 dval = str.Atof();
1547 // check that the sector time stamp is smaller than all lgb time stamps
1548 for (UInt_t j=0; j<fOriginalFitRange.size(); j++) {
1549 if (dval > fOriginalFitRange[j].second) {
1550 std::cerr << std::endl << ">> PFitter::CheckCommands(): **FATAL ERROR** in line " << it->fLineNo;
1551 std::cerr << std::endl << ">> " << line.Data();
1552 std::cerr << std::endl << ">> The sector time stamp " << dval << " is > as the lgb time stamp (" << fOriginalFitRange[j].second << ") of run " << j << ".";
1553 std::cerr << std::endl << ">> Will stop ...";
1554 std::cerr << std::endl;
1555 // cleanup
1556 if (tokens) {
1557 delete tokens;
1558 tokens = nullptr;
1559 }
1560 fIsValid = false;
1561 fSectorFlag = false;
1562 return fIsValid;
1563 }
1564 sec.SetRunFirstTime(fOriginalFitRange[j].first, j); // keep fgb time stamp for sector
1565 }
1566 sec.SetSectorTime(dval);
1567 fSector.push_back(sec);
1568 } else { // sector element is NOT a float
1569 std::cerr << std::endl << ">> PFitter::CheckCommands(): **FATAL ERROR** in line " << it->fLineNo;
1570 std::cerr << std::endl << ">> " << line.Data();
1571 std::cerr << std::endl << ">> The sector time stamp '" << str << "' is not a number.";
1572 std::cerr << std::endl << ">> Will stop ...";
1573 std::cerr << std::endl;
1574 // cleanup
1575 if (tokens) {
1576 delete tokens;
1577 tokens = nullptr;
1578 }
1579 fIsValid = false;
1580 fSectorFlag = false;
1581 break;
1582 }
1583 }
1584
1585 if (tokens) {
1586 delete tokens;
1587 tokens = nullptr;
1588 }
1589 } else { // unkown command
1590 std::cerr << std::endl << ">> PFitter::CheckCommands(): **FATAL ERROR** in line " << it->fLineNo << " an unkown command is found:";
1591 std::cerr << std::endl << ">> " << line.Data();
1592 std::cerr << std::endl << ">> Will stop ...";
1593 std::cerr << std::endl;
1594 fIsValid = false;
1595 break;
1596 }
1597 }
1598
1599 // Check that in case release/restore is present, that it is followed by a minimizer before minos is called.
1600 // If this is not the case, place a warning
1601 Bool_t fixFlag = false;
1602 Bool_t releaseFlag = false;
1603 Bool_t minimizerFlag = false;
1604 for (it = fCmdLines.begin(); it != fCmdLines.end(); ++it) {
1605 if (line.Contains("FIX", TString::kIgnoreCase))
1606 fixFlag = true;
1607 else if (line.Contains("RELEASE", TString::kIgnoreCase) ||
1608 line.Contains("RESTORE", TString::kIgnoreCase))
1609 releaseFlag = true;
1610 else if (line.Contains("MINIMIZE", TString::kIgnoreCase) ||
1611 line.Contains("MIGRAD", TString::kIgnoreCase) ||
1612 line.Contains("SIMPLEX", TString::kIgnoreCase)) {
1613 if (releaseFlag)
1614 minimizerFlag = true;
1615 } else if (line.Contains("MINOS", TString::kIgnoreCase)) {
1616 if (fixFlag && releaseFlag && !minimizerFlag) {
1617 std::cerr << std::endl << ">> PFitter::CheckCommands(): **WARNING** RELEASE/RESTORE command present";
1618 std::cerr << std::endl << ">> without minimizer command (MINIMIZE/MIGRAD/SIMPLEX) between";
1619 std::cerr << std::endl << ">> RELEASE/RESTORE and MINOS. Behaviour might be different to the";
1620 std::cerr << std::endl << ">> expectation of the user ?!?" << std::endl;
1621 }
1622 fixFlag = false;
1623 releaseFlag = false;
1624 minimizerFlag = false;
1625 }
1626 }
1627
1628 return fIsValid;
1629}
1630
1631//--------------------------------------------------------------------------
1632// SetParameters
1633//--------------------------------------------------------------------------
1641{
1642 for (UInt_t i=0; i<fParams.size(); i++) {
1643 // check if parameter is fixed
1644 if (fParams[i].fStep == 0.0) { // add fixed parameter
1645 fMnUserParams.Add(fParams[i].fName.Data(), fParams[i].fValue);
1646 } else { // add free parameter
1647 // check if boundaries are given
1648 if (fParams[i].fNoOfParams > 5) { // boundaries given
1649 if (fParams[i].fLowerBoundaryPresent &&
1650 fParams[i].fUpperBoundaryPresent) { // upper and lower boundaries given
1651 fMnUserParams.Add(fParams[i].fName.Data(), fParams[i].fValue, fParams[i].fStep,
1652 fParams[i].fLowerBoundary, fParams[i].fUpperBoundary);
1653 } else if (fParams[i].fLowerBoundaryPresent &&
1654 !fParams[i].fUpperBoundaryPresent) { // lower boundary limited
1655 fMnUserParams.Add(fParams[i].fName.Data(), fParams[i].fValue, fParams[i].fStep);
1656 fMnUserParams.SetLowerLimit(fParams[i].fName.Data(), fParams[i].fLowerBoundary);
1657 } else { // upper boundary limited
1658 fMnUserParams.Add(fParams[i].fName.Data(), fParams[i].fValue, fParams[i].fStep);
1659 fMnUserParams.SetUpperLimit(fParams[i].fName.Data(), fParams[i].fUpperBoundary);
1660 }
1661 } else { // no boundaries given
1662 fMnUserParams.Add(fParams[i].fName.Data(), fParams[i].fValue, fParams[i].fStep);
1663 }
1664 }
1665 }
1666
1667 // check if there is an unused parameter, if so, fix it
1668 for (UInt_t i=0; i<fParams.size(); i++) {
1669 // parameter not used in the whole theory and not already fixed!!
1670 if ((fRunInfo->ParameterInUse(i) == 0) && (fParams[i].fStep != 0.0)) {
1671 fMnUserParams.Fix(i); // fix the unused parameter so that minuit will not vary it
1672 std::cerr << std::endl << "**WARNING** : Parameter No " << i+1 << " is not used at all, will fix it";
1673 std::cerr << std::endl;
1674 }
1675 }
1676
1677 return true;
1678}
1679
1680//--------------------------------------------------------------------------
1681// ExecuteContours
1682//--------------------------------------------------------------------------
1689{
1690 std::cout << ">> PFitter::ExecuteContours() ..." << std::endl;
1691
1692 // if already some minimization is done use the minuit2 output as input
1693 if (!fFcnMin) {
1694 std::cerr << std::endl << "**WARNING**: CONTOURS musn't be called before any minimization (MINIMIZE/MIGRAD/SIMPLEX) is done!!";
1695 std::cerr << std::endl;
1696 return false;
1697 }
1698
1699 // check if minimum was valid
1700 if (!fFcnMin->IsValid()) {
1701 std::cerr << std::endl << "**ERROR**: CONTOURS cannot started since the previous minimization failed :-(";
1702 std::cerr << std::endl;
1703 return false;
1704 }
1705
1706 ROOT::Minuit2::MnContours contours((*fFitterFcn), *fFcnMin);
1707
1709
1710 return true;
1711}
1712
1713//--------------------------------------------------------------------------
1714// ExecuteFitRange
1715//--------------------------------------------------------------------------
1723Bool_t PFitter::ExecuteFitRange(UInt_t lineNo)
1724{
1725 std::cout << ">> PFitter::ExecuteFitRange(): " << fCmdLines[lineNo].fLine.Data() << std::endl;
1726
1727 if (fCmdLines[lineNo].fLine.Contains("fgb", TString::kIgnoreCase)) { // fit range given in bins
1728 fRunListCollection->SetFitRange(fCmdLines[lineNo].fLine);
1729 return true;
1730 }
1731
1732 TObjArray *tokens = nullptr;
1733 TObjString *ostr;
1734 TString str;
1735
1736 tokens = fCmdLines[lineNo].fLine.Tokenize(", \t");
1737
1738 PMsrRunList *runList = fRunInfo->GetMsrRunList();
1739
1740 // execute command, no error checking needed since this has been already carried out in CheckCommands()
1741 if (tokens->GetEntries() == 2) { // reset command
1743 } else if (tokens->GetEntries() == 3) { // single fit range for all runs
1744 Double_t start = 0.0, end = 0.0;
1745 PDoublePair fitRange;
1746 PDoublePairVector fitRangeVector;
1747
1748 ostr = dynamic_cast<TObjString*>(tokens->At(1));
1749 str = ostr->GetString();
1750 start = str.Atof();
1751 ostr = dynamic_cast<TObjString*>(tokens->At(2));
1752 str = ostr->GetString();
1753 end = str.Atof();
1754
1755 fitRange.first = start;
1756 fitRange.second = end;
1757 fitRangeVector.push_back(fitRange);
1758 fRunListCollection->SetFitRange(fitRangeVector);
1759
1760 } else { // individual fit ranges for each run
1761 Double_t start = 0.0, end = 0.0;
1762 PDoublePair fitRange;
1763 PDoublePairVector fitRangeVector;
1764
1765 for (UInt_t i=0; i<runList->size(); i++) {
1766 ostr = dynamic_cast<TObjString*>(tokens->At(2*i+1));
1767 str = ostr->GetString();
1768 start = str.Atof();
1769 ostr = dynamic_cast<TObjString*>(tokens->At(2*i+2));
1770 str = ostr->GetString();
1771 end = str.Atof();
1772
1773 fitRange.first = start;
1774 fitRange.second = end;
1775 fitRangeVector.push_back(fitRange);
1776 }
1777
1778 fRunListCollection->SetFitRange(fitRangeVector);
1779 }
1780
1781 return true;
1782}
1783
1784//--------------------------------------------------------------------------
1785// ExecuteFix
1786//--------------------------------------------------------------------------
1794Bool_t PFitter::ExecuteFix(UInt_t lineNo)
1795{
1796 std::cout << ">> PFitter::ExecuteFix(): " << fCmdLines[lineNo].fLine.Data() << std::endl;
1797
1798 TObjArray *tokens = nullptr;
1799 TObjString *ostr;
1800 TString str;
1801
1802 tokens = fCmdLines[lineNo].fLine.Tokenize(", \t");
1803
1804 for (Int_t i=1; i<tokens->GetEntries(); i++) {
1805 ostr = dynamic_cast<TObjString*>(tokens->At(i));
1806 str = ostr->GetString();
1807
1808 if (str.IsDigit()) { // token is a parameter number
1809 fMnUserParams.Fix(static_cast<UInt_t>(str.Atoi())-1);
1810 } else { // token is a parameter name
1811 fMnUserParams.Fix(str.Data());
1812 }
1813 }
1814
1815 // clean up
1816 if (tokens) {
1817 delete tokens;
1818 tokens = nullptr;
1819 }
1820
1821 return true;
1822}
1823
1824//--------------------------------------------------------------------------
1825// ExecuteHesse
1826//--------------------------------------------------------------------------
1833{
1834 std::cout << ">> PFitter::ExecuteHesse(): will call hesse ..." << std::endl;
1835
1836 // create the hesse object
1837 ROOT::Minuit2::MnHesse hesse;
1838
1839 // specify maximal number of function calls
1840 UInt_t maxfcn = std::numeric_limits<UInt_t>::max();
1841
1842 // call hesse
1843 Double_t start=0.0, end=0.0;
1844 start=MilliTime();
1845 ROOT::Minuit2::MnUserParameterState mnState = hesse((*fFitterFcn), fMnUserParams, maxfcn);
1846 end=MilliTime();
1847 std::cout << ">> PFitter::ExecuteMinimize(): execution time for Hesse = " << std::setprecision(3) << (end-start)/1.0e3 << " sec." << std::endl;
1848 TString str = TString::Format("Hesse: %.3f sec", (end-start)/1.0e3);
1849 fElapsedTime.push_back(str);
1850 if (!mnState.IsValid()) {
1851 std::cerr << std::endl << ">> PFitter::ExecuteHesse(): **WARNING** Hesse encountered a problem! The state found is invalid.";
1852 std::cerr << std::endl;
1853 return false;
1854 }
1855 if (!mnState.HasCovariance()) {
1856 std::cerr << std::endl << ">> PFitter::ExecuteHesse(): **WARNING** Hesse encountered a problem! No covariance matrix available.";
1857 std::cerr << std::endl;
1858 return false;
1859 }
1860
1861 // fill parabolic errors
1862 for (UInt_t i=0; i<fParams.size(); i++) {
1863 fRunInfo->SetMsrParamStep(i, mnState.Error(i));
1864 fRunInfo->SetMsrParamPosErrorPresent(i, false);
1865 }
1866
1867 if (fPrintLevel >= 2)
1868 std::cout << mnState << std::endl;
1869
1870 return true;
1871}
1872
1873//--------------------------------------------------------------------------
1874// ExecuteMigrad
1875//--------------------------------------------------------------------------
1882{
1883 std::cout << ">> PFitter::ExecuteMigrad(): will call migrad ..." << std::endl;
1884
1885 // create migrad object
1886 // strategy is by default = 'default'
1887 ROOT::Minuit2::MnMigrad migrad((*fFitterFcn), fMnUserParams, ROOT::Minuit2::MnStrategy{fStrategy});
1888
1889 // minimize
1890 // maxfcn is MINUIT2 Default maxfcn
1891 UInt_t maxfcn = std::numeric_limits<UInt_t>::max();
1892 // tolerance = MINUIT2 Default tolerance
1893 Double_t tolerance = 0.1;
1894 // keep track of elapsed time
1895 Double_t start=0.0, end=0.0;
1896 start=MilliTime();
1897 ROOT::Minuit2::FunctionMinimum min = migrad(maxfcn, tolerance);
1898 end=MilliTime();
1899 std::cout << ">> PFitter::ExecuteMinimize(): execution time for Migrad = " << std::setprecision(3) << (end-start)/1.0e3 << " sec." << std::endl;
1900 TString str = TString::Format("Migrad: %.3f sec", (end-start)/1.0e3);
1901 fElapsedTime.push_back(str);
1902 if (!min.IsValid()) {
1903 std::cerr << std::endl << ">> PFitter::ExecuteMigrad(): **WARNING**: Fit did not converge, sorry ...";
1904 std::cerr << std::endl;
1905 fIsValid = false;
1906 return false;
1907 }
1908
1909 // keep FunctionMinimum object
1910 fFcnMin.reset(new ROOT::Minuit2::FunctionMinimum(min));
1911
1912 // keep user parameters
1913 if (fFcnMin)
1914 fMnUserParams = fFcnMin->UserParameters();
1915
1916 // fill run info
1917 for (UInt_t i=0; i<fParams.size(); i++) {
1918 Double_t dval = min.UserState().Value(i);
1919 if (fPhase[i]) {
1920 Int_t m = (Int_t)(dval/360.0);
1921 dval = dval - m*360.0;
1922 }
1923 fRunInfo->SetMsrParamValue(i, dval);
1924 fRunInfo->SetMsrParamStep(i, min.UserState().Error(i));
1925 fRunInfo->SetMsrParamPosErrorPresent(i, false);
1926 }
1927
1928 // handle statistics
1929 Double_t minVal = min.Fval();
1930 UInt_t ndf = fFitterFcn->GetTotalNoOfFittedBins();
1931 // subtract number of varied parameters from total no of fitted bins -> ndf
1932 for (UInt_t i=0; i<fParams.size(); i++) {
1933 if ((min.UserState().Error(i) != 0.0) && !fMnUserParams.Parameters().at(i).IsFixed())
1934 ndf -= 1;
1935 }
1936
1937 // feed run info with new statistics info
1938 fRunInfo->SetMsrStatisticMin(minVal);
1939 fRunInfo->SetMsrStatisticNdf(ndf);
1940
1941 fConverged = true;
1942
1943 if (fPrintLevel >= 2)
1944 std::cout << *fFcnMin << std::endl;
1945
1946 return true;
1947}
1948
1949//--------------------------------------------------------------------------
1950// ExecuteMinimize
1951//--------------------------------------------------------------------------
1958{
1959 std::cout << ">> PFitter::ExecuteMinimize(): will call minimize ..." << std::endl;
1960
1961 // create minimizer object
1962 // strategy is by default = 'default'
1963 ROOT::Minuit2::MnMinimize minimize((*fFitterFcn), fMnUserParams, ROOT::Minuit2::MnStrategy{fStrategy});
1964
1965 // minimize
1966 // maxfcn is MINUIT2 Default maxfcn
1967 UInt_t maxfcn = std::numeric_limits<UInt_t>::max();
1968
1969 // tolerance = MINUIT2 Default tolerance
1970 Double_t tolerance = 0.1;
1971 // keep track of elapsed time
1972 Double_t start=0.0, end=0.0;
1973 start = MilliTime();
1974 ROOT::Minuit2::FunctionMinimum min = minimize(maxfcn, tolerance);
1975 end = MilliTime();
1976 std::cout << ">> PFitter::ExecuteMinimize(): execution time for Minimize = " << std::setprecision(3) << (end-start)/1.0e3 << " sec." << std::endl;
1977 TString str = TString::Format("Minimize: %.3f sec", (end-start)/1.0e3);
1978 fElapsedTime.push_back(str);
1979 if (!min.IsValid()) {
1980 std::cerr << std::endl << ">> PFitter::ExecuteMinimize(): **WARNING**: Fit did not converge, sorry ...";
1981 std::cerr << std::endl;
1982 fIsValid = false;
1983 return false;
1984 }
1985
1986 // keep FunctionMinimum object
1987 fFcnMin.reset(new ROOT::Minuit2::FunctionMinimum(min));
1988
1989 // keep user parameters
1990 if (fFcnMin)
1991 fMnUserParams = fFcnMin->UserParameters();
1992
1993 // fill run info
1994 for (UInt_t i=0; i<fParams.size(); i++) {
1995 Double_t dval = min.UserState().Value(i);
1996 if (fPhase[i]) {
1997 Int_t m = (Int_t)(dval/360.0);
1998 dval = dval - m*360.0;
1999 }
2000 fRunInfo->SetMsrParamValue(i, dval);
2001 fRunInfo->SetMsrParamStep(i, min.UserState().Error(i));
2002 fRunInfo->SetMsrParamPosErrorPresent(i, false);
2003 }
2004
2005 // handle statistics
2006 Double_t minVal = min.Fval();
2007 UInt_t ndf = fFitterFcn->GetTotalNoOfFittedBins();
2008 // subtract number of varied parameters from total no of fitted bins -> ndf
2009 for (UInt_t i=0; i<fParams.size(); i++) {
2010 if ((min.UserState().Error(i) != 0.0) && !fMnUserParams.Parameters().at(i).IsFixed())
2011 ndf -= 1;
2012 }
2013
2014 // feed run info with new statistics info
2015 fRunInfo->SetMsrStatisticMin(minVal);
2016 fRunInfo->SetMsrStatisticNdf(ndf);
2017
2018 fConverged = true;
2019
2020 if (fPrintLevel >= 2)
2021 std::cout << *fFcnMin << std::endl;
2022
2023 return true;
2024}
2025
2026//--------------------------------------------------------------------------
2027// ExecuteMinos
2028//--------------------------------------------------------------------------
2035{
2036 std::cout << ">> PFitter::ExecuteMinos(): will call minos ..." << std::endl;
2037
2038 // if already some minimization is done use the minuit2 output as input
2039 if (!fFcnMin) {
2040 std::cerr << std::endl << "**ERROR**: MINOS musn't be called before any minimization (MINIMIZE/MIGRAD/SIMPLEX) is done!!";
2041 std::cerr << std::endl;
2042 return false;
2043 }
2044
2045 // check if minimum was valid
2046 if (!fFcnMin->IsValid()) {
2047 std::cerr << std::endl << "**ERROR**: MINOS cannot started since the previous minimization failed :-(";
2048 std::cerr << std::endl;
2049 return false;
2050 }
2051
2052 // make minos analysis
2053 Double_t start=0.0, end=0.0;
2054 start=MilliTime();
2055 ROOT::Minuit2::MnMinos minos((*fFitterFcn), (*fFcnMin));
2056
2057 for (UInt_t i=0; i<fParams.size(); i++) {
2058 // only try to call minos if the parameter is not fixed!!
2059 // the 1st condition is from an user fixed variable,
2060 // the 2nd condition is from an all together unused variable
2061 // the 3rd condition is a variable fixed via the FIX command
2062 if ((fMnUserParams.Error(i) != 0.0) && (fRunInfo->ParameterInUse(i) != 0) && (!fMnUserParams.Parameters().at(i).IsFixed())) {
2063 std::cout << ">> PFitter::ExecuteMinos(): calculate errors for " << fParams[i].fName << std::endl;
2064
2065 // 1-sigma MINOS errors
2066 ROOT::Minuit2::MinosError err = minos.Minos(i);
2067
2068 if (err.IsValid()) {
2069 // fill msr-file structure
2070 fRunInfo->SetMsrParamStep(i, err.Lower());
2071 fRunInfo->SetMsrParamPosError(i, err.Upper());
2072 fRunInfo->SetMsrParamPosErrorPresent(i, true);
2073 } else {
2074 fRunInfo->SetMsrParamPosErrorPresent(i, false);
2075 }
2076 }
2077
2078 if (fMnUserParams.Parameters().at(i).IsFixed()) {
2079 std::cerr << std::endl << ">> PFitter::ExecuteMinos(): **WARNING** Parameter " << fMnUserParams.Name(i) << " (ParamNo " << i+1 << ") is fixed!";
2080 std::cerr << std::endl << ">> Will set STEP to zero, i.e. making it a constant parameter";
2081 std::cerr << std::endl;
2082 fRunInfo->SetMsrParamStep(i, 0.0);
2083 fRunInfo->SetMsrParamPosErrorPresent(i, false);
2084 }
2085 }
2086
2087 end=MilliTime();
2088 std::cout << ">> PFitter::ExecuteMinimize(): execution time for Minos = " << std::setprecision(3) << (end-start)/1.0e3 << " sec." << std::endl;
2089 TString str = TString::Format("Minos: %.3f sec", (end-start)/1.0e3);
2090 fElapsedTime.push_back(str);
2091
2092 return true;
2093}
2094
2095//--------------------------------------------------------------------------
2096// ExecutePlot
2097//--------------------------------------------------------------------------
2104{
2105 std::cout << ">> PFitter::ExecutePlot() ..." << std::endl;
2106
2107 ROOT::Minuit2::MnPlot plot;
2108 plot(fScanData);
2109
2110 return true;
2111}
2112
2113//--------------------------------------------------------------------------
2114// ExecutePrintLevel
2115//--------------------------------------------------------------------------
2123Bool_t PFitter::ExecutePrintLevel(UInt_t lineNo)
2124{
2125 std::cout << ">> PFitter::ExecutePrintLevel(): " << fCmdLines[lineNo].fLine.Data() << std::endl;
2126
2127 TObjArray *tokens = nullptr;
2128 TObjString *ostr;
2129 TString str;
2130
2131 tokens = fCmdLines[lineNo].fLine.Tokenize(", \t");
2132
2133 if (tokens->GetEntries() < 2) {
2134 std::cerr << std::endl << "**ERROR** from PFitter::ExecutePrintLevel(): SYNTAX: PRINT_LEVEL <N>, where <N>=0-3" << std::endl << std::endl;
2135 return false;
2136 }
2137
2138 ostr = (TObjString*)tokens->At(1);
2139 str = ostr->GetString();
2140
2141 Int_t ival;
2142 if (str.IsDigit()) {
2143 ival = str.Atoi();
2144 if ((ival >=0) && (ival <= 3)) {
2145 fPrintLevel = (UInt_t) ival;
2146 } else {
2147 std::cerr << std::endl << "**ERROR** from PFitter::ExecutePrintLevel(): SYNTAX: PRINT_LEVEL <N>, where <N>=0-3";
2148 std::cerr << std::endl << " found <N>=" << ival << std::endl << std::endl;
2149 return false;
2150 }
2151 } else {
2152 std::cerr << std::endl << "**ERROR** from PFitter::ExecutePrintLevel(): SYNTAX: PRINT_LEVEL <N>, where <N>=0-3" << std::endl << std::endl;
2153 return false;
2154 }
2155
2156#ifdef ROOT_GRTEQ_24
2157 ROOT::Minuit2::MnPrint::SetGlobalLevel(fPrintLevel);
2158#else
2159 ROOT::Minuit2::MnPrint::SetLevel(fPrintLevel);
2160#endif
2161
2162 // clean up
2163 if (tokens) {
2164 delete tokens;
2165 tokens = nullptr;
2166 }
2167
2168 return true;
2169}
2170
2171//--------------------------------------------------------------------------
2172// ExecuteRelease
2173//--------------------------------------------------------------------------
2181Bool_t PFitter::ExecuteRelease(UInt_t lineNo)
2182{
2183 TObjArray *tokens = nullptr;
2184 TObjString *ostr;
2185 TString str;
2186
2187 tokens = fCmdLines[lineNo].fLine.Tokenize(", \t");
2188
2189 std::cout << ">> PFitter::ExecuteRelease(): " << fCmdLines[lineNo].fLine.Data() << std::endl;
2190
2191 for (Int_t i=1; i<tokens->GetEntries(); i++) {
2192 ostr = dynamic_cast<TObjString*>(tokens->At(i));
2193 str = ostr->GetString();
2194
2195 if (str.IsDigit()) { // token is a parameter number
2196 fMnUserParams.Release(static_cast<UInt_t>(str.Atoi())-1);
2197 // set the error to 2% of the value when releasing
2198 fMnUserParams.SetError(static_cast<UInt_t>(str.Atoi())-1, 0.02*fMnUserParams.Value(static_cast<UInt_t>(str.Atoi())-1));
2199 } else { // token is a parameter name
2200 fMnUserParams.Release(str.Data());
2201 // set the error to 2% of the value when releasing
2202 fMnUserParams.SetError(str.Data(), 0.02*fMnUserParams.Value(str.Data()));
2203 }
2204 }
2205
2206 // clean up
2207 if (tokens) {
2208 delete tokens;
2209 tokens = nullptr;
2210 }
2211
2212 return true;
2213}
2214
2215//--------------------------------------------------------------------------
2216// ExecuteRestore
2217//--------------------------------------------------------------------------
2224{
2225 std::cout << "PFitter::ExecuteRestore(): release all fixed parameters (RESTORE) ..." << std::endl;
2226
2227 for (UInt_t i=0; i<fMnUserParams.Parameters().size(); i++) {
2228 if (fMnUserParams.Parameters().at(i).IsFixed()) {
2229 fMnUserParams.Release(i);
2230 fMnUserParams.SetError(i, 0.02*fMnUserParams.Value(i));
2231 }
2232 }
2233
2234 return true;
2235}
2236
2237//--------------------------------------------------------------------------
2238// ExecuteScan
2239//--------------------------------------------------------------------------
2246{
2247 std::cout << ">> PFitter::ExecuteScan(): will call scan ..." << std::endl;
2248
2249 ROOT::Minuit2::MnScan scan((*fFitterFcn), fMnUserParams);
2250
2251 if (fScanAll) { // not clear at the moment what to be done here
2252 // TO BE IMPLEMENTED
2253 } else { // single parameter scan
2255 }
2256
2257 fConverged = true;
2258
2259 return true;
2260}
2261
2262//--------------------------------------------------------------------------
2263// ExecuteSave
2264//--------------------------------------------------------------------------
2272Bool_t PFitter::ExecuteSave(Bool_t firstSave)
2273{
2274 // if any minimization was done, otherwise get out immediately
2275 if (!fFcnMin) {
2276 std::cout << std::endl << ">> PFitter::ExecuteSave(): nothing to be saved ...";
2277 return false;
2278 }
2279
2280 ROOT::Minuit2::MnUserParameterState mnState = fFcnMin->UserState();
2281
2282 // check if the user parameter state is valid
2283 if (!mnState.IsValid()) {
2284 std::cerr << std::endl << ">> PFitter::ExecuteSave: **WARNING** Minuit2 User Parameter State is not valid, i.e. nothing to be saved";
2285 std::cerr << std::endl;
2286 return false;
2287 }
2288
2289 // handle expected chisq if applicable
2290 fParams = *(fRunInfo->GetMsrParamList()); // get the update parameters back
2291
2292 // calculate expected chisq
2293 std::vector<Double_t> param;
2294 std::vector<Double_t> err;
2295 Double_t totalExpectedChisq = 0.0;
2296 std::vector<Double_t> expectedchisqPerRun;
2297 std::vector<UInt_t> ndfPerHisto;
2298
2299 for (UInt_t i=0; i<fParams.size(); i++) {
2300 param.push_back(fParams[i].fValue);
2301 err.push_back(fParams[i].fStep);
2302 }
2303
2304 // CalcExpectedChiSquare handles both, chisq and mlh
2305 Bool_t ok;
2306 PDoubleVector par_r = ParamRound(param, err, ok);
2307 if (!ok)
2308 par_r = param;
2309 fFitterFcn->CalcExpectedChiSquare(par_r, totalExpectedChisq, expectedchisqPerRun);
2310
2311 // calculate chisq per run
2312 std::vector<Double_t> chisqPerRun;
2313 for (UInt_t i=0; i<fRunInfo->GetMsrRunList()->size(); i++) {
2314 if (fUseChi2)
2315 chisqPerRun.push_back(fRunListCollection->GetSingleRunChisq(par_r, i));
2316 else
2317 chisqPerRun.push_back(fRunListCollection->GetSingleRunMaximumLikelihood(par_r, i));
2318 }
2319
2320 if (totalExpectedChisq != 0.0) { // i.e. applicable for single histogram fits only
2321 // get the ndf's of the histos
2322 UInt_t ndf_run;
2323 for (UInt_t i=0; i<expectedchisqPerRun.size(); i++) {
2324 ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i);
2325 ndfPerHisto.push_back(ndf_run);
2326 }
2327
2328 // feed the msr-file handler
2329 PMsrStatisticStructure *statistics = fRunInfo->GetMsrStatistic();
2330 if (statistics) {
2331 statistics->fMinPerHisto = chisqPerRun;
2332 statistics->fMinExpected = totalExpectedChisq;
2333 statistics->fMinExpectedPerHisto = expectedchisqPerRun;
2334 statistics->fNdfPerHisto = ndfPerHisto;
2335 }
2336 } else if (chisqPerRun.size() > 1) { // in case expected chisq is not applicable like for asymmetry fits
2337 UInt_t ndf_run = 0;
2338 for (UInt_t i=0; i<chisqPerRun.size(); i++) {
2339 ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i);
2340 ndfPerHisto.push_back(ndf_run);
2341 }
2342
2343 // feed the msr-file handler
2344 PMsrStatisticStructure *statistics = fRunInfo->GetMsrStatistic();
2345 if (statistics) {
2346 statistics->fMinPerHisto = chisqPerRun;
2347 statistics->fNdfPerHisto = ndfPerHisto;
2348 }
2349 }
2350
2351 // check if sector command has been requested
2352 if (fSectorFlag) {
2353 PDoubleVector error;
2354 for (UInt_t i=0; i<fParams.size(); i++)
2355 error.push_back(fParams[i].fStep);
2356
2357 PrepareSector(param, error);
2358 }
2359
2360 // clean up
2361 param.clear();
2362 expectedchisqPerRun.clear();
2363 ndfPerHisto.clear();
2364 chisqPerRun.clear();
2365
2366 std::cout << ">> PFitter::ExecuteSave(): will write minuit2 output file ..." << std::endl;
2367
2368 std::ofstream fout;
2369
2370 // open minuit2 output file
2371 if (firstSave)
2372 fout.open("MINUIT2.OUTPUT", std::iostream::out);
2373 else
2374 fout.open("MINUIT2.OUTPUT", std::iostream::out | std::iostream::app);
2375
2376 if (!fout.is_open()) {
2377 std::cerr << std::endl << "**ERROR** PFitter::ExecuteSave() couldn't open MINUIT2.OUTPUT file";
2378 std::cerr << std::endl;
2379 return false;
2380 }
2381
2382 // write header
2383 TDatime dt;
2384 fout << std::endl << "*************************************************************************";
2385 fout << std::endl << " musrfit MINUIT2 output file from " << fRunInfo->GetFileName().Data() << " - " << dt.AsSQLString();
2386 fout << std::endl << "*************************************************************************";
2387 fout << std::endl;
2388
2389 // write elapsed times
2390 fout << std::endl << " elapsed times:";
2391 for (UInt_t i=0; i<fElapsedTime.size(); i++) {
2392 fout << std::endl << " " << fElapsedTime[i];
2393 }
2394 fout << std::endl;
2395 fout << std::endl << "*************************************************************************";
2396 fout << std::endl;
2397 fElapsedTime.clear();
2398
2399 // write global information
2400 fout << std::endl << " Fval() = " << mnState.Fval() << ", Edm() = " << mnState.Edm() << ", NFcn() = " << mnState.NFcn();
2401 fout << std::endl;
2402 fout << std::endl << "*************************************************************************";
2403 fout << std::endl;
2404
2405 // identifiy the longest variable name for proper formating reasons
2406 Int_t maxLength = 10;
2407 for (UInt_t i=0; i<fParams.size(); i++) {
2408 if (fParams[i].fName.Length() > maxLength)
2409 maxLength = fParams[i].fName.Length() + 1;
2410 }
2411
2412 // write parameters
2413 fParams = *(fRunInfo->GetMsrParamList()); // get the update parameters back
2414 fout << std::endl << " PARAMETERS";
2415 fout << std::endl << "-------------------------------------------------------------------------";
2416 fout << std::endl << " ";
2417 for (Int_t j=0; j<=maxLength-4; j++)
2418 fout << " ";
2419 fout << "Parabolic Minos";
2420 fout << std::endl << " No Name";
2421 for (Int_t j=0; j<=maxLength-4; j++)
2422 fout << " ";
2423 fout << "Value Error Negative Positive Limits";
2424 for (UInt_t i=0; i<fParams.size(); i++) {
2425 // write no
2426 fout.setf(std::ios::right, std::ios::adjustfield);
2427 fout.width(3);
2428 fout << std::endl << i+1 << " ";
2429 // write name
2430 fout << fParams[i].fName.Data();
2431 for (Int_t j=0; j<=maxLength-fParams[i].fName.Length(); j++)
2432 fout << " ";
2433 // write value
2434 fout.setf(std::ios::left, std::ios::adjustfield);
2435 fout.precision(6);
2436 fout.width(10);
2437 fout << fParams[i].fValue << " ";
2438 // write parabolic error
2439 fout.setf(std::ios::left, std::ios::adjustfield);
2440 fout.precision(6);
2441 fout.width(10);
2442 if (fParams[i].fStep != 0.0)
2443 fout << fMnUserParams.Error(i) << " ";
2444 else
2445 fout << "---";
2446 // write minos errors
2447 if (fParams[i].fPosErrorPresent) {
2448 fout.setf(std::ios::left, std::ios::adjustfield);
2449 fout.precision(6);
2450 fout.width(12);
2451 fout << fParams[i].fStep;
2452 fout.setf(std::ios::left, std::ios::adjustfield);
2453 fout.precision(6);
2454 fout.width(11);
2455 fout << fParams[i].fPosError << " ";
2456 } else {
2457 fout.setf(std::ios::left, std::ios::adjustfield);
2458 fout.width(12);
2459 fout << "---";
2460 fout.setf(std::ios::left, std::ios::adjustfield);
2461 fout.width(12);
2462 fout << "---";
2463 }
2464 // write limits
2465 if (fParams[i].fNoOfParams > 5) {
2466 fout.setf(std::ios::left, std::ios::adjustfield);
2467 fout.width(7);
2468 if (fParams[i].fLowerBoundaryPresent)
2469 fout << fParams[i].fLowerBoundary;
2470 else
2471 fout << "---";
2472 fout.setf(std::ios::left, std::ios::adjustfield);
2473 fout.width(7);
2474 if (fParams[i].fUpperBoundaryPresent)
2475 fout << fParams[i].fUpperBoundary;
2476 else
2477 fout << "---";
2478 } else {
2479 fout.setf(std::ios::left, std::ios::adjustfield);
2480 fout.width(7);
2481 fout << "---";
2482 fout.setf(std::ios::left, std::ios::adjustfield);
2483 fout.width(7);
2484 fout << "---";
2485 }
2486 }
2487 fout << std::endl;
2488 fout << std::endl << "*************************************************************************";
2489
2490 // write covariance matrix
2491 fout << std::endl << " COVARIANCE MATRIX";
2492 fout << std::endl << "-------------------------------------------------------------------------";
2493 if (mnState.HasCovariance()) {
2494 ROOT::Minuit2::MnUserCovariance cov = mnState.Covariance();
2495 fout << std::endl << "from " << cov.Nrow() << " free parameters";
2496 for (UInt_t i=0; i<cov.Nrow(); i++) {
2497 fout << std::endl;
2498 for (UInt_t j=0; j<i; j++) {
2499 fout.setf(std::ios::left, std::ios::adjustfield);
2500 fout.precision(6);
2501 if (cov(i,j) > 0.0) {
2502 fout << " ";
2503 fout.width(13);
2504 } else {
2505 fout.width(14);
2506 }
2507 fout << cov(i,j);
2508 }
2509 }
2510 } else {
2511 fout << std::endl << " no covariance matrix available";
2512 }
2513 fout << std::endl;
2514 fout << std::endl << "*************************************************************************";
2515
2516 // write correlation matrix
2517 fout << std::endl << " CORRELATION COEFFICIENTS";
2518 fout << std::endl << "-------------------------------------------------------------------------";
2519 if (mnState.IsValid() && mnState.HasCovariance()) {
2520 ROOT::Minuit2::MnGlobalCorrelationCoeff corr = mnState.GlobalCC();
2521 ROOT::Minuit2::MnUserCovariance cov = mnState.Covariance();
2522 PIntVector parNo;
2523 fout << std::endl << " No Global ";
2524 for (UInt_t i=0; i<fParams.size(); i++) {
2525 // only free parameters, i.e. not fixed, and not unsed ones!
2526 if ((fParams[i].fStep != 0) && (fRunInfo->ParameterInUse(i) > 0) && (!fMnUserParams.Parameters().at(i).IsFixed())) {
2527 fout.setf(std::ios::left, std::ios::adjustfield);
2528 fout.width(9);
2529 fout << i+1;
2530 parNo.push_back(i);
2531 }
2532 }
2533 // check that there is a correspondens between minuit2 and musrfit book keeping
2534 if (parNo.size() != cov.Nrow()) {
2535 std::cerr << std::endl << "**SEVERE ERROR** in PFitter::ExecuteSave(): minuit2 and musrfit book keeping to not correspond! Unable to write correlation matrix.";
2536 std::cerr << std::endl;
2537 } else { // book keeping is OK
2538 TString title("Minuit2 Output Correlation Matrix for ");
2539 title += fRunInfo->GetFileName();
2540 title += " - ";
2541 title += dt.AsSQLString();
2542 std::unique_ptr<TCanvas> ccorr = std::make_unique<TCanvas>("ccorr", "title", 500, 500);
2543 std::unique_ptr<TH2D> hcorr = std::make_unique<TH2D>("hcorr", title, cov.Nrow(), 0.0, cov.Nrow(), cov.Nrow(), 0.0, cov.Nrow());
2544 Double_t dval;
2545 for (UInt_t i=0; i<cov.Nrow(); i++) {
2546 // parameter number
2547 fout << std::endl << " ";
2548 fout.setf(std::ios::left, std::ios::adjustfield);
2549 fout.width(5);
2550 fout << parNo[i]+1;
2551 // global correlation coefficient
2552 fout.setf(std::ios::left, std::ios::adjustfield);
2553 fout.precision(6);
2554 fout.width(12);
2555 fout << corr.GlobalCC()[i];
2556 // correlations matrix
2557 for (UInt_t j=0; j<cov.Nrow(); j++) {
2558 fout.setf(std::ios::left, std::ios::adjustfield);
2559// fout.precision(4);
2560 if (i==j) {
2561 fout.width(9);
2562 fout << " 1.0 ";
2563 hcorr->Fill((Double_t)i,(Double_t)i,1.0);
2564 } else {
2565 // check that errors are none zero
2566 if (fMnUserParams.Error(parNo[i]) == 0.0) {
2567 std::cerr << std::endl << "**SEVERE ERROR** in PFitter::ExecuteSave(): parameter no " << parNo[i]+1 << " has an error == 0. Cannot correctly handle the correlation matrix.";
2568 std::cerr << std::endl;
2569 dval = 0.0;
2570 } else if (fMnUserParams.Error(parNo[j]) == 0.0) {
2571 std::cerr << std::endl << "**SEVERE ERROR** in PFitter::ExecuteSave(): parameter no " << parNo[j]+1 << " has an error == 0. Cannot correctly handle the correlation matrix.";
2572 std::cerr << std::endl;
2573 dval = 0.0;
2574 } else {
2575 dval = cov(i,j)/(fMnUserParams.Error(parNo[i])*fMnUserParams.Error(parNo[j]));
2576 }
2577 hcorr->Fill((Double_t)i,(Double_t)j,dval);
2578 // handle precision, ugly but ...
2579 if (dval < 1.0e-2) {
2580 fout.precision(2);
2581 } else {
2582 fout.precision(4);
2583 }
2584 // handle sign
2585 if (dval > 0.0) {
2586 fout << " ";
2587 fout.width(7);
2588 } else {
2589 fout.width(8);
2590 }
2591 fout << dval << " ";
2592 }
2593 }
2594 }
2595 // write correlation matrix into a root file
2596 TFile ff("MINUIT2.root", "recreate");
2597 ccorr->Draw();
2598 if (cov.Nrow() <= 6)
2599 hcorr->Draw("COLZTEXT");
2600 else
2601 hcorr->Draw("COLZ");
2602 ccorr->Write("ccorr", TObject::kOverwrite, sizeof(ccorr));
2603 hcorr->Write("hcorr", TObject::kOverwrite, sizeof(hcorr));
2604 ff.Close();
2605
2606 if (fYamlOut) {
2607 // write the fit results to an easy-to-read/parse yaml file
2608 // note: the block names follow those used by Python library iminuit
2609 // https://github.com/scikit-hep/iminuit
2610
2611 // dynamically name the yaml output file
2612 // https://stackoverflow.com/a/25389052
2613 std::string yaml_filename(fRunInfo->GetFileName().Data());
2614 const std::string msr_ext(".msr");
2615 yaml_filename.replace(yaml_filename.find(msr_ext), msr_ext.length(),
2616 ".yaml");
2617
2618 // define yaml's 2-space indentation
2619 const std::string yaml_indent(" ");
2620
2621 // open the yaml file for writing
2622 std::ofstream yaml_file(yaml_filename);
2623
2624 // number formatting of the output
2625 yaml_file << std::scientific << std::setprecision(16);
2626
2627 // write the parameter values
2628 yaml_file << "values:\n";
2629 for (unsigned int i = 0; i < fParams.size(); ++i) {
2630 yaml_file << yaml_indent << fParams[i].fName.Data() << ": "
2631 << fParams[i].fValue << "\n";
2632 }
2633
2634 // write the parabolic errors
2635 yaml_file << "errors:\n";
2636 for (unsigned int i = 0; i < fParams.size(); ++i) {
2637 yaml_file << yaml_indent << fParams[i].fName.Data() << ": "
2638 << fMnUserParams.Error(i) << "\n";
2639 }
2640
2641 // write the minos errors
2642 yaml_file << "mnerrors:\n";
2643 for (unsigned int i = 0; i < fParams.size(); ++i) {
2644 // use boost's implementation of a variant, which can be streamed by
2645 // default - see: https://stackoverflow.com/q/47168477
2646 boost::variant<double, std::string> positive_error, negative_error;
2647 if (fParams[i].fPosErrorPresent) {
2648 positive_error = fParams[i].fPosError;
2649 negative_error = fParams[i].fStep;
2650 } else {
2651 positive_error = "null";
2652 negative_error = "null";
2653 }
2654
2655 yaml_file << yaml_indent << fParams[i].fName.Data() << ":\n";
2656 yaml_file << yaml_indent << yaml_indent
2657 << "positive: " << positive_error << "\n";
2658 yaml_file << yaml_indent << yaml_indent
2659 << "negative: " << negative_error << "\n";
2660 }
2661
2662 // write the parameter limits
2663 yaml_file << "limits:\n";
2664 for (unsigned int i = 0; i < fParams.size(); ++i) {
2665 // use boost's implementation of a variant, which can be streamed by
2666 // default - see: https://stackoverflow.com/q/47168477
2667 boost::variant<double, std::string> upper_limit, lower_limit;
2668 if (fParams[i].fLowerBoundaryPresent) {
2669 lower_limit = fParams[i].fLowerBoundary;
2670 } else {
2671 lower_limit = "null";
2672 }
2673 if (fParams[i].fUpperBoundaryPresent) {
2674 upper_limit = fParams[i].fUpperBoundary;
2675 } else {
2676 upper_limit = "null";
2677 }
2678
2679 yaml_file << yaml_indent << fParams[i].fName.Data() << ":\n";
2680 yaml_file << yaml_indent << yaml_indent << "lower: " << lower_limit
2681 << "\n";
2682 yaml_file << yaml_indent << yaml_indent << "upper: " << upper_limit
2683 << "\n";
2684 }
2685
2686 // write if the parameter is fixed
2687 yaml_file << "fixed:\n";
2688 for (unsigned int i = 0; i < fParams.size(); ++i) {
2689 std::string is_fixed = fParams[i].fStep == 0.0 ? "true" : "false";
2690 yaml_file << yaml_indent << fParams[i].fName.Data() << ": " << is_fixed
2691 << "\n";
2692 }
2693
2694 // write the covariance matrix (omitting fixed parameters)
2695 yaml_file << "covariance:\n";
2696 for (unsigned int i = 0; i < cov.Nrow(); ++i) {
2697 yaml_file << yaml_indent << mnState.Name(parNo[i]) << ":\n";
2698 for (unsigned int j = 0; j < cov.Nrow(); ++j) {
2699 yaml_file << yaml_indent << yaml_indent << mnState.Name(parNo[j])
2700 << ": " << cov(i, j) << "\n";
2701 }
2702 }
2703
2704 // write the correlation matrix (omitting fixed parameters)
2705 yaml_file << "correlation:\n";
2706 for (unsigned int i = 0; i < cov.Nrow(); ++i) {
2707 yaml_file << yaml_indent << mnState.Name(parNo[i]) << ":\n";
2708 for (unsigned int j = 0; j < cov.Nrow(); ++j) {
2709 double correlation =
2710 i == j ? 1.0
2711 : cov(i, j) / (fMnUserParams.Error(parNo[i]) *
2712 fMnUserParams.Error(parNo[j]));
2713 yaml_file << yaml_indent << yaml_indent << mnState.Name(parNo[j])
2714 << ": " << correlation << "\n";
2715 }
2716 }
2717
2718 // close the yaml file
2719 yaml_file.close();
2720 }
2721 }
2722 parNo.clear(); // clean up
2723 } else {
2724 fout << std::endl << " no correlation coefficients available";
2725 }
2726
2727 fout << std::endl;
2728 fout << std::endl << "*************************************************************************";
2729 fout << std::endl << " chisq/maxLH RESULT ";
2730 fout << std::endl << "*************************************************************************";
2731 PMsrStatisticStructure *statistics = fRunInfo->GetMsrStatistic();
2732
2733 // get time range and write it
2734 Double_t fitStartTime = PMUSR_UNDEFINED, fitEndTime = PMUSR_UNDEFINED;
2735 // first check if there is a global block with a valid time range
2736 PMsrGlobalBlock *global = fRunInfo->GetMsrGlobal();
2737 fitStartTime = global->GetFitRange(0);
2738 fitEndTime = global->GetFitRange(1);
2739 if (fitStartTime == PMUSR_UNDEFINED) { // no global time range, hence take the one from the first run block
2740 PMsrRunList *run = fRunInfo->GetMsrRunList();
2741 fitStartTime = run->at(0).GetFitRange(0);
2742 fitEndTime = run->at(0).GetFitRange(1);
2743 }
2744 fout.setf(std::ios::fixed, std::ios::floatfield);
2745 fout << std::endl << " Time Range: " << fitStartTime << ", " << fitEndTime << std::endl;
2746 if (fUseChi2) {
2747 fout.setf(std::ios::fixed, std::ios::floatfield);
2748 fout << std::endl << " chisq = " << std::setprecision(4) << statistics->fMin << ", NDF = " << statistics->fNdf << ", chisq/NDF = " << std::setprecision(6) << statistics->fMin/statistics->fNdf;
2749 if (statistics->fMinExpected > 0)
2750 fout << std::endl << " chisq_e = " << std::setprecision(4) << statistics->fMinExpected << ", NDF = " << statistics->fNdf << ", chisq_e/NDF = " << std::setprecision(6) << statistics->fMinExpected/statistics->fNdf;
2751 } else { // maxLH
2752 fout.setf(std::ios::fixed, std::ios::floatfield);
2753 fout << std::endl << " maxLH = " << std::setprecision(4) << statistics->fMin << ", NDF = " << statistics->fNdf << ", maxLH/NDF = " << std::setprecision(6) << statistics->fMin/statistics->fNdf;
2754 if (statistics->fMinExpected > 0)
2755 fout << std::endl << " maxLH_e = " << std::setprecision(4) << statistics->fMinExpected << ", NDF = " << statistics->fNdf << ", maxLH_e/NDF = " << std::setprecision(6) << statistics->fMinExpected/statistics->fNdf;
2756 }
2757
2758 if (fSectorFlag)
2759 ExecuteSector(fout);
2760
2761 fout << std::endl;
2762 fout << std::endl << "*************************************************************************";
2763 fout << std::endl << " DONE ";
2764 fout << std::endl << "*************************************************************************";
2765 fout << std::endl << std::endl;
2766
2767 // close MINUIT2.OUTPUT file
2768 fout.close();
2769
2770 return true;
2771}
2772
2773//--------------------------------------------------------------------------
2774// ExecuteSimplex
2775//--------------------------------------------------------------------------
2782{
2783 std::cout << ">> PFitter::ExecuteSimplex(): will call simplex ..." << std::endl;
2784
2785 // create minimizer object
2786 // strategy is by default = 'default'
2787 ROOT::Minuit2::MnSimplex simplex((*fFitterFcn), fMnUserParams, ROOT::Minuit2::MnStrategy{fStrategy});
2788
2789 // minimize
2790 // maxfcn is 10*MINUIT2 Default maxfcn
2791 UInt_t maxfcn = std::numeric_limits<UInt_t>::max();
2792 // tolerance = MINUIT2 Default tolerance
2793 Double_t tolerance = 0.1;
2794 // keep track of elapsed time
2795 Double_t start=0.0, end=0.0;
2796 start=MilliTime();
2797 ROOT::Minuit2::FunctionMinimum min = simplex(maxfcn, tolerance);
2798 end=MilliTime();
2799 std::cout << ">> PFitter::ExecuteMinimize(): execution time for Simplex = " << std::setprecision(3) << (end-start)/1.0e3 << " sec." << std::endl;
2800 TString str = TString::Format("Simplex: %.3f sec", (end-start)/1.0e3);
2801 fElapsedTime.push_back(str);
2802 if (!min.IsValid()) {
2803 std::cerr << std::endl << ">> PFitter::ExecuteSimplex(): **WARNING**: Fit did not converge, sorry ...";
2804 std::cerr << std::endl;
2805 fIsValid = false;
2806 return false;
2807 }
2808
2809 // keep FunctionMinimum object
2810 fFcnMin.reset(new ROOT::Minuit2::FunctionMinimum(min));
2811
2812 // keep user parameters
2813 if (fFcnMin)
2814 fMnUserParams = fFcnMin->UserParameters();
2815
2816 // fill run info
2817 for (UInt_t i=0; i<fParams.size(); i++) {
2818 Double_t dval = min.UserState().Value(i);
2819 if (fPhase[i]) {
2820 Int_t m = (Int_t)(dval/360.0);
2821 dval = dval - m*360.0;
2822 }
2823 fRunInfo->SetMsrParamValue(i, dval);
2824 fRunInfo->SetMsrParamStep(i, min.UserState().Error(i));
2825 fRunInfo->SetMsrParamPosErrorPresent(i, false);
2826 }
2827
2828 // handle statistics
2829 Double_t minVal = min.Fval();
2830 UInt_t ndf = fFitterFcn->GetTotalNoOfFittedBins();
2831 // subtract number of varied parameters from total no of fitted bins -> ndf
2832 for (UInt_t i=0; i<fParams.size(); i++) {
2833 if ((min.UserState().Error(i) != 0.0) && !fMnUserParams.Parameters().at(i).IsFixed())
2834 ndf -= 1;
2835 }
2836
2837 // feed run info with new statistics info
2838 fRunInfo->SetMsrStatisticMin(minVal);
2839 fRunInfo->SetMsrStatisticNdf(ndf);
2840
2841 fConverged = true;
2842
2843 if (fPrintLevel >= 2)
2844 std::cout << *fFcnMin << std::endl;
2845
2846 return true;
2847}
2848
2849//--------------------------------------------------------------------------
2850// PrepareSector
2851//--------------------------------------------------------------------------
2859{
2860 Double_t val;
2861 UInt_t ndf;
2862
2863 Int_t usedParams = 0;
2864 for (UInt_t i=0; i<error.size(); i++) {
2865 if (error[i] != 0.0)
2866 usedParams++;
2867 }
2868
2869 PDoublePairVector secFitRange;
2870 secFitRange.resize(1);
2871
2872 if (fUseChi2) {
2873 Double_t totalExpectedChisq = 0.0;
2874 PDoubleVector expectedChisqPerRun;
2875 PDoubleVector chisqPerRun;
2876 for (UInt_t k=0; k<fSector.size(); k++) {
2877 // set sector fit range
2878 secFitRange[0].first = fSector[k].GetTimeRangeFirst(0);
2879 secFitRange[0].second = fSector[k].GetTimeRangeLast();
2880 fRunListCollection->SetFitRange(secFitRange);
2881 // calculate chisq
2882 val = (*fFitterFcn)(param);
2883 fSector[k].SetChisq(val);
2884 // calculate NDF
2885 ndf = static_cast<UInt_t>(fFitterFcn->GetTotalNoOfFittedBins()) - usedParams;
2886 fSector[k].SetNDF(ndf);
2887 // calculate expected chisq
2888 totalExpectedChisq = 0.0;
2889 fFitterFcn->CalcExpectedChiSquare(param, totalExpectedChisq, expectedChisqPerRun);
2890 fSector[k].SetExpectedChisq(totalExpectedChisq);
2891 // calculate chisq per run
2892 for (UInt_t i=0; i<fRunInfo->GetMsrRunList()->size(); i++) {
2893 chisqPerRun.push_back(fRunListCollection->GetSingleRunChisq(param, i));
2894 fSector[k].SetChisq(chisqPerRun[i], i);
2895 fSector[k].SetExpectedChisq(expectedChisqPerRun[i], i);
2896 }
2897
2898 if (totalExpectedChisq != 0.0) {
2899 UInt_t ndf_run = 0;
2900 for (UInt_t i=0; i<expectedChisqPerRun.size(); i++) {
2901 ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i);
2902 if (ndf_run > 0) {
2903 fSector[k].SetNDF(ndf_run, i);
2904 }
2905 }
2906 } else if (chisqPerRun.size() > 0) { // in case expected chisq is not applicable like for asymmetry fits
2907 UInt_t ndf_run = 0;
2908 for (UInt_t i=0; i<chisqPerRun.size(); i++) {
2909 ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i);
2910 if (ndf_run > 0) {
2911 fSector[k].SetNDF(ndf_run, i);
2912 }
2913 }
2914 }
2915 // clean up
2916 chisqPerRun.clear();
2917 expectedChisqPerRun.clear();
2918 }
2919 } else {
2920 Double_t totalExpectedMaxLH = 0.0;
2921 PDoubleVector expectedMaxLHPerRun;
2922 PDoubleVector maxLHPerRun;
2923 for (UInt_t k=0; k<fSector.size(); k++) {
2924 // set sector fit range
2925 secFitRange[0].first = fSector[k].GetTimeRangeFirst(0);
2926 secFitRange[0].second = fSector[k].GetTimeRangeLast();
2927 fRunListCollection->SetFitRange(secFitRange);
2928 // calculate maxLH
2929 val = (*fFitterFcn)(param);
2930 fSector[k].SetChisq(val);
2931 // calculate NDF
2932 ndf = static_cast<UInt_t>(fFitterFcn->GetTotalNoOfFittedBins()) - usedParams;
2933 fSector[k].SetNDF(ndf);
2934 // calculate expected maxLH
2935 totalExpectedMaxLH = 0.0;
2936 fFitterFcn->CalcExpectedChiSquare(param, totalExpectedMaxLH, expectedMaxLHPerRun);
2937 fSector[k].SetExpectedChisq(totalExpectedMaxLH);
2938 // calculate maxLH per run
2939 for (UInt_t i=0; i<fRunInfo->GetMsrRunList()->size(); i++) {
2940 maxLHPerRun.push_back(fRunListCollection->GetSingleRunMaximumLikelihood(param, i));
2941 fSector[k].SetChisq(maxLHPerRun[i], i);
2942 fSector[k].SetExpectedChisq(expectedMaxLHPerRun[i], i);
2943 }
2944
2945 if (totalExpectedMaxLH != 0.0) {
2946 UInt_t ndf_run = 0;
2947 for (UInt_t i=0; i<expectedMaxLHPerRun.size(); i++) {
2948 ndf_run = fFitterFcn->GetNoOfFittedBins(i) - fRunInfo->GetNoOfFitParameters(i);
2949 if (ndf_run > 0) {
2950 fSector[k].SetNDF(ndf_run, i);
2951 }
2952 }
2953 }
2954
2955 // clean up
2956 maxLHPerRun.clear();
2957 expectedMaxLHPerRun.clear();
2958 }
2959 }
2960}
2961
2962//--------------------------------------------------------------------------
2963// ExecuteSector
2964//--------------------------------------------------------------------------
2971Bool_t PFitter::ExecuteSector(std::ofstream &fout)
2972{
2973 fout << std::endl;
2974 fout << std::endl << "*************************************************************************";
2975 fout << std::endl << " SECTOR RESULTS";
2976 fout << std::endl << "*************************************************************************";
2977
2978 if (fUseChi2) {
2979 for (UInt_t i=0; i<fSector.size(); i++) {
2980 fout << std::endl;
2981 fout << " Sector " << i+1 << ": FitRange: " << fSector[i].GetTimeRangeFirst(0) << ", " << fSector[i].GetTimeRangeLast() << std::endl;
2982 fout << " chisq = " << fSector[i].GetChisq() << ", NDF = " << fSector[i].GetNDF() << ", chisq/NDF = " << fSector[i].GetChisq()/fSector[i].GetNDF();
2983
2984 if (fSector[i].GetExpectedChisq() > 0) {
2985 fout << std::endl << " expected chisq = " << fSector[i].GetExpectedChisq() << ", NDF = " << fSector[i].GetNDF() << ", expected chisq/NDF = " << fSector[i].GetExpectedChisq()/fSector[i].GetNDF();
2986 for (UInt_t j=0; j<fSector[i].GetNoRuns(); j++) {
2987 fout << std::endl << " run block " << j+1 << " (NDF/red.chisq/red.chisq_e) = (" << fSector[i].GetNDF(j) << "/" << fSector[i].GetChisq(j)/fSector[i].GetNDF(j) << "/" << fSector[i].GetExpectedChisq(j)/fSector[i].GetNDF(j) << ")";
2988 }
2989 } else if (fSector[i].GetNoRuns() > 0) { // in case expected chisq is not applicable like for asymmetry fits
2990 for (UInt_t j=0; j<fSector[i].GetNoRuns(); j++) {
2991 fout << std::endl << " run block " << j+1 << " (NDF/red.chisq) = (" << fSector[i].GetNDF(j) << "/" << fSector[i].GetChisq(j)/fSector[i].GetNDF(j) << ")";
2992 }
2993 }
2994 fout << std::endl << "++++";
2995 }
2996 } else { // max log likelihood
2997 for (UInt_t i=0; i<fSector.size(); i++) {
2998 fout << std::endl;
2999 fout << " Sector " << i+1 << ": FitRange: " << fSector[i].GetTimeRangeFirst(0) << ", " << fSector[i].GetTimeRangeLast() << std::endl;
3000 fout << " maxLH = " << fSector[i].GetChisq() << ", NDF = " << fSector[i].GetNDF() << ", maxLH/NDF = " << fSector[i].GetChisq()/fSector[i].GetNDF();
3001
3002 if (fSector[i].GetExpectedChisq() > 0) {
3003 fout << std::endl << " expected maxLH = " << fSector[i].GetExpectedChisq() << ", NDF = " << fSector[i].GetNDF() << ", expected maxLH/NDF = " << fSector[i].GetExpectedChisq()/fSector[i].GetNDF();
3004 for (UInt_t j=0; j<fSector[i].GetNoRuns(); j++) {
3005 fout << std::endl << " run block " << j+1 << " (NDF/red.maxLH/red.maxLH_e) = (" << fSector[i].GetNDF(j) << "/" << fSector[i].GetChisq(j)/fSector[i].GetNDF(j) << "/" << fSector[i].GetExpectedChisq(j)/fSector[i].GetNDF(j) << ")";
3006 }
3007 } else if (fSector[i].GetNoRuns() > 0) { // in case expected chisq is not applicable like for asymmetry fits
3008 for (UInt_t j=0; j<fSector[i].GetNoRuns(); j++) {
3009 fout << std::endl << " run block " << j+1 << " (NDF/red.maxLH) = (" << fSector[i].GetNDF(j) << "/" << fSector[i].GetChisq(j)/fSector[i].GetNDF(j) << ")";
3010 }
3011 }
3012 fout << std::endl << "++++";
3013 }
3014 }
3015
3016 return true;
3017}
3018
3019//--------------------------------------------------------------------------
3020// MilliTime
3021//--------------------------------------------------------------------------
3028{
3029 struct timeval now;
3030 gettimeofday(&now, nullptr);
3031
3032 return ((Double_t)now.tv_sec * 1.0e6 + (Double_t)now.tv_usec)/1.0e3;
3033}
3034
3035//--------------------------------------------------------------------------
3036// ParamRound (private)
3037//--------------------------------------------------------------------------
3051{
3052 PDoubleVector par_r;
3053
3054 par_r.resize(par.size());
3055 ok = true;
3056
3057 if (par.size() != err.size()) {
3058 // error msg
3059 ok = false;
3060 return par_r;
3061 }
3062
3063 int exp;
3064 double dval;
3065 for (unsigned int i=0; i<par.size(); i++) {
3066 if (err[i] != 0.0) {
3067 exp = floor(log10(fabs(err[i]))-1);
3068 dval = round(par[i]*pow(10.0, -exp))/pow(10.0, -exp);
3069 par_r[i] = dval;
3070 } else {
3071 par_r[i] = par[i];
3072 }
3073 }
3074
3075 return par_r;
3076}
3077
3078
3079//-------------------------------------------------------------------------------------------------
3080// end
3081//-------------------------------------------------------------------------------------------------
#define PMN_FIX
Fix parameters at current values.
Definition PFitter.h:70
#define PMN_SIMPLEX
SIMPLEX minimizer (robust but slow)
Definition PFitter.h:92
#define PMN_USER_PARAM_STATE
Set user parameter state (not implemented)
Definition PFitter.h:98
#define PMN_RESTORE
Restore parameters from previous SAVE.
Definition PFitter.h:86
#define PMN_RELEASE
Release previously fixed parameters.
Definition PFitter.h:84
#define PMN_PRINT
Set print level for fit output (0=quiet, 1=normal, 2=verbose)
Definition PFitter.h:100
#define PMN_PLOT
Plot command (for scan/contour results)
Definition PFitter.h:82
#define PMN_CONTOURS
Contour plot command (2D error ellipses)
Definition PFitter.h:64
#define PMN_HESSE
Calculate Hessian matrix for error estimation.
Definition PFitter.h:72
#define PMN_FIT_RANGE
Fit range scan to find optimal fitting window.
Definition PFitter.h:68
#define PMN_EIGEN
Eigenvalue analysis (not implemented)
Definition PFitter.h:66
#define PMN_MACHINE_PRECISION
Set machine precision for numerical derivatives.
Definition PFitter.h:74
#define PMN_SAVE
Save current parameter state.
Definition PFitter.h:88
#define PMN_USER_COVARIANCE
Set user covariance matrix (not implemented)
Definition PFitter.h:96
#define PMN_INTERACTIVE
Interactive mode (not implemented in musrfit)
Definition PFitter.h:62
#define PMN_MIGRAD
MIGRAD minimizer (gradient-based, recommended)
Definition PFitter.h:76
#define PMN_SECTOR
Calculate χ² vs. time in sectors (time-window analysis)
Definition PFitter.h:102
#define PMN_SCAN
Parameter scan (1D or 2D)
Definition PFitter.h:90
#define PMN_MINOS
MINOS error analysis (asymmetric confidence intervals)
Definition PFitter.h:80
#define PMN_MINIMIZE
MINIMIZE (automatic algorithm selection)
Definition PFitter.h:78
std::pair< Double_t, Double_t > PDoublePair
Definition PMusr.h:391
std::vector< PMsrRunBlock > PMsrRunList
Definition PMusr.h:1245
#define PMUSR_UNDEFINED
Definition PMusr.h:172
std::vector< PMsrLineStructure > PMsrLines
Definition PMusr.h:989
std::vector< PDoublePair > PDoublePairVector
Definition PMusr.h:397
std::pair< Int_t, Int_t > PIntPair
Definition PMusr.h:373
std::vector< Int_t > PIntVector
Definition PMusr.h:367
std::vector< Double_t > PDoubleVector
Definition PMusr.h:385
return status
Bool_t ExecuteContours()
Executes CONTOURS command (2D error contours).
Definition PFitter.cpp:1688
Bool_t ExecutePlot()
Executes PLOT command (visualize scan/contour results).
Definition PFitter.cpp:2103
PDoublePairVector fOriginalFitRange
Original fit ranges per run (saved for FIT_RANGE command)
Definition PFitter.h:327
UInt_t fScanNoPoints
Number of scan/contour evaluation points (default=41)
Definition PFitter.h:322
Bool_t IsValid()
Definition PFitter.h:273
UInt_t fStrategy
Minuit2 strategy: 0=fast/low-accuracy, 1=default, 2=careful/high-accuracy.
Definition PFitter.h:303
Double_t fScanHigh
Scan upper bound: 0.0 = auto (2σ above current value)
Definition PFitter.h:324
Bool_t fIsValid
Overall validity flag: true if fitter initialized successfully.
Definition PFitter.h:295
Bool_t ExecutePrintLevel(UInt_t lineNo)
Executes PRINT command (set verbosity level).
Definition PFitter.cpp:2123
PStringVector fElapsedTime
Timing information for each fit command.
Definition PFitter.h:329
PIntPairVector fCmdList
Parsed commands: first=command ID, second=line number.
Definition PFitter.h:312
Double_t MilliTime()
Returns current time in milliseconds.
Definition PFitter.cpp:3027
UInt_t fScanParameter[2]
Parameter indices: [0]=primary scan/contour, [1]=secondary (contours only)
Definition PFitter.h:321
Bool_t DoFit()
Main entry point for executing the fit.
Definition PFitter.cpp:647
PIntVector GetParFromFun(const TString funStr)
Extracts parameter numbers from a FUNCTIONS block entry.
Definition PFitter.cpp:489
Bool_t fSectorFlag
SECTOR command present flag.
Definition PFitter.h:332
Bool_t fYamlOut
Output flag: true to generate YAML output file (MINUIT2.OUTPUT → yaml)
Definition PFitter.h:299
Bool_t ExecuteScan()
Executes SCAN command (1D parameter space scan).
Definition PFitter.cpp:2245
UInt_t fPrintLevel
Verbosity level: 0=quiet, 1=normal, 2=verbose (Minuit output)
Definition PFitter.h:301
Bool_t ExecuteSave(Bool_t first)
Executes SAVE command (store current parameters).
Definition PFitter.cpp:2272
PDoubleVector ParamRound(const PDoubleVector &par, const PDoubleVector &err, Bool_t &ok)
Rounds parameters for output with appropriate precision.
Definition PFitter.cpp:3050
Bool_t fScanAll
Multi-parameter scan flag: false=1D scan, true=2D scan (not fully implemented)
Definition PFitter.h:320
Bool_t fIsScanOnly
Scan mode flag: true if only parameter scans requested (no minimization)
Definition PFitter.h:296
virtual ~PFitter()
Destructor - Cleans up dynamically allocated resources.
Definition PFitter.cpp:352
PRunListCollection * fRunListCollection
Pointer to preprocessed run data collection.
Definition PFitter.h:307
Bool_t ExecuteSimplex()
Executes SIMPLEX command (non-gradient minimization).
Definition PFitter.cpp:2781
PMsrLines fCmdLines
Raw command lines from MSR COMMANDS block.
Definition PFitter.h:311
std::vector< PSectorChisq > fSector
Sector analysis results (χ² vs. time windows)
Definition PFitter.h:333
Bool_t SetParameters()
Transfers MSR parameters to Minuit2 parameter state.
Definition PFitter.cpp:1640
Bool_t ExecuteSector(std::ofstream &fout)
Executes SECTOR command (time-dependent χ² analysis).
Definition PFitter.cpp:2971
void GetPhaseParams()
Identifies which parameters represent phase angles.
Definition PFitter.cpp:390
Double_t fScanLow
Scan lower bound: 0.0 = auto (2σ below current value)
Definition PFitter.h:323
PFitter(PMsrHandler *runInfo, PRunListCollection *runListCollection, Bool_t chisq_only=false, Bool_t yaml_out=false)
Constructor for the fitting engine.
Definition PFitter.cpp:290
Bool_t ExecuteHesse()
Executes HESSE command (calculate error matrix).
Definition PFitter.cpp:1832
PMsrParamList fParams
Copy of parameter list from MSR file.
Definition PFitter.h:309
PMsrHandler * fRunInfo
Pointer to MSR file handler (parameters, theory, commands)
Definition PFitter.h:306
Bool_t ExecuteRelease(UInt_t lineNo)
Executes RELEASE command (unfreeze parameters).
Definition PFitter.cpp:2181
Bool_t ExecuteMinos()
Executes MINOS command (asymmetric error analysis).
Definition PFitter.cpp:2034
PIntVector GetParFromMap(const TString mapStr)
Extracts parameter numbers from a map reference.
Definition PFitter.cpp:570
PDoublePairVector fScanData
Scan results: (parameter_value, χ²) pairs.
Definition PFitter.h:325
Bool_t ExecuteMinimize()
Executes MINIMIZE command (automatic algorithm selection).
Definition PFitter.cpp:1957
ROOT::Minuit2::MnUserParameters fMnUserParams
Minuit2 parameter state (values, errors, limits)
Definition PFitter.h:316
Bool_t ExecuteMigrad()
Executes MIGRAD command (gradient descent minimization).
Definition PFitter.cpp:1881
std::unique_ptr< ROOT::Minuit2::FunctionMinimum > fFcnMin
Minuit2 function minimum result.
Definition PFitter.h:317
Bool_t ExecuteRestore()
Executes RESTORE command (reload saved parameters).
Definition PFitter.cpp:2223
Bool_t CheckCommands()
Validates COMMANDS block syntax and builds execution queue.
Definition PFitter.cpp:953
Bool_t fConverged
Convergence flag: true if fit converged to a valid minimum.
Definition PFitter.h:297
Bool_t fChisqOnly
Evaluation-only flag: true to calculate χ² without fitting.
Definition PFitter.h:298
Bool_t ExecuteFitRange(UInt_t lineNo)
Executes FIT_RANGE command (optimal time-window search).
Definition PFitter.cpp:1723
Bool_t ExecuteFix(UInt_t lineNo)
Executes FIX command (freeze parameters).
Definition PFitter.cpp:1794
std::vector< bool > fPhase
Phase parameter flags: true if parameter is a phase angle.
Definition PFitter.h:335
void PrepareSector(PDoubleVector &param, PDoubleVector &error)
Prepares sector χ² analysis data structures.
Definition PFitter.cpp:2858
std::unique_ptr< PFitterFcn > fFitterFcn
Objective function for Minuit2 minimization.
Definition PFitter.h:314
Bool_t fUseChi2
Fit mode: true = χ² minimization, false = log-max-likelihood.
Definition PFitter.h:300
virtual Double_t GetFitRange(UInt_t idx)
Definition PMusr.cpp:1120
MSR file parser and manager for the musrfit framework.
virtual PMsrLines * GetMsrCommands()
Returns pointer to COMMANDS block lines.
virtual PMsrParamList * GetMsrParamList()
Returns pointer to fit parameter list.
Manager class for all processed μSR run data during fitting.
void SetChisq(Double_t chisq)
Definition PFitter.h:144
Double_t GetExpectedChisq()
Definition PFitter.h:189
Double_t fLast
requested time stamp
Definition PFitter.h:211
UInt_t GetNDF()
Definition PFitter.h:198
PDoubleVector fFirst
time stamp for fgb for a given run
Definition PFitter.h:215
void SetNDF(UInt_t ndf)
Definition PFitter.h:162
void SetExpectedChisq(Double_t expChisq)
Definition PFitter.h:153
PUIntVector fNDFRun
NDF for the sector and run.
Definition PFitter.h:218
Double_t fChisq
chisq or maxLH for the sector
Definition PFitter.h:212
void SetSectorTime(Double_t last)
Definition PFitter.h:140
UInt_t fNDF
NDF for the sector.
Definition PFitter.h:214
Double_t GetTimeRangeFirst(UInt_t idx)
Definition PFitter.cpp:195
PSectorChisq(UInt_t noOfRuns)
Definition PFitter.cpp:81
Double_t GetChisq()
Definition PFitter.h:180
PDoubleVector fChisqRun
chisq or maxLH for the sector and run
Definition PFitter.h:216
Double_t fExpectedChisq
keep the expected chisq or maxLH for the sector
Definition PFitter.h:213
PDoubleVector fExpectedChisqRun
expected chisq or maxLH for the sector and run
Definition PFitter.h:217
void SetRunFirstTime(Double_t first, UInt_t idx)
Definition PFitter.cpp:109
UInt_t fNoOfRuns
number of runs presesent
Definition PFitter.h:210
UInt_t fNdf
number of degrees of freedom
Definition PMusr.h:1333
Double_t fMinExpected
expected total chi2 or max. likelihood
Definition PMusr.h:1334
Double_t fMin
chisq or max. likelihood
Definition PMusr.h:1331
PUIntVector fNdfPerHisto
number of degrees of freedom per histo
Definition PMusr.h:1336
PDoubleVector fMinExpectedPerHisto
expected pre histo chi2 or max. likelihood
Definition PMusr.h:1335
PDoubleVector fMinPerHisto
chisq or max. likelihood per histo
Definition PMusr.h:1332