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