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