laura is hosted by Hepforge, IPPP Durham
Laura++  v3r4
A maximum likelihood fitting package for performing Dalitz-plot analysis.
LauMinuit.cc
Go to the documentation of this file.
1 
2 /*
3 Copyright 2013 University of Warwick
4 
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8 
9  http://www.apache.org/licenses/LICENSE-2.0
10 
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 */
17 
18 /*
19 Laura++ package authors:
20 John Back
21 Paul Harrison
22 Thomas Latham
23 */
24 
29 #include <iostream>
30 #include <algorithm>
31 
32 #include "TMatrixD.h"
33 #include "TVirtualFitter.h"
34 
35 #include "LauFitObject.hh"
36 #include "LauFitter.hh"
37 #include "LauMinuit.hh"
38 #include "LauParameter.hh"
39 #include "LauParamFixed.hh"
40 
41 // It's necessary to define an external function that specifies the address of the function
42 // that Minuit needs to minimise. Minuit doesn't know about any classes - therefore
43 // use gMinuit->SetFCN(external_function), gMinuit->SetObjectFit(this).
44 // Here, we use TVirtualFitter* fitter instead of gMinuit, defined below.
45 // Then, within the external function, invoke an object from this class (LauAllModel),
46 // and use the member functions to access the parameters/variables.
47 extern void logLikeFun(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag);
48 
49 
50 LauMinuit::LauMinuit( Int_t maxPar ) : LauAbsFitter(),
51  minuit_(0),
52  maxPar_(maxPar),
53  nParams_(0),
54  nFreeParams_(0),
55  twoStageFit_(kFALSE),
56  useAsymmFitErrors_(kFALSE),
57  fitStatus_({-1,0.0,0.0})
58 {
59  TVirtualFitter::SetDefaultFitter( "Minuit" );
60  minuit_ = TVirtualFitter::Fitter( 0, maxPar_ );
61 }
62 
64 {
65 }
66 
67 void LauMinuit::initialise( LauFitObject* fitObj, const std::vector<LauParameter*>& parameters )
68 {
69  // Check whether we're going to use asymmetric errors
70  if (useAsymmFitErrors_ == kTRUE) {
71  std::cout << "INFO in LauMinuit::fit : We are going to calculate the asymmetric fit errors." << std::endl;
72  std::cout << " : This will, in general, significantly increase the CPU time required for fitting." << std::endl;
73  } else {
74  std::cout << "INFO in LauMinuit::fit : Only parabolic errors will be calculated." << std::endl;
75  }
76 
77  // Store the parameters
78  params_ = parameters;
79 
80  // Hook the external likelihood function to this LauFitter::fitter() and this class.
81  minuit_->SetFCN( logLikeFun );
82  minuit_->SetObjectFit( fitObj );
83 
84  // Clear any stored parameters etc... before using
85  minuit_->Clear();
86 
87  nParams_ = params_.size();
88  std::cout << "INFO in LauMinuit::initialise : Setting fit parameters" << std::endl;
89  std::cout << " : Total number of parameters = " << nParams_ << std::endl;
90 
91  // Define the default relative error
92  const Double_t defaultError(0.01);
93 
94  // Set-up the parameters
95  for (UInt_t i = 0; i < nParams_; ++i) {
96  TString name = params_[i]->name();
97  Double_t initVal = params_[i]->initValue();
98  Double_t initErr = params_[i]->error();
99  // If we do not have a supplied estimate of the error, we should make a reasonable guess
100  if ( initErr == 0.0 ) {
101  if ( initVal == 0.0 ) {
102  initErr = defaultError;
103  } else if ( TMath::Abs(initErr/initVal) < 1e-6 ) {
104  initErr = TMath::Abs(defaultError * initVal);
105  }
106  }
107  Double_t minVal = params_[i]->minValue();
108  Double_t maxVal = params_[i]->maxValue();
109  Bool_t secondStage = params_[i]->secondStage();
110  if (this->twoStageFit() && secondStage == kTRUE) {
111  params_[i]->fixed(kTRUE);
112  }
113  Bool_t fixVar = params_[i]->fixed();
114 
115  std::cout << " : Setting parameter " << i << " called " << name << " to have initial value " << initVal << ", error " << initErr << " and range " << minVal << " to " << maxVal << std::endl;
116  minuit_->SetParameter(i, name, initVal, initErr, minVal, maxVal);
117 
118  // Fix parameter if required
119  if (fixVar == kTRUE) {
120  std::cout << " : Fixing parameter " << i << std::endl;
121  minuit_->FixParameter(i);
122  }
123  }
124 
125  LauParamFixed pred;
126  nFreeParams_ = nParams_ - std::count_if(params_.begin(),params_.end(),pred);
127 
128  // Need to set the "SET ERR" command to +0.5 for +/-1 sigma errors
129  // for maximum likelihood fit. Very important command, otherwise all
130  // extracted errors will be too big, and pull distributions will be too narrow!
131  // TODO - The alternative to this is to make FCN = -2log(L) rather than -log(L)
132  Double_t argL[2];
133  argL[0] = 0.5;
134  fitStatus_.status = minuit_->ExecuteCommand("SET ERR", argL, 1);
135 
136  //argL[0] = 0;
137  //fitStatus_.status = minuit_->ExecuteCommand("SET STRATEGY", argL, 1);
138 }
139 
141 {
142  return (minuit_!=0) ? dynamic_cast<LauFitObject*>( minuit_->GetObjectFit() ) : 0;
143 }
144 
146 {
147  Double_t arglist[2];
148  arglist[0] = 1000*nParams_; // maximum iterations
149  arglist[1] = 0.05; // tolerance -> min EDM = 0.001*tolerance (0.05)
150  fitStatus_.status = minuit_->ExecuteCommand("MIGRAD", arglist, 2);
151 
152  // Dummy variables - need to feed them to the function
153  // used for getting NLL, EDM and error matrix status
154  Double_t errdef;
155  Int_t nvpar, nparx;
156 
157  if (fitStatus_.status != 0) {
158 
159  std::cerr << "ERROR in LauMinuit::minimise : Error in minimising loglike." << std::endl;
160 
161  } else {
162 
163  // Check that the error matrix is ok
164  fitStatus_.status = minuit_->GetStats(fitStatus_.NLL, fitStatus_.EDM, errdef, nvpar, nparx);
165  std::cout << "INFO in LauMinuit::minimise : Error matrix status after MIGRAD is: " << fitStatus_.status << std::endl;
166  // 0= not calculated at all
167  // 1= approximation only, not accurate
168  // 2= full matrix, but forced positive-definite
169  // 3= full accurate covariance matrix
170 
171  // Fit result was OK. Now get the more precise errors.
172  fitStatus_.status = minuit_->ExecuteCommand("HESSE", arglist, 1);
173 
174  if (fitStatus_.status != 0) {
175 
176  std::cerr << "ERROR in LauMinuit::minimise : Error in HESSE routine." << std::endl;
177 
178  } else {
179 
180  // Check that the error matrix is ok
181  fitStatus_.status = minuit_->GetStats(fitStatus_.NLL, fitStatus_.EDM, errdef, nvpar, nparx);
182  std::cout << "INFO in LauMinuit::minimise : Error matrix status after HESSE is: " << fitStatus_.status << std::endl;
183  // 0= not calculated at all
184  // 1= approximation only, not accurate
185  // 2= full matrix, but forced positive-definite
186  // 3= full accurate covariance matrix
187 
188  // Symmetric errors and eror matrix were OK.
189  // Get asymmetric errors if asked for.
190  if (useAsymmFitErrors_ == kTRUE) {
191  LauFitObject* fitObj = this->getFitObject();
192  fitObj->withinAsymErrorCalc( kTRUE );
193  fitStatus_.status = minuit_->ExecuteCommand("MINOS", arglist, 1);
194  fitObj->withinAsymErrorCalc( kFALSE );
195  if (fitStatus_.status != 0) {
196  std::cerr << "ERROR in LauMinuit::minimise : Error in MINOS routine." << std::endl;
197  }
198  }
199  }
200  }
201 
202  // Print results
203  fitStatus_.status = minuit_->GetStats(fitStatus_.NLL, fitStatus_.EDM, errdef, nvpar, nparx);
204  std::cout << "INFO in LauMinuit::minimise : Final error matrix status is: " << fitStatus_.status << std::endl;
205  // 0= not calculated at all
206  // 1= approximation only, not accurate
207  // 2= full matrix, but forced positive-definite
208  // 3= full accurate covariance matrix
209 
210  minuit_->PrintResults(3, fitStatus_.NLL);
211 
212  // Retrieve the covariance matrix from the fitter
213  // For some reason the array returned is as if the matrix is of dimension nParams_ x nParams_
214  // but only the elements within the sub-matrix nFreeParams_ x nFreeParams_ have values,
215  // the "trailing" elements are zero, so we trim them off.
216  Double_t* covMatrix = minuit_->GetCovarianceMatrix();
217  covMatrix_.Clear();
218  covMatrix_.ResizeTo( nParams_, nParams_ );
219  covMatrix_.SetMatrixArray( covMatrix );
220  covMatrix_.ResizeTo( nFreeParams_, nFreeParams_ );
221 
222  return fitStatus_;
223 }
224 
226 {
227  for (UInt_t i = 0; i < nParams_; ++i) {
228  Bool_t secondStage = params_[i]->secondStage();
229  if (secondStage == kTRUE) {
230  params_[i]->fixed(kTRUE);
231  minuit_->FixParameter(i);
232  }
233  }
234  LauParamFixed pred;
235  nFreeParams_ = nParams_ - std::count_if(params_.begin(),params_.end(),pred);
236 }
237 
239 {
240  for (UInt_t i = 0; i < nParams_; ++i) {
241  Bool_t secondStage = params_[i]->secondStage();
242  if (secondStage == kTRUE) {
243  params_[i]->fixed(kFALSE);
244  minuit_->ReleaseParameter(i);
245  }
246  }
247  LauParamFixed pred;
248  nFreeParams_ = nParams_ - std::count_if(params_.begin(),params_.end(),pred);
249 }
250 
252 {
253  for (UInt_t i = 0; i < nParams_; ++i) {
254  // Get the value and errors from MINUIT
255  Double_t value = minuit_->GetParameter(i);
256  Double_t error(0.0);
257  Double_t negError(0.0);
258  Double_t posError(0.0);
259  Double_t globalcc(0.0);
260  minuit_->GetErrors(i, posError, negError, error, globalcc);
261  params_[i]->valueAndErrors(value, error, negError, posError);
262  params_[i]->globalCorrelationCoeff(globalcc);
263  }
264 }
265 
266 // Definition of the fitting function for Minuit
267 void logLikeFun(Int_t& npar, Double_t* /*first_derivatives*/, Double_t& f, Double_t* par, Int_t /*iflag*/)
268 {
269  // Routine that specifies the negative log-likelihood function for the fit.
270  // Used by the MINUIT minimising code.
271 
273 
274  // Set the internal parameters for this model using parameters from Minuit (pars):
275  theModel->setParsFromMinuit( par, npar );
276 
277  // Set the value of f to be the total negative log-likelihood for the data sample.
278  f = theModel->getTotNegLogLikelihood();
279 }
280 
UInt_t nParams_
The total number of parameters.
Definition: LauMinuit.hh:139
Double_t EDM
The estimated distance to the minimum.
Definition: LauAbsFitter.hh:61
virtual void releaseSecondStageParameters()
Release parameters marked as &quot;second stage&quot;.
Definition: LauMinuit.cc:238
virtual Double_t getTotNegLogLikelihood()=0
Calculate the new value of the negative log likelihood.
File containing declaration of LauParamFixed class.
FitStatus fitStatus_
The status of the fit.
Definition: LauMinuit.hh:151
virtual void updateParameters()
Update the values and errors of the parameters based on the fit minimum.
Definition: LauMinuit.cc:251
const TString & name() const
The parameter name.
virtual void initialise(LauFitObject *fitObj, const std::vector< LauParameter * > &parameters)
Initialise the fitter, setting the information on the parameters.
Definition: LauMinuit.cc:67
virtual ~LauMinuit()
Destructor.
Definition: LauMinuit.cc:63
LauMinuit(Int_t maxPar=100)
Constructor.
Definition: LauMinuit.cc:50
virtual void setParsFromMinuit(Double_t *par, Int_t npar)=0
This function sets the parameter values from Minuit.
Double_t negError() const
The lower error on the parameter.
void logLikeFun(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag)
Definition: LauMinuit.cc:267
Double_t posError() const
The upper error on the parameter.
File containing declaration of LauFitter class.
The abstract interface to the fitter.
Definition: LauAbsFitter.hh:48
minuit_
Definition: LauMinuit.cc:60
Double_t NLL
The negative log-likelihood.
Definition: LauAbsFitter.hh:59
virtual Bool_t twoStageFit() const
Determine whether the two-stage fit is enabled.
Definition: LauMinuit.hh:73
Int_t status
The status code of the fit.
Definition: LauAbsFitter.hh:57
TMatrixD covMatrix_
The covariance matrix.
Definition: LauMinuit.hh:154
File containing declaration of LauParameter class.
Struct to store fit status information.
Definition: LauAbsFitter.hh:55
Predicate to allow counting of the number of fixed parameters.
Bool_t secondStage() const
Check whether the parameter should be floated only in the second stage of a two stage fit...
Double_t error() const
The error on the parameter.
Bool_t useAsymmFitErrors_
Option to use asymmetric errors.
Definition: LauMinuit.hh:148
virtual void withinAsymErrorCalc(const Bool_t inAsymErrCalc)
Mark that the fit is calculating asymmetric errors.
Definition: LauFitObject.hh:82
static LauAbsFitter * fitter()
Method that provides access to the singleton fitter.
Definition: LauFitter.cc:48
virtual LauFitObject * getFitObject()=0
Get the object that controls the calculation of the likelihood.
UInt_t nFreeParams_
The number of free parameters.
Definition: LauMinuit.hh:142
File containing declaration of LauFitObject class.
virtual const FitStatus & minimise()
Perform the minimisation of the fit function.
Definition: LauMinuit.cc:145
TVirtualFitter * minuit_
The interface to Minuit.
Definition: LauMinuit.hh:130
Double_t value() const
The value of the parameter.
virtual void fixSecondStageParameters()
Fix parameters marked as &quot;second stage&quot;.
Definition: LauMinuit.cc:225
virtual LauFitObject * getFitObject()
Get the object that controls the calculation of the likelihood.
Definition: LauMinuit.cc:140
std::vector< LauParameter * > params_
The fit parameters.
Definition: LauMinuit.hh:136
File containing declaration of LauMinuit class.
The abstract interface for the objects that control the calculation of the likelihood.
Definition: LauFitObject.hh:44