laura is hosted by Hepforge, IPPP Durham
Laura++  v3r5
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 
50 
51 
52 LauMinuit::LauMinuit( Int_t maxPar ) : LauAbsFitter(),
53  minuit_(0),
54  maxPar_(maxPar),
55  nParams_(0),
56  nFreeParams_(0),
57  twoStageFit_(kFALSE),
58  useAsymmFitErrors_(kFALSE),
59  fitStatus_({-1,0.0,0.0})
60 {
61  TVirtualFitter::SetDefaultFitter( "Minuit" );
62  minuit_ = TVirtualFitter::Fitter( 0, maxPar_ );
63 }
64 
66 {
67 }
68 
69 void LauMinuit::initialise( LauFitObject* fitObj, const std::vector<LauParameter*>& parameters )
70 {
71  // Check whether we're going to use asymmetric errors
72  if (useAsymmFitErrors_ == kTRUE) {
73  std::cout << "INFO in LauMinuit::fit : We are going to calculate the asymmetric fit errors." << std::endl;
74  std::cout << " : This will, in general, significantly increase the CPU time required for fitting." << std::endl;
75  } else {
76  std::cout << "INFO in LauMinuit::fit : Only parabolic errors will be calculated." << std::endl;
77  }
78 
79  // Store the parameters
80  params_ = parameters;
81 
82  // Hook the external likelihood function to this LauFitter::fitter() and this class.
83  minuit_->SetFCN( logLikeFun );
84  minuit_->SetObjectFit( fitObj );
85 
86  // Clear any stored parameters etc... before using
87  minuit_->Clear();
88 
89  nParams_ = params_.size();
90  std::cout << "INFO in LauMinuit::initialise : Setting fit parameters" << std::endl;
91  std::cout << " : Total number of parameters = " << nParams_ << std::endl;
92 
93  // Define the default relative error
94  const Double_t defaultError(0.01);
95 
96  // Set-up the parameters
97  for (UInt_t i = 0; i < nParams_; ++i) {
98  TString name = params_[i]->name();
99  Double_t initVal = params_[i]->initValue();
100  Double_t initErr = params_[i]->error();
101  // If we do not have a supplied estimate of the error, we should make a reasonable guess
102  if ( initErr == 0.0 ) {
103  if ( initVal == 0.0 ) {
104  initErr = defaultError;
105  } else if ( TMath::Abs(initErr/initVal) < 1e-6 ) {
106  initErr = TMath::Abs(defaultError * initVal);
107  }
108  }
109  Double_t minVal = params_[i]->minValue();
110  Double_t maxVal = params_[i]->maxValue();
111  Bool_t secondStage = params_[i]->secondStage();
112  if (this->twoStageFit() && secondStage == kTRUE) {
113  params_[i]->fixed(kTRUE);
114  }
115  Bool_t fixVar = params_[i]->fixed();
116 
117  std::cout << " : Setting parameter " << i << " called " << name << " to have initial value " << initVal << ", error " << initErr << " and range " << minVal << " to " << maxVal << std::endl;
118  minuit_->SetParameter(i, name, initVal, initErr, minVal, maxVal);
119 
120  // Fix parameter if required
121  if (fixVar == kTRUE) {
122  std::cout << " : Fixing parameter " << i << std::endl;
123  minuit_->FixParameter(i);
124  }
125  }
126 
127  LauParamFixed pred;
128  nFreeParams_ = nParams_ - std::count_if(params_.begin(),params_.end(),pred);
129 
130  // Need to set the "SET ERR" command to +0.5 for +/-1 sigma errors
131  // for maximum likelihood fit. Very important command, otherwise all
132  // extracted errors will be too big, and pull distributions will be too narrow!
133  // TODO - The alternative to this is to make FCN = -2log(L) rather than -log(L)
134  Double_t argL[2];
135  argL[0] = 0.5;
136  fitStatus_.status = minuit_->ExecuteCommand("SET ERR", argL, 1);
137 
138  //argL[0] = 0;
139  //fitStatus_.status = minuit_->ExecuteCommand("SET STRATEGY", argL, 1);
140 }
141 
143 {
144  return (minuit_!=0) ? dynamic_cast<LauFitObject*>( minuit_->GetObjectFit() ) : 0;
145 }
146 
148 {
149  Double_t arglist[2];
150  arglist[0] = 1000*nParams_; // maximum iterations
151  arglist[1] = 0.05; // tolerance -> min EDM = 0.001*tolerance (0.05)
152  fitStatus_.status = minuit_->ExecuteCommand("MIGRAD", arglist, 2);
153 
154  // Dummy variables - need to feed them to the function
155  // used for getting NLL, EDM and error matrix status
156  Double_t errdef;
157  Int_t nvpar, nparx;
158 
159  if (fitStatus_.status != 0) {
160 
161  std::cerr << "ERROR in LauMinuit::minimise : Error in minimising loglike." << std::endl;
162 
163  } else {
164 
165  // Check that the error matrix is ok
166  fitStatus_.status = minuit_->GetStats(fitStatus_.NLL, fitStatus_.EDM, errdef, nvpar, nparx);
167  std::cout << "INFO in LauMinuit::minimise : Error matrix status after MIGRAD is: " << fitStatus_.status << std::endl;
168  // 0= not calculated at all
169  // 1= approximation only, not accurate
170  // 2= full matrix, but forced positive-definite
171  // 3= full accurate covariance matrix
172 
173  // Fit result was OK. Now get the more precise errors.
174  fitStatus_.status = minuit_->ExecuteCommand("HESSE", arglist, 1);
175 
176  if (fitStatus_.status != 0) {
177 
178  std::cerr << "ERROR in LauMinuit::minimise : Error in HESSE routine." << std::endl;
179 
180  } else {
181 
182  // Check that the error matrix is ok
183  fitStatus_.status = minuit_->GetStats(fitStatus_.NLL, fitStatus_.EDM, errdef, nvpar, nparx);
184  std::cout << "INFO in LauMinuit::minimise : Error matrix status after HESSE is: " << fitStatus_.status << std::endl;
185  // 0= not calculated at all
186  // 1= approximation only, not accurate
187  // 2= full matrix, but forced positive-definite
188  // 3= full accurate covariance matrix
189 
190  // Symmetric errors and eror matrix were OK.
191  // Get asymmetric errors if asked for.
192  if (useAsymmFitErrors_ == kTRUE) {
193  LauFitObject* fitObj = this->getFitObject();
194  fitObj->withinAsymErrorCalc( kTRUE );
195  fitStatus_.status = minuit_->ExecuteCommand("MINOS", arglist, 1);
196  fitObj->withinAsymErrorCalc( kFALSE );
197  if (fitStatus_.status != 0) {
198  std::cerr << "ERROR in LauMinuit::minimise : Error in MINOS routine." << std::endl;
199  }
200  }
201  }
202  }
203 
204  // Print results
205  fitStatus_.status = minuit_->GetStats(fitStatus_.NLL, fitStatus_.EDM, errdef, nvpar, nparx);
206  std::cout << "INFO in LauMinuit::minimise : Final error matrix status is: " << fitStatus_.status << std::endl;
207  // 0= not calculated at all
208  // 1= approximation only, not accurate
209  // 2= full matrix, but forced positive-definite
210  // 3= full accurate covariance matrix
211 
212  minuit_->PrintResults(3, fitStatus_.NLL);
213 
214  // Retrieve the covariance matrix from the fitter
215  // For some reason the array returned is as if the matrix is of dimension nParams_ x nParams_
216  // but only the elements within the sub-matrix nFreeParams_ x nFreeParams_ have values,
217  // the "trailing" elements are zero, so we trim them off.
218  Double_t* covMatrix = minuit_->GetCovarianceMatrix();
219  covMatrix_.Clear();
220  covMatrix_.ResizeTo( nParams_, nParams_ );
221  covMatrix_.SetMatrixArray( covMatrix );
222  covMatrix_.ResizeTo( nFreeParams_, nFreeParams_ );
223 
224  return fitStatus_;
225 }
226 
228 {
229  for (UInt_t i = 0; i < nParams_; ++i) {
230  Bool_t secondStage = params_[i]->secondStage();
231  if (secondStage == kTRUE) {
232  params_[i]->fixed(kTRUE);
233  minuit_->FixParameter(i);
234  }
235  }
236  LauParamFixed pred;
237  nFreeParams_ = nParams_ - std::count_if(params_.begin(),params_.end(),pred);
238 }
239 
241 {
242  for (UInt_t i = 0; i < nParams_; ++i) {
243  Bool_t secondStage = params_[i]->secondStage();
244  if (secondStage == kTRUE) {
245  params_[i]->fixed(kFALSE);
246  minuit_->ReleaseParameter(i);
247  }
248  }
249  LauParamFixed pred;
250  nFreeParams_ = nParams_ - std::count_if(params_.begin(),params_.end(),pred);
251 }
252 
254 {
255  for (UInt_t i = 0; i < nParams_; ++i) {
256  // Get the value and errors from MINUIT
257  Double_t value = minuit_->GetParameter(i);
258  Double_t error(0.0);
259  Double_t negError(0.0);
260  Double_t posError(0.0);
261  Double_t globalcc(0.0);
262  minuit_->GetErrors(i, posError, negError, error, globalcc);
263  params_[i]->valueAndErrors(value, error, negError, posError);
264  params_[i]->globalCorrelationCoeff(globalcc);
265  }
266 }
267 
268 // Definition of the fitting function for Minuit
269 void logLikeFun(Int_t& npar, Double_t* /*first_derivatives*/, Double_t& f, Double_t* par, Int_t /*iflag*/)
270 {
271  // Routine that specifies the negative log-likelihood function for the fit.
272  // Used by the MINUIT minimising code.
273 
275 
276  // Set the internal parameters for this model using parameters from Minuit (pars):
277  theModel->setParsFromMinuit( par, npar );
278 
279  // Set the value of f to be the total negative log-likelihood for the data sample.
280  f = theModel->getTotNegLogLikelihood();
281 }
282 
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:240
virtual Double_t getTotNegLogLikelihood()=0
Calculate the new value of the negative log likelihood.
File containing declaration of LauParamFixed class.
ClassImp(LauAbsCoeffSet)
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:253
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:69
virtual ~LauMinuit()
Destructor.
Definition: LauMinuit.cc:65
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.
The interface to the Minuit fitter.
Definition: LauMinuit.hh:50
void logLikeFun(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag)
Definition: LauMinuit.cc:269
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:62
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:51
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:147
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:227
virtual LauFitObject * getFitObject()
Get the object that controls the calculation of the likelihood.
Definition: LauMinuit.cc:142
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