laura is hosted by Hepforge, IPPP Durham
Laura++  v3r2
A maximum likelihood fitting package for performing Dalitz-plot analysis.
LauRooFitSlave.cc
Go to the documentation of this file.
1 
2 // Copyright University of Warwick 2016 - 2017.
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 <vector>
17 
18 #include "RooRealVar.h"
19 #include "RooDataSet.h"
20 #include "TFile.h"
21 #include "TString.h"
22 #include "TSystem.h"
23 #include "TTree.h"
24 
25 #include "LauFitNtuple.hh"
26 #include "LauParameter.hh"
27 #include "LauSimFitSlave.hh"
28 #include "LauRooFitSlave.hh"
29 
31 
32 
33 LauRooFitSlave::LauRooFitSlave( RooAbsPdf& model, const Bool_t extended, const RooArgSet& vars, const TString& weightVarName ) :
35  model_(model),
36  dataVars_(vars),
37  weightVarName_(weightVarName),
38  dataFile_(0),
39  dataTree_(0),
40  exptData_(0),
41  extended_(extended),
42  iExptCat_("iExpt","Expt Number"),
43  nllVar_(0)
44 {
45 }
46 
48 {
49  delete nllVar_; nllVar_ = 0;
50  this->cleanData();
51 }
52 
54 {
55  if ( dataFile_ != 0 ) {
56  dataFile_->Close();
57  delete dataFile_;
58  dataTree_ = 0;
59  dataFile_ = 0;
60  }
61  delete exptData_;
62  exptData_ = 0;
63 }
64 
66 {
67  if ( weightVarName_ != "" ) {
68  Bool_t weightVarFound = kFALSE;
69  RooFIter argset_iter = dataVars_.fwdIterator();
70  RooAbsArg* param(0);
71  while ( (param = argset_iter.next()) ) {
72  TString name = param->GetName();
73  if ( name == weightVarName_ ) {
74  weightVarFound = kTRUE;
75  break;
76  }
77  }
78  if ( ! weightVarFound ) {
79  std::cerr << "ERROR in LauRooFitSlave::initialise : The set of data variables does not contain the weighting variable \"" << weightVarName_ << std::endl;
80  std::cerr << " : Weighting will be disabled." << std::endl;
81  weightVarName_ = "";
82  }
83  }
84 }
85 
86 Bool_t LauRooFitSlave::verifyFitData(const TString& dataFileName, const TString& dataTreeName)
87 {
88  // Clean-up from any previous runs
89  if ( dataFile_ != 0 ) {
90  this->cleanData();
91  }
92 
93  // Open the data file
94  dataFile_ = TFile::Open( dataFileName );
95  if ( ! dataFile_ ) {
96  std::cerr << "ERROR in LauRooFitSlave::verifyFitData : Problem opening data file \"" << dataFileName << "\"" << std::endl;
97  return kFALSE;
98  }
99 
100  // Retrieve the tree
101  dataTree_ = dynamic_cast<TTree*>( dataFile_->Get( dataTreeName ) );
102  if ( ! dataTree_ ) {
103  std::cerr << "ERROR in LauRooFitSlave::verifyFitData : Problem retrieving tree \"" << dataTreeName << "\" from data file \"" << dataFileName << "\"" << std::endl;
104  dataFile_->Close();
105  delete dataFile_;
106  dataFile_ = 0;
107  return kFALSE;
108  }
109 
110  // Check that the tree contains branches for all the fit variables
111  RooFIter argset_iter = dataVars_.fwdIterator();
112  RooAbsArg* param(0);
113  Bool_t allOK(kTRUE);
114  while ( (param = argset_iter.next()) ) {
115  TString name = param->GetName();
116  TBranch* branch = dataTree_->GetBranch( name );
117  if ( branch == 0 ) {
118  std::cerr << "ERROR in LauRooFitSlave::verifyFitData : The data tree does not contain a branch for fit variable \"" << name << std::endl;
119  allOK = kFALSE;
120  }
121  }
122  if ( ! allOK ) {
123  return kFALSE;
124  }
125 
126  // Check whether the tree has the branch iExpt
127  TBranch* branch = dataTree_->GetBranch("iExpt");
128  if ( branch == 0 ) {
129  std::cout << "WARNING in LauRooFitSlave::verifyFitData : Cannot find branch \"iExpt\" in the tree, will treat all data as being from a single experiment" << std::endl;
130  } else {
131  // Define the valid values for the iExpt RooCategory
132  iExptCat_.clearTypes();
133  const UInt_t firstExp = dataTree_->GetMinimum("iExpt");
134  const UInt_t lastExp = dataTree_->GetMaximum("iExpt");
135  for ( UInt_t iExp = firstExp; iExp <= lastExp; ++iExp ) {
136  iExptCat_.defineType( TString::Format("expt%d",iExp), iExp );
137  }
138  }
139 
140  return kTRUE;
141 }
142 
144 {
145  // Check that the NLL variable has been initialised
146  if ( ! nllVar_ ) {
147  std::cerr << "ERROR in LauRooFitSlave::prepareInitialParArray : NLL var not initialised" << std::endl;
148  return;
149  }
150 
151  // If we already prepared the entries in the fitPars_ vector then we only need to add the contents to the array
152  if ( ! fitPars_.empty() ) {
153  for ( std::vector<LauParameter*>::iterator iter = fitPars_.begin(); iter != fitPars_.end(); ++iter ) {
154  array.Add(*iter);
155  }
156  return;
157  }
158 
159  // Store the set of parameters and the total number of parameters
160  RooArgSet* varSet = nllVar_->getParameters( exptData_ );
161  UInt_t nFreePars(0);
162 
163  // Loop through the fit parameters
164  RooFIter argset_iter = varSet->fwdIterator();
165  RooAbsArg* param(0);
166  while ( (param = argset_iter.next()) ) {
167  // Only consider the free parameters
168  if ( ! param->isConstant() ) {
169  // Add the parameter
170  RooRealVar* rrvar = dynamic_cast<RooRealVar*>( param );
171  if ( rrvar != 0 ) {
172  // Count the number of free parameters
173  ++nFreePars;
174  // Do the conversion and add it to the array
175  LauParameter* lpar = this->convertToLauParameter( rrvar );
176  fitVars_.push_back( rrvar );
177  fitPars_.push_back( lpar );
178  array.Add( lpar );
179  } else {
180  RooFormulaVar* rfvar = dynamic_cast<RooFormulaVar*>( param );
181  if ( rfvar == 0 ) {
182  std::cerr << "ERROR in LauRooFitSlave::prepareInitialParArray : The parameter is neither a RooRealVar nor a RooFormulaVar, don't know what to do" << std::endl;
183  continue;
184  }
185  std::vector< std::pair<RooRealVar*,LauParameter*> > lpars = this->convertToLauParameters( rfvar );
186  for ( std::vector< std::pair<RooRealVar*,LauParameter*> >::iterator iter = lpars.begin(); iter != lpars.end(); ++iter ) {
187  RooRealVar* rrv = iter->first;
188  LauParameter* lpar = iter->second;
189  if ( ! rrv->isConstant() ) {
190  continue;
191  }
192 
193  // Count the number of free parameters
194  ++nFreePars;
195  // Add the parameter to the array
196  fitVars_.push_back( rrvar );
197  fitPars_.push_back( lpar );
198  array.Add( lpar );
199  }
200  }
201  }
202  }
203  delete varSet;
204 
205  this->startNewFit( nFreePars, nFreePars );
206 }
207 
208 LauParameter* LauRooFitSlave::convertToLauParameter( const RooRealVar* rooParameter ) const
209 {
210  return new LauParameter( rooParameter->GetName(), rooParameter->getVal(), rooParameter->getMin(), rooParameter->getMax(), rooParameter->isConstant() );
211 }
212 
213 std::vector< std::pair<RooRealVar*,LauParameter*> > LauRooFitSlave::convertToLauParameters( const RooFormulaVar* rooFormula ) const
214 {
215  // Create the empty vector
216  std::vector< std::pair<RooRealVar*,LauParameter*> > lauParameters;
217 
218  Int_t parIndex(0);
219  RooAbsArg* rabsarg(0);
220  RooRealVar* rrvar(0);
221  RooFormulaVar* rfvar(0);
222  // Loop through all the parameters of the formula
223  while ( (rabsarg = rooFormula->getParameter(parIndex)) ) {
224  // First try converting to a RooRealVar
225  rrvar = dynamic_cast<RooRealVar*>( rabsarg );
226  if ( rrvar ) {
227  // Do the conversion and add it to the array
228  LauParameter* lpar = this->convertToLauParameter( rrvar );
229  lauParameters.push_back( std::make_pair(rrvar,lpar) );
230  continue;
231  }
232 
233  // If that didn't work, try converting to a RooFormulaVar
234  rfvar = dynamic_cast<RooFormulaVar*>( rabsarg );
235  if ( rfvar ) {
236  // Do the conversion and add these to the array
237  std::vector< std::pair<RooRealVar*,LauParameter*> > lpars = this->convertToLauParameters( rfvar );
238  for ( std::vector< std::pair<RooRealVar*,LauParameter*> >::iterator iter = lpars.begin(); iter != lpars.end(); ++iter ) {
239  lauParameters.push_back( *iter );
240  }
241  continue;
242  }
243 
244  // If neither of those worked we don't know what to do, so print an error message and continue
245  std::cerr << "ERROR in LauRooFitSlave::convertToLauParameters : One of the parameters is not a RooRealVar nor a RooFormulaVar, it is a: " << rabsarg->ClassName() << std::endl;
246  std::cerr << " : Do not know how to process that - it will be skipped." << std::endl;
247  }
248 
249  return lauParameters;
250 }
251 
253 {
254  Double_t nLL = (nllVar_ != 0) ? nllVar_->getVal() : 0.0;
255  return nLL;
256 }
257 
258 void LauRooFitSlave::setParsFromMinuit(Double_t* par, Int_t npar)
259 {
260  // This function sets the internal parameters based on the values
261  // that Minuit is using when trying to minimise the total likelihood function.
262 
263  // MINOS reports different numbers of free parameters depending on the
264  // situation, so disable this check
265  const UInt_t nFreePars = this->nFreeParams();
266  if ( ! this->withinAsymErrorCalc() ) {
267  if (static_cast<UInt_t>(npar) != nFreePars) {
268  std::cerr << "ERROR in LauRooFitSlave::setParsFromMinuit : Unexpected number of free parameters: " << npar << ".\n";
269  std::cerr << " Expected: " << nFreePars << ".\n" << std::endl;
270  gSystem->Exit(EXIT_FAILURE);
271  }
272  }
273 
274  // Despite npar being the number of free parameters
275  // the par array actually contains all the parameters,
276  // free and floating...
277 
278  // Update all the floating ones with their new values
279  for (UInt_t i(0); i<nFreePars; ++i) {
280  if (!fitPars_[i]->fixed()) {
281  // Set both the RooRealVars and the LauParameters
282  fitPars_[i]->value(par[i]);
283  fitVars_[i]->setVal(par[i]);
284  }
285  }
286 }
287 
289 {
290  // check that we're being asked to read a valid index
291  const UInt_t exptIndex = this->iExpt();
292  if ( iExptCat_.numTypes() == 0 && exptIndex != 0 ) {
293  std::cerr << "ERROR in LauRooFitSlave::readExperimentData : Invalid experiment number " << exptIndex << ", data contains only one experiment" << std::endl;
294  return 0;
295  } else if ( ! iExptCat_.isValidIndex( exptIndex ) ) {
296  std::cerr << "ERROR in LauRooFitSlave::readExperimentData : Invalid experiment number " << exptIndex << std::endl;
297  return 0;
298  }
299 
300  // cleanup the data from any previous experiment
301  delete exptData_;
302 
303  // retrieve the data and find out how many events have been read
304  if ( iExptCat_.numTypes() == 0 ) {
305  exptData_ = new RooDataSet( TString::Format("expt%dData",exptIndex), "", dataTree_, dataVars_, "", (weightVarName_ != "") ? weightVarName_.Data() : 0 );
306  } else {
307  const TString selectionString = TString::Format("iExpt==%d",exptIndex);
308  TTree* exptTree = dataTree_->CopyTree(selectionString);
309  exptData_ = new RooDataSet( TString::Format("expt%dData",exptIndex), "", exptTree, dataVars_, "", (weightVarName_ != "") ? weightVarName_.Data() : 0 );
310  delete exptTree;
311  }
312 
313  const UInt_t nEvent = exptData_->numEntries();
314  this->eventsPerExpt( nEvent );
315  return nEvent;
316 }
317 
319 {
320  // cleanup the old NLL info
321  delete nllVar_;
322 
323  // construct the new NLL variable for this dataset
324  nllVar_ = new RooNLLVar("nllVar", "", model_, *exptData_, extended_);
325 }
326 
327 void LauRooFitSlave::finaliseExperiment( const LauAbsFitter::FitStatus& fitStat, const TObjArray* parsFromMaster, const TMatrixD* covMat, TObjArray& parsToMaster )
328 {
329  // Copy the fit status information
330  this->storeFitStatus( fitStat, *covMat );
331 
332  // Now process the parameters
333  const UInt_t nFreePars = this->nFreeParams();
334  UInt_t nPars = parsFromMaster->GetEntries();
335  if ( nPars != nFreePars ) {
336  std::cerr << "ERROR in LauRooFitSlave::finaliseExperiment : Unexpected number of parameters received from master" << std::endl;
337  std::cerr << " : Received " << nPars << " when expecting " << nFreePars << std::endl;
338  gSystem->Exit( EXIT_FAILURE );
339  }
340 
341  for ( UInt_t iPar(0); iPar < nPars; ++iPar ) {
342  LauParameter* parameter = dynamic_cast<LauParameter*>( (*parsFromMaster)[iPar] );
343  if ( ! parameter ) {
344  std::cerr << "ERROR in LauRooFitSlave::finaliseExperiment : Error reading parameter from master" << std::endl;
345  gSystem->Exit( EXIT_FAILURE );
346  }
347 
348  if ( parameter->name() != fitPars_[iPar]->name() ) {
349  std::cerr << "ERROR in LauRooFitSlave::finaliseExperiment : Error reading parameter from master" << std::endl;
350  gSystem->Exit( EXIT_FAILURE );
351  }
352 
353  *(fitPars_[iPar]) = *parameter;
354 
355  RooRealVar* rrv = fitVars_[iPar];
356  rrv->setVal( parameter->value() );
357  rrv->setError( parameter->error() );
358  rrv->setAsymError( parameter->negError(), parameter->posError() );
359  }
360 
361  // Update the pulls and add each finalised fit parameter to the list to
362  // send back to the master
363  for ( std::vector<LauParameter*>::iterator iter = fitPars_.begin(); iter != fitPars_.end(); ++iter ) {
364  (*iter)->updatePull();
365  parsToMaster.Add( *iter );
366  }
367 
368  // Write the results into the ntuple
369  std::vector<LauParameter> extraVars;
370  LauFitNtuple* ntuple = this->fitNtuple();
371  ntuple->storeParsAndErrors(fitPars_, extraVars);
372 
373  // find out the correlation matrix for the parameters
374  ntuple->storeCorrMatrix(this->iExpt(), this->fitStatus(), this->covarianceMatrix());
375 
376  // Fill the data into ntuple
377  ntuple->updateFitNtuple();
378 }
379 
virtual void finaliseExperiment(const LauAbsFitter::FitStatus &fitStat, const TObjArray *parsFromMaster, const TMatrixD *covMat, TObjArray &parsToMaster)
Perform all finalisation actions.
Bool_t fixed() const
Check whether the parameter is fixed or floated.
TFile * dataFile_
The data file.
RooNLLVar * nllVar_
The NLL variable.
Bool_t withinAsymErrorCalc() const
Query whether the fit is calculating the asymmetric errors.
Definition: LauFitObject.hh:74
virtual Double_t getTotNegLogLikelihood()
Calculates the total negative log-likelihood.
ClassImp(LauAbsCoeffSet)
virtual void prepareInitialParArray(TObjArray &array)
Package the initial fit parameters for transmission to the master.
File containing declaration of LauRooFitSlave class.
LauParameter()
Default constructor.
Definition: LauParameter.cc:30
RooAbsPdf & model_
The model.
const TString & name() const
The parameter name.
void cleanData()
Cleanup the data.
LauParameter * convertToLauParameter(const RooRealVar *rooParameter) const
Convert a RooRealVar into a LauParameter.
const LauFitNtuple * fitNtuple() const
Const access to the fit ntuple.
Double_t negError() const
The lower error on the parameter.
void storeFitStatus(const LauAbsFitter::FitStatus &status, const TMatrixD &covMatrix)
Store fit status information.
Definition: LauFitObject.cc:56
RooArgSet dataVars_
The dataset variables.
std::vector< LauParameter * > fitPars_
The fit parameters (as LauParameter&#39;s)
void updateFitNtuple()
Update the fit ntuple.
UInt_t nFreeParams() const
Access the total number of fit parameters.
Double_t posError() const
The upper error on the parameter.
A class for creating a RooFit-based slave process for simultaneous/combined fits. ...
std::vector< std::pair< RooRealVar *, LauParameter * > > convertToLauParameters(const RooFormulaVar *rooFormula) const
Convert a RooFormulaVar into LauParameters.
void storeCorrMatrix(const UInt_t iExpt, const LauAbsFitter::FitStatus &fitStatus, const TMatrixD &covMatrix)
Store the correlation matrix and other fit information.
Definition: LauFitNtuple.cc:60
virtual void cacheInputFitVars()
Cache the input data values to calculate the likelihood during the fit.
UInt_t eventsPerExpt() const
Obtain the total number of events in the current experiment.
Definition: LauFitObject.hh:87
virtual ~LauRooFitSlave()
Destructor.
File containing declaration of LauParameter class.
Struct to store fit status information.
Definition: LauAbsFitter.hh:41
TTree * dataTree_
The data tree.
Double_t error() const
The error on the parameter.
virtual UInt_t readExperimentData()
Read in the data for the current experiment.
const TMatrixD & covarianceMatrix() const
Access the fit covariance matrix.
Class for defining the fit parameter objects.
Definition: LauParameter.hh:35
std::vector< RooRealVar * > fitVars_
The fit parameters (as RooRealVar&#39;s)
virtual void setParsFromMinuit(Double_t *par, Int_t npar)
This function sets the parameter values from Minuit.
File containing declaration of LauSimFitSlave class.
void storeParsAndErrors(const std::vector< LauParameter * > &fitVars, const std::vector< LauParameter > &extraVars)
Store parameters and their errors.
virtual Bool_t verifyFitData(const TString &dataFileName, const TString &dataTreeName)
Open the input file and verify that all required variables are present.
RooCategory iExptCat_
The experiment category variable.
Class to store the results from the fit into an ntuple.
Definition: LauFitNtuple.hh:44
The base class for any slave process for simultaneous/combined fits.
void startNewFit(const UInt_t nPars, const UInt_t nFreePars)
Indicate the start of a new fit.
Definition: LauFitObject.cc:46
const LauAbsFitter::FitStatus & fitStatus() const
Access the fit status information.
const Bool_t extended_
Is the PDF extended?
Double_t value() const
The value of the parameter.
virtual void initialise()
Initialise the fit model.
UInt_t iExpt() const
Obtain the number of the current experiment.
Definition: LauFitObject.hh:96
RooAbsData * exptData_
The data for the current experiment.
TString weightVarName_
The name of the (optional) weight variable in the dataset.
File containing declaration of LauFitNtuple class.