MaCh3  2.6.0
Reference Guide
MinuitFit.cpp
Go to the documentation of this file.
1 #include "MinuitFit.h"
2 
3 // *******************
4 // Run the Minuit Fit with all the systematic objects added
6 // *******************
7  AlgorithmName = "MinuitFit";
9  // Minimizer type: determines the underlying implementation.
10  // Available types include:
11  // - "Minuit2" (recommended modern option)
12  // - "Minuit" (legacy)
13  // - "Fumili"
14  // - "GSLMultiMin" (for gradient-free minimization)
15  // - "GSLMultiFit"
16  // - "GSLSimAn" (Simulated Annealing)
17  const std::string MinimizerType = "Minuit2";
18  // Minimizer algorithm (specific to the selected type).
19  // For Minuit2, the following algorithms are available:
20  // - "Migrad" : gradient-based minimization (default)
21  // - "Simplex" : Nelder-Mead simplex method (derivative-free)
22  // - "Combined" : combination of Simplex and Migrad
23  // - "Scan" : parameter grid scan
24  const std::string MinimizerAlgo = "Migrad";
25 
26  MACH3LOG_INFO("Creating instance of Minimizer with {} and {}", MinimizerType, MinimizerAlgo);
27 
28  minuit = std::unique_ptr<ROOT::Math::Minimizer>(
29  ROOT::Math::Factory::CreateMinimizer(MinimizerType.c_str(), MinimizerAlgo.c_str()));
30 
31  std::string Features = gROOT->GetConfigFeatures();
32  if (Features.find("minuit2_omp") != std::string::npos) {
33  MACH3LOG_ERROR("Minuit in ROOT has been compiled with OMP support");
34  MACH3LOG_ERROR("Since MaCh3 uses OMP for reweight this could cause terrible clash");
35  throw MaCh3Exception(__FILE__ , __LINE__ );
36  }
37 }
38 
39 // *************************
40 // Destructor: close the logger and output file
42 // *************************
43 }
44 
45 // *******************
46 // Run the Minuit with all the systematic objects added
48 // *******************
49  PrepareFit();
50 
51  // Remove obsolete memory and make other checks before fit starts
53 
54  //KS: For none PCA this will be equal to normal parameters
55  const int NparsMinuitFull = NPars;
56  const int NparsMinuit = NParsPCA;
57 
58  //KS: Set SetFunction we will Minimize
59  ROOT::Math::Functor fChi2(this, &MinuitFit::CalcChi2, NparsMinuit);
60  minuit->SetFunction(fChi2);
61 
62  //KS: add config or something
63  minuit->SetPrintLevel(2);
64  minuit->SetTolerance(0.01);
65  minuit->SetMaxFunctionCalls(fitMan->raw()["General"]["Minuit2"]["NSteps"].as<unsigned>());
66  minuit->SetMaxIterations(10000);
67 
68 
69  // Save the adaptive MCMC
70  for (const auto &syst : systematics)
71  {
72  if (syst->GetDoAdaption())
73  {
74  MACH3LOG_ERROR("Param Handler {} has enabled Adaption, this is not needed for Minuit so please turn it off", syst->GetDoAdaption());
75  throw MaCh3Exception(__FILE__ , __LINE__ );
76  }
77  }
78 
79  MACH3LOG_INFO("Preparing Minuit");
80  int ParCounter = 0;
81  for (std::vector<ParameterHandlerBase*>::iterator it = systematics.begin(); it != systematics.end(); ++it)
82  {
83  if(!(*it)->IsPCA())
84  {
85  for(int i = 0; i < (*it)->GetNumParams(); ++i, ++ParCounter)
86  {
87  // KS: Index, name, prior, step scale [different to MCMC],
88  // divide by 10 because this is what BANFF used to do...
89  minuit->SetVariable(ParCounter, ((*it)->GetParName(i)), (*it)->GetParPreFit(i), (*it)->GetDiagonalError(i)/10);
90  minuit->SetVariableValue(ParCounter, (*it)->GetParPreFit(i));
91  //KS: lower bound, upper bound, if Mirroring enabled then ignore
92  if(!fMirroring) minuit->SetVariableLimits(ParCounter, (*it)->GetLowerBound(i), (*it)->GetUpperBound(i));
93  if((*it)->IsParameterFixed(i))
94  {
95  minuit->FixVariable(ParCounter);
96  }
97  }
98  }
99  else
100  {
101  for(int i = 0; i < (*it)->GetNParameters(); ++i, ++ParCounter)
102  {
103  // KS: Index, name, prior, step scale [different to MCMC],
104  // divide by 10 because this is what BANFF used to do...
105  minuit->SetVariable(ParCounter, Form("%i_PCA", i), (*it)->GetPCAHandler()->GetParPropPCA(i), (*it)->GetPCAHandler()->GetEigenValuesMaster()[i]/10);
106  if((*it)->GetPCAHandler()->IsParameterFixedPCA(i))
107  {
108  minuit->FixVariable(ParCounter);
109  }
110  }
111  }
112  }
113 
114  minuit->SetPrintLevel(2);
115 
116  MACH3LOG_INFO("Starting MIGRAD");
117  minuit->Minimize();
118 
119  MACH3LOG_INFO("Starting HESSE");
120  minuit->Hesse();
121  outputFile->cd();
122 
123  TVectorD* MinuitParValue = new TVectorD(NparsMinuitFull);
124  TVectorD* MinuitParError = new TVectorD(NparsMinuitFull);
125  TMatrixDSym* Postmatrix = new TMatrixDSym(NparsMinuitFull);
126 
127  for(int i = 0; i < NparsMinuitFull; ++i)
128  {
129  (*MinuitParValue)(i) = 0;
130  (*MinuitParError)(i) = 0;
131  for(int j = 0; j < NparsMinuitFull; ++j)
132  {
133  (*Postmatrix)(i,j) = 0;
134  (*Postmatrix)(i,j) = minuit->CovMatrix(i,j);
135  }
136  }
137 
138  ParCounter = 0;
139  const double *X = minuit->X();
140  const double *err = minuit->Errors();
141  for (std::vector<ParameterHandlerBase*>::iterator it = systematics.begin(); it != systematics.end(); ++it)
142  {
143  if(!(*it)->IsPCA())
144  {
145  for(int i = 0; i < (*it)->GetNumParams(); ++i, ++ParCounter)
146  {
147  double ParVal = X[ParCounter];
148  //KS: Basically apply mirroring for parameters out of bounds
149  if(fMirroring)
150  {
151  if(ParVal < (*it)->GetLowerBound(i))
152  {
153  ParVal = (*it)->GetLowerBound(i) + ((*it)->GetLowerBound(i) - ParVal);
154  }
155  else if (ParVal > (*it)->GetUpperBound(i))
156  {
157  ParVal = (*it)->GetUpperBound(i) - ( ParVal - (*it)->GetUpperBound(i));
158  }
159  }
160  (*MinuitParValue)(ParCounter) = ParVal;
161  (*MinuitParError)(ParCounter) = err[ParCounter];
162  //KS: For fixed params HESS will not calculate error so we need to pass prior error
163  if((*it)->IsParameterFixed(i))
164  {
165  (*MinuitParError)(ParCounter) = (*it)->GetDiagonalError(i);
166  (*Postmatrix)(ParCounter,ParCounter) = (*MinuitParError)(ParCounter) * (*MinuitParError)(ParCounter);
167  }
168  }
169  }
170  else
171  {
172  //KS: We need to convert parameters from PCA to normal base
173  TVectorD ParVals((*it)->GetNumParams());
174  TVectorD ParVals_PCA((*it)->GetNParameters());
175 
176  TVectorD ErrorVals((*it)->GetNumParams());
177  TVectorD ErrorVals_PCA((*it)->GetNParameters());
178 
179  TMatrixD MatrixVals((*it)->GetNumParams(), (*it)->GetNumParams());
180  TMatrixD MatrixVals_PCA((*it)->GetNParameters(), (*it)->GetNParameters());
181 
182  //First save them
183  //KS: This code is super convoluted as MaCh3 can store separate matrices while Minuit has one matrix. In future this will be simplified, keep it like this for now.
184  const int StartVal = ParCounter;
185  for(int i = 0; i < (*it)->GetNParameters(); ++i, ++ParCounter)
186  {
187  ParVals_PCA(i) = X[ParCounter];
188  ErrorVals_PCA(i) = err[ParCounter];
189  int ParCounterMatrix = StartVal;
190  for(int j = 0; j < (*it)->GetNParameters(); ++j, ++ParCounterMatrix)
191  {
192  MatrixVals_PCA(i,j) = minuit->CovMatrix(ParCounter,ParCounterMatrix);
193  }
194  }
195  ParVals = ((*it)->GetPCAHandler()->GetTransferMatrix())*ParVals_PCA;
196  ErrorVals = ((*it)->GetPCAHandler()->GetTransferMatrix())*ErrorVals_PCA;
197  MatrixVals.Mult(((*it)->GetPCAHandler()->GetTransferMatrix()),MatrixVals_PCA);
198 
199  ParCounter = StartVal;
200  //KS: Now after going from PCA to normal let';s save it
201  for(int i = 0; i < (*it)->GetNumParams(); ++i, ++ParCounter)
202  {
203  (*MinuitParValue)(ParCounter) = ParVals(i);
204  (*MinuitParError)(ParCounter) = std::fabs(ErrorVals(i));
205  int ParCounterMatrix = StartVal;
206  for(int j = 0; j < (*it)->GetNumParams(); ++j, ++ParCounterMatrix)
207  {
208  (*Postmatrix)(ParCounter,ParCounterMatrix) = MatrixVals(i,j);
209  }
210  //If fixed take prior
211  if((*it)->GetPCAHandler()->IsParameterFixedPCA(i))
212  {
213  (*MinuitParError)(ParCounter) = (*it)->GetDiagonalError(i);
214  (*Postmatrix)(ParCounter,ParCounter) = (*MinuitParError)(ParCounter) * (*MinuitParError)(ParCounter);
215  }
216  }
217  }
218  }
219 
220  MinuitParValue->Write("MinuitParValue");
221  MinuitParError->Write("MinuitParError");
222  Postmatrix->Write("Postmatrix");
223  delete MinuitParValue;
224  delete MinuitParError;
225  delete Postmatrix;
226  // Save all the output
227  SaveOutput();
228 }
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:37
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:35
void SaveOutput()
Save output and close files.
Definition: FitterBase.cpp:229
TFile * outputFile
Output.
Definition: FitterBase.h:152
std::string AlgorithmName
Name of fitting algorithm that is being used.
Definition: FitterBase.h:173
Manager * fitMan
The manager for configuration handling.
Definition: FitterBase.h:113
void SanitiseInputs()
Remove obsolete memory and make other checks before fit starts.
Definition: FitterBase.cpp:221
std::vector< ParameterHandlerBase * > systematics
Systematic holder.
Definition: FitterBase.h:139
Implementation of base Likelihood Fit class, it is mostly responsible for likelihood calculation whil...
Definition: LikelihoodFit.h:6
int NParsPCA
Number of all parameters from all covariances in PCA base.
Definition: LikelihoodFit.h:25
int NPars
Number of all parameters from all covariances.
Definition: LikelihoodFit.h:23
void PrepareFit()
prepare output and perform sanity checks
bool fMirroring
Flag telling if mirroring is used or not.
Definition: LikelihoodFit.h:27
virtual double CalcChi2(const double *x)
Chi2 calculation over all included samples and syst objects.
Custom exception class used throughout MaCh3.
The manager class is responsible for managing configurations and settings.
Definition: Manager.h:16
YAML::Node const & raw() const
Return config.
Definition: Manager.h:47
std::unique_ptr< ROOT::Math::Minimizer > minuit
Pointer to minimizer, which most often is Minuit.
Definition: MinuitFit.h:29
MinuitFit(Manager *const fitMan)
Constructor.
Definition: MinuitFit.cpp:5
void RunMCMC() final
Actual implementation of Minuit Fit algorithm.
Definition: MinuitFit.cpp:47
virtual ~MinuitFit()
Destructor.
Definition: MinuitFit.cpp:41