MaCh3  2.4.2
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 
32 // *************************
33 // Destructor: close the logger and output file
35 // *************************
36 }
37 
38 
39 // *******************
40 // Run the Minuit with all the systematic objects added
42 // *******************
43  PrepareFit();
44 
45  // Remove obsolete memory and make other checks before fit starts
47 
48  //KS: For none PCA this will be equal to normal parameters
49  const int NparsMinuitFull = NPars;
50  const int NparsMinuit = NParsPCA;
51 
52  //KS: Set SetFunction we will Minimize
53  ROOT::Math::Functor fChi2(this, &MinuitFit::CalcChi2, NparsMinuit);
54  minuit->SetFunction(fChi2);
55 
56  //KS: add config or something
57  minuit->SetPrintLevel(2);
58  minuit->SetTolerance(0.01);
59  minuit->SetMaxFunctionCalls(fitMan->raw()["General"]["Minuit2"]["NSteps"].as<unsigned>());
60  minuit->SetMaxIterations(10000);
61 
62 
63  // Save the adaptive MCMC
64  for (const auto &syst : systematics)
65  {
66  if (syst->GetDoAdaption())
67  {
68  MACH3LOG_ERROR("Param Handler {} has enabled Adaption, this is not needed for Minuit so please turn it off", syst->GetDoAdaption());
69  throw MaCh3Exception(__FILE__ , __LINE__ );
70  }
71  }
72 
73 
74 
75  MACH3LOG_INFO("Preparing Minuit");
76  int ParCounter = 0;
77 
78  for (std::vector<ParameterHandlerBase*>::iterator it = systematics.begin(); it != systematics.end(); ++it)
79  {
80  if(!(*it)->IsPCA())
81  {
82  for(int i = 0; i < (*it)->GetNumParams(); ++i, ++ParCounter)
83  {
84  //KS: Index, name, prior, step scale [different to MCMC],
85  minuit->SetVariable(ParCounter, ((*it)->GetParName(i)), (*it)->GetParInit(i), (*it)->GetDiagonalError(i)/10);
86  minuit->SetVariableValue(ParCounter, (*it)->GetParInit(i));
87  //KS: lower bound, upper bound, if Mirroring enabled then ignore
88  if(!fMirroring) minuit->SetVariableLimits(ParCounter, (*it)->GetLowerBound(i), (*it)->GetUpperBound(i));
89  if((*it)->IsParameterFixed(i))
90  {
91  minuit->FixVariable(ParCounter);
92  }
93  }
94  }
95  else
96  {
97  for(int i = 0; i < (*it)->GetNParameters(); ++i, ++ParCounter)
98  {
99  minuit->SetVariable(ParCounter, Form("%i_PCA", i), (*it)->GetPCAHandler()->GetParPropPCA(i), (*it)->GetPCAHandler()->GetEigenValuesMaster()[i]/10);
100  if((*it)->GetPCAHandler()->IsParameterFixedPCA(i))
101  {
102  minuit->FixVariable(ParCounter);
103  }
104  }
105  }
106  }
107 
108  minuit->SetPrintLevel(2);
109 
110  MACH3LOG_INFO("Starting MIGRAD");
111  minuit->Minimize();
112 
113  MACH3LOG_INFO("Starting HESSE");
114  minuit->Hesse();
115  outputFile->cd();
116 
117  TVectorD* MinuitParValue = new TVectorD(NparsMinuitFull);
118  TVectorD* MinuitParError = new TVectorD(NparsMinuitFull);
119  TMatrixDSym* Postmatrix = new TMatrixDSym(NparsMinuitFull);
120 
121  for(int i = 0; i < NparsMinuitFull; ++i)
122  {
123  (*MinuitParValue)(i) = 0;
124  (*MinuitParError)(i) = 0;
125  for(int j = 0; j < NparsMinuitFull; ++j)
126  {
127  (*Postmatrix)(i,j) = 0;
128  (*Postmatrix)(i,j) = minuit->CovMatrix(i,j);
129  }
130  }
131 
132  ParCounter = 0;
133  const double *X = minuit->X();
134  const double *err = minuit->Errors();
135  for (std::vector<ParameterHandlerBase*>::iterator it = systematics.begin(); it != systematics.end(); ++it)
136  {
137  if(!(*it)->IsPCA())
138  {
139  for(int i = 0; i < (*it)->GetNumParams(); ++i, ++ParCounter)
140  {
141  double ParVal = X[ParCounter];
142  //KS: Basically apply mirroring for parameters out of bounds
143  if(fMirroring)
144  {
145  if(ParVal < (*it)->GetLowerBound(i))
146  {
147  ParVal = (*it)->GetLowerBound(i) + ((*it)->GetLowerBound(i) - ParVal);
148  }
149  else if (ParVal > (*it)->GetUpperBound(i))
150  {
151  ParVal = (*it)->GetUpperBound(i) - ( ParVal - (*it)->GetUpperBound(i));
152  }
153  }
154  (*MinuitParValue)(ParCounter) = ParVal;
155  (*MinuitParError)(ParCounter) = err[ParCounter];
156  //KS: For fixed params HESS will not calculate error so we need to pass prior error
157  if((*it)->IsParameterFixed(i))
158  {
159  (*MinuitParError)(ParCounter) = (*it)->GetDiagonalError(i);
160  (*Postmatrix)(ParCounter,ParCounter) = (*MinuitParError)(ParCounter) * (*MinuitParError)(ParCounter);
161  }
162  }
163  }
164  else
165  {
166  //KS: We need to convert parameters from PCA to normal base
167  TVectorD ParVals((*it)->GetNumParams());
168  TVectorD ParVals_PCA((*it)->GetNParameters());
169 
170  TVectorD ErrorVals((*it)->GetNumParams());
171  TVectorD ErrorVals_PCA((*it)->GetNParameters());
172 
173  TMatrixD MatrixVals((*it)->GetNumParams(), (*it)->GetNumParams());
174  TMatrixD MatrixVals_PCA((*it)->GetNParameters(), (*it)->GetNParameters());
175 
176  //First save them
177  //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.
178  const int StartVal = ParCounter;
179  for(int i = 0; i < (*it)->GetNParameters(); ++i, ++ParCounter)
180  {
181  ParVals_PCA(i) = X[ParCounter];
182  ErrorVals_PCA(i) = err[ParCounter];
183  int ParCounterMatrix = StartVal;
184  for(int j = 0; j < (*it)->GetNParameters(); ++j, ++ParCounterMatrix)
185  {
186  MatrixVals_PCA(i,j) = minuit->CovMatrix(ParCounter,ParCounterMatrix);
187  }
188  }
189  ParVals = ((*it)->GetPCAHandler()->GetTransferMatrix())*ParVals_PCA;
190  ErrorVals = ((*it)->GetPCAHandler()->GetTransferMatrix())*ErrorVals_PCA;
191  MatrixVals.Mult(((*it)->GetPCAHandler()->GetTransferMatrix()),MatrixVals_PCA);
192 
193  ParCounter = StartVal;
194  //KS: Now after going from PCA to normal let';s save it
195  for(int i = 0; i < (*it)->GetNumParams(); ++i, ++ParCounter)
196  {
197  (*MinuitParValue)(ParCounter) = ParVals(i);
198  (*MinuitParError)(ParCounter) = std::fabs(ErrorVals(i));
199  int ParCounterMatrix = StartVal;
200  for(int j = 0; j < (*it)->GetNumParams(); ++j, ++ParCounterMatrix)
201  {
202  (*Postmatrix)(ParCounter,ParCounterMatrix) = MatrixVals(i,j);
203  }
204  //If fixed take prior
205  if((*it)->GetPCAHandler()->IsParameterFixedPCA(i))
206  {
207  (*MinuitParError)(ParCounter) = (*it)->GetDiagonalError(i);
208  (*Postmatrix)(ParCounter,ParCounter) = (*MinuitParError)(ParCounter) * (*MinuitParError)(ParCounter);
209  }
210  }
211  }
212  }
213 
214  MinuitParValue->Write("MinuitParValue");
215  MinuitParError->Write("MinuitParError");
216  Postmatrix->Write("Postmatrix");
217  delete MinuitParValue;
218  delete MinuitParError;
219  delete Postmatrix;
220  // Save all the output
221  SaveOutput();
222 }
223 
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:37
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:35
void SaveOutput()
Save output and close files.
Definition: FitterBase.cpp:231
TFile * outputFile
Output.
Definition: FitterBase.h:147
std::string AlgorithmName
Name of fitting algorithm that is being used.
Definition: FitterBase.h:168
Manager * fitMan
The manager for configuration handling.
Definition: FitterBase.h:108
void SanitiseInputs()
Remove obsolete memory and make other checks before fit starts.
Definition: FitterBase.cpp:223
std::vector< ParameterHandlerBase * > systematics
Systematic holder.
Definition: FitterBase.h:134
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:41
std::unique_ptr< ROOT::Math::Minimizer > minuit
Pointer to minimizer, which most often is Minuit.
Definition: MinuitFit.h:27
MinuitFit(Manager *const fitMan)
Constructor.
Definition: MinuitFit.cpp:5
void RunMCMC() override
Actual implementation of Minuit Fit algorithm.
Definition: MinuitFit.cpp:41
virtual ~MinuitFit()
Destructor.
Definition: MinuitFit.cpp:34