Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooMCStudy.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooFitCore *
4 * @(#)root/roofitcore:$Id$
5 * Authors: *
6 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7 * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8 * *
9 * Copyright (c) 2000-2005, Regents of the University of California *
10 * and Stanford University. All rights reserved. *
11 * *
12 * Redistribution and use in source and binary forms, *
13 * with or without modification, are permitted according to the terms *
14 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15 *****************************************************************************/
16
17/**
18\file RooMCStudy.cxx
19\class RooMCStudy
20\ingroup Roofitcore
21
22Helper class to facilitate Monte Carlo studies
23such as 'goodness-of-fit' studies, that involve fitting a PDF
24to multiple toy Monte Carlo sets. These may be generated from either same PDF
25or from a different PDF with similar parameters.
26
27Given a fit and a generator PDF (they might be identical), RooMCStudy can produce
28toyMC samples and/or fit these.
29It accumulates the post-fit parameters of each iteration in a dataset. These can be
30retrieved using fitParams() or fitParDataSet(). This dataset additionally contains the
31variables
32- NLL: The value of the negative log-likelihood for each run.
33- ngen: The number of events generated for each run.
34
35Additional plotting routines simplify the task of plotting
36the distribution of the minimized likelihood, the fitted parameter values,
37fitted error and pull distribution.
38
39RooMCStudy provides the option to insert add-in modules
40that modify the generate-and-fit cycle and allow to perform
41extra steps in the cycle. Output of these modules can be stored
42alongside the fit results in the aggregate results dataset.
43These study modules should derive from the class RooAbsMCStudyModule.
44
45Check the RooFit tutorials
46- rf801_mcstudy.C
47- rf802_mcstudy_addons.C
48- rf803_mcstudy_addons2.C
49- rf804_mcstudy_constr.C
50for usage examples.
51**/
52
53
54#include <RooMCStudy.h>
55
56#include <RooAbsMCStudyModule.h>
57#include <RooAbsPdf.h>
58#include <RooArgList.h>
59#include <RooCmdConfig.h>
60#include <RooDataHist.h>
61#include <RooDataSet.h>
62#include <RooErrorVar.h>
63#include <RooFitResult.h>
64#include <RooFormulaVar.h>
65#include <RooGenContext.h>
66#include <RooGlobalFunc.h>
67#include <RooMsgService.h>
68#include <RooPlot.h>
69#include <RooProdPdf.h>
70#include <RooPullVar.h>
71#include <RooRandom.h>
72#include <RooRealVar.h>
73#include <RooWorkspace.h>
74
75#include <snprintf.h>
76#include <iostream>
77
78
79/**
80Construct Monte Carlo Study Manager. This class automates generating data from a given PDF,
81fitting the PDF to data and accumulating the fit statistics.
82
83\param[in] model The PDF to be studied
84\param[in] observables The variables of the PDF to be considered observables
85\param[in] arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 Optional arguments according to table below.
86
87<table>
88<tr><th> Optional arguments <th>
89<tr><td> Silence() <td> Suppress all RooFit messages during running below PROGRESS level
90<tr><td> FitModel(const RooAbsPdf&) <td> The PDF for fitting if it is different from the PDF for generating.
91<tr><td> ConditionalObservables(const RooArgSet& set) <td> The set of observables that the PDF should _not_ be normalized over
92<tr><td> Binned(bool flag) <td> Bin the dataset before fitting it. Speeds up fitting of large data samples
93<tr><td> FitOptions(....) <td> Options to be used for fitting. All named arguments inside FitOptions() are passed to RooAbsPdf::fitTo().
94 `Save()` is especially interesting to be able to retrieve fit results of each run using fitResult().
95<tr><td> Verbose(bool flag) <td> Activate informational messages in event generation phase
96<tr><td> Extended(bool flag) <td> Determine number of events for each sample anew from a Poisson distribution
97<tr><td> Constrain(const RooArgSet& pars) <td> Apply internal constraints on given parameters in fit and sample constrained parameter values from constraint p.d.f for each toy.
98<tr><td> ExternalConstraints(const RooArgSet& cpdfs) <td> Apply given external constraint p.d.f.s in fit and sample values of the parameters they constrain from them for each toy.
99 To apply the constraints in the fit only, without the per-toy sampling, pass them inside FitOptions() instead.
100<tr><td> ProtoData(const RooDataSet&, bool randOrder)
101 <td> Prototype data for the event generation. If the randOrder flag is set, the order of the dataset will be re-randomized for each generation
102 cycle to protect against systematic biases if the number of generated events does not exactly match the number of events in the prototype dataset
103 at the cost of reduced precision with mu equal to the specified number of events
104</table>
105*/
106RooMCStudy::RooMCStudy(const RooAbsPdf& model, const RooArgSet& observables,
107 const RooCmdArg& arg1, const RooCmdArg& arg2,
108 const RooCmdArg& arg3,const RooCmdArg& arg4,const RooCmdArg& arg5,
109 const RooCmdArg& arg6,const RooCmdArg& arg7,const RooCmdArg& arg8) : TNamed("mcstudy","mcstudy")
110
111{
112 // Stuff all arguments in a list
114 cmdList.Add(const_cast<RooCmdArg*>(&arg1)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg2)) ;
115 cmdList.Add(const_cast<RooCmdArg*>(&arg3)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg4)) ;
116 cmdList.Add(const_cast<RooCmdArg*>(&arg5)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg6)) ;
117 cmdList.Add(const_cast<RooCmdArg*>(&arg7)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg8)) ;
118
119 // Select the pdf-specific commands
120 RooCmdConfig pc("RooMCStudy::RooMCStudy(" + std::string(model.GetName()) + ")");
121
122 pc.defineObject("fitModel","FitModel",0,nullptr) ;
123 pc.defineSet("condObs","ProjectedObservables",0,nullptr) ;
124 pc.defineObject("protoData","PrototypeData",0,nullptr) ;
125 pc.defineSet("cPars","Constrain",0,nullptr) ;
126 pc.defineSet("extCons","ExternalConstraints",0,nullptr) ;
127 pc.defineInt("silence","Silence",0,0) ;
128 pc.defineInt("randProtoData","PrototypeData",0,0) ;
129 pc.defineInt("verboseGen","Verbose",0,0) ;
130 pc.defineInt("extendedGen","Extended",0,0) ;
131 pc.defineInt("binGenData","Binned",0,0) ;
132 pc.defineInt("dummy","FitOptArgs",0,0) ;
133
134 // Process and check varargs
135 pc.process(cmdList) ;
136 if (!pc.ok(true)) {
137 // WVE do something here
138 throw std::string("RooMCStudy::RooMCStudy() Error in parsing arguments passed to constructor") ;
139 return ;
140 }
141
142 // Save fit command options
143 if (pc.hasProcessed("FitOptArgs")) {
144 RooCmdArg* fitOptArg = static_cast<RooCmdArg*>(cmdList.FindObject("FitOptArgs")) ;
145 for (int i=0 ; i<fitOptArg->subArgs().GetSize() ;i++) {
146 _fitOptList.Add(new RooCmdArg(static_cast<RooCmdArg&>(*fitOptArg->subArgs().At(i)))) ;
147 }
148 }
149
150 // Decode command line arguments
151 _silence = pc.getInt("silence") ;
152 _verboseGen = pc.getInt("verboseGen") ;
153 _extendedGen = pc.getInt("extendedGen") ;
154 _binGenData = pc.getInt("binGenData") ;
155 _randProto = pc.getInt("randProtoData") ;
156
157 // Process constraints specifications
158 const RooArgSet* cParsTmp = pc.getSet("cPars") ;
159 const RooArgSet* extCons = pc.getSet("extCons") ;
160
161 auto cPars = std::make_unique<RooArgSet>();
162 if (cParsTmp) {
163 cPars->add(*cParsTmp) ;
164 }
165
166 // If constraints are specified, add to fit options
167 if (cPars) {
169 }
170 if (extCons) {
172 }
173
174 // Make list of all constraints and of the parameters they constrain
177 if (cPars) {
178 if (std::unique_ptr<RooArgSet> constraints{model.getAllConstraints(observables,*cPars,true)}) {
179 allConstraints.add(*constraints) ;
180 }
181 consPars.add(*cPars) ;
182 }
183 if (extCons) {
184 // External constraint p.d.f.s are not part of the model, so the parameters
185 // they constrain are found among their observables instead
186 allConstraints.add(*extCons) ;
187 RooArgSet params;
188 model.getParameters(&observables, params);
189 for (RooAbsArg const* con : *extCons) {
191 con->getObservables(&params, cparams);
192 consPars.add(cparams, /*silent=*/true) ;
193 }
194 }
195
196 // Construct constraint p.d.f
197 if (!allConstraints.empty()) {
198 _constrPdf = std::make_unique<RooProdPdf>("mcs_constr_prod","RooMCStudy constraints product",allConstraints);
199 _constrGenContext.reset(_constrPdf->genContext(consPars,nullptr,nullptr,_verboseGen));
200
202
203 coutI(Generation) << "RooMCStudy::RooMCStudy: INFO have pdf with constraints, will generate parameters from constraint pdf for each experiment" << std::endl ;
204 }
205
206
207 // Extract generator and fit models
208 _genModel = const_cast<RooAbsPdf*>(&model) ;
209 RooAbsPdf* fitModel = static_cast<RooAbsPdf*>(pc.getObject("fitModel",nullptr)) ;
210 _fitModel = fitModel ? fitModel : _genModel ;
211
212 // Extract conditional observables and prototype data
213 _genProtoData = static_cast<RooDataSet*>(pc.getObject("protoData",nullptr)) ;
214 if (auto condObs = pc.getSet("condObs",nullptr)) {
216 }
217
218 _dependents.add(observables) ;
219
222
224 oocoutW(_fitModel,Generation) << "RooMCStudy::RooMCStudy: WARNING Using generator option 'e' (Poisson distribution of #events) together " << std::endl
225 << " with a prototype dataset implies incomplete sampling or oversampling of proto data." << std::endl
226 << " Use option \"r\" to randomize prototype dataset order and thus to randomize" << std::endl
227 << " the set of over/undersampled prototype events for each generation cycle." << std::endl ;
228 }
229
231 if (!_binGenData) {
233 _genContext->attach(_genParams) ;
234 }
235
237
238 // Store list of parameters and save initial values separately
241
243
244 // Place holder for NLL
245 _nllVar = std::make_unique<RooRealVar>("NLL","-log(Likelihood)",0);
246
247 // Place holder for number of generated events
248 _ngenVar = std::make_unique<RooRealVar>("ngen","number of generated events",0);
249
250 // Create data set containing parameter values, errors and pulls
252 tmp2.add(*_nllVar) ;
253 tmp2.add(*_ngenVar) ;
254
255 // Mark all variable to store their errors in the dataset
256 tmp2.setAttribAll("StoreError",true) ;
257 tmp2.setAttribAll("StoreAsymError",true) ;
258 std::string fpdName;
259 if (_fitModel==_genModel) {
260 fpdName = "fitParData_" + std::string(_fitModel->GetName());
261 } else {
262 fpdName= "fitParData_" + std::string(_fitModel->GetName()) + "_" + std::string(_genModel->GetName());
263 }
264
265 _fitParData = std::make_unique<RooDataSet>(fpdName,"Fit Parameters DataSet",tmp2);
266 tmp2.setAttribAll("StoreError",false) ;
267 tmp2.setAttribAll("StoreAsymError",false) ;
268
269 _genParData = std::make_unique<RooDataSet>("genParData","Generated Parameters dataset",_genParams);
270
271 // Append proto variables to allDependents
272 if (_genProtoData) {
273 _allDependents.add(*_genProtoData->get(),true) ;
274 }
275
276 // Call module initializers
277 for (auto iter=_modList.begin() ; iter!= _modList.end() ; ++iter) {
278 bool ok = (*iter)->doInitializeInstance(*this) ;
279 if (!ok) {
280 oocoutE(_fitModel,Generation) << "RooMCStudy::ctor: removing study module " << (*iter)->GetName() << " from analysis chain because initialization failed" << std::endl ;
281 iter = _modList.erase(iter) ;
282 }
283 }
284
285}
286
287
288////////////////////////////////////////////////////////////////////////////////
289
295
296
297
298////////////////////////////////////////////////////////////////////////////////
299/// Insert given RooMCStudy add-on module to the processing chain
300/// of this MCStudy object
301
303{
304 module.doInitializeInstance(*this) ;
305 _modList.push_back(&module) ;
306}
307
308
309
310////////////////////////////////////////////////////////////////////////////////
311/// Run engine method. Generate and/or fit, according to flags, 'nSamples' samples of 'nEvtPerSample' events.
312/// If keepGenData is set, all generated data sets will be kept in memory and can be accessed
313/// later via genData().
314///
315/// When generating, the generator parameter values used for each sample are recorded in the
316/// dataset returned by genParDataSet(). When constraints are used and the run both generates
317/// and fits, the sampled parameter values are in addition merged into the fit parameter
318/// dataset as `<name>_gen` columns for each toy whose fit converged.
319///
320/// When generating, data sets will be written out in ascii form if the pattern string is supplied
321/// The pattern, which is a template for snprintf, should look something like "data/toymc_%04d.dat"
322/// and should contain one integer field that encodes the sample serial number.
323///
324/// When fitting only, data sets may optionally be read from ascii files, using the same file
325/// pattern.
326///
327
328bool RooMCStudy::run(bool doGenerate, bool DoFit, Int_t nSamples, Int_t nEvtPerSample, bool keepGenData, const char* asciiFilePat)
329{
331 if (_silence) {
332 oldLevel = RooMsgService::instance().globalKillBelow() ;
333 RooMsgService::instance().setGlobalKillBelow(RooFit::PROGRESS) ;
334 }
335
337 mod->initializeRun(nSamples) ;
338 }
339
340 if (DoFit && !doGenerate && _perExptGenParams) {
341 coutW(Generation) << "RooMCStudy::run: WARNING fitting previously generated samples in a separate run:"
342 " the per-toy sampled generator parameters are not merged into the fit parameter dataset,"
343 " so pulls are computed with respect to the initial parameter values instead of the sampled ones" << std::endl ;
344 }
345
346 int prescale = nSamples>100 ? int(nSamples/100) : 1 ;
347
348 // Generator parameter values of the toys whose fit converged, filled in the
349 // same order as _fitParData so that the two datasets can be merged after the
350 // loop. Only done when the parameters are sampled from constraint p.d.f.s:
351 // otherwise the values are the constant initial ones, and study modules like
352 // RooRandomizeParamMCSModule publish their own "<name>_gen" columns that
353 // must not be overwritten by the merge.
354 std::unique_ptr<RooDataSet> genParDataForMerge;
355 if (doGenerate && DoFit && _perExptGenParams && _genParData) {
356 genParDataForMerge = std::make_unique<RooDataSet>("genParDataForMerge","Generated Parameters dataset",*_genParData->get());
357 }
358
359 while(nSamples--) {
360
361 if (nSamples%prescale==0) {
362 oocoutP(_fitModel,Generation) << "RooMCStudy::run: " ;
363 if (doGenerate) ooccoutI(_fitModel,Generation) << "Generating " ;
364 if (doGenerate && DoFit) ooccoutI(_fitModel,Generation) << "and " ;
365 if (DoFit) ooccoutI(_fitModel,Generation) << "fitting " ;
366 ooccoutP(_fitModel,Generation) << "sample " << nSamples << std::endl ;
367 }
368
369 std::unique_ptr<RooAbsData> ownedGenSample;
370 _genSample = nullptr;
371 bool existingData = false ;
372 if (doGenerate) {
373 // Generate sample
374 int nEvt(nEvtPerSample) ;
375
376 // Reset generator parameters to initial values
378
379 // If constraints are present, sample generator values from constraints
380 if (_constrPdf) {
381 _genParams.assign(*std::unique_ptr<RooDataSet>{_constrGenContext->generate(1)}->get());
382 }
383
384 // Call module before-generation hook
386 mod->processBeforeGen(nSamples) ;
387 }
388
389 // Save the generator parameters used for this toy, including any
390 // modification applied by the study modules above
391 if (_genParData) {
392 _genParData->add(_genParams) ;
393 }
394
395 if (_binGenData) {
396
397 // Calculate the number of (extended) events for this run
398 if (_extendedGen) {
401 }
402
403 // Binned generation
404 ownedGenSample = std::unique_ptr<RooDataHist>{_genModel->generateBinned(_dependents,nEvt)};
405
406 } else {
407
408 // Calculate the number of (extended) events for this run
409 if (_extendedGen) {
412 }
413
414 // Optional randomization of protodata for this run
415 if (_randProto && _genProtoData && _genProtoData->numEntries()!=nEvt) {
416 oocoutI(_fitModel,Generation) << "RooMCStudy: (Re)randomizing event order in prototype dataset (Nevt=" << nEvt << ")" << std::endl ;
418 _genContext->setProtoDataOrder(newOrder) ;
419 delete[] newOrder ;
420 }
421
422 // Actual generation of events
423 if (nEvt>0) {
424 ownedGenSample = std::unique_ptr<RooAbsData>{_genContext->generate(nEvt)};
425 } else {
426 // Make empty dataset
427 ownedGenSample = std::make_unique<RooDataSet>("emptySample","emptySample",_dependents);
428 }
429 }
430
432
433 //} else if (asciiFilePat && &asciiFilePat) { //warning: the address of 'asciiFilePat' will always evaluate as 'true'
434 } else if (asciiFilePat) {
435
436 // Load sample from ASCII file
437 char asciiFile[1024] ;
438 snprintf(asciiFile,1024,asciiFilePat,nSamples) ;
440 ownedGenSample = std::unique_ptr<RooDataSet>{RooDataSet::read(asciiFile,depList,"q")};
442
443 } else {
444
445 // Load sample from internal list
446 _genSample = static_cast<RooDataSet*>(_genDataList.At(nSamples)) ;
448 if (!_genSample) {
449 oocoutW(_fitModel,Generation) << "RooMCStudy::run: WARNING: Sample #" << nSamples << " not loaded, skipping" << std::endl ;
450 continue ;
451 }
452 }
453
454 // Save number of generated events
455 _ngenVar->setVal(_genSample->sumEntries()) ;
456
457 // Call module between generation and fitting hook
459 mod->processBetweenGenAndFit(nSamples) ;
460 }
461
462 bool fitOk = true;
463 if (DoFit) fitOk = !fitSample(_genSample) ;
464
465 // Keep the generator parameters of this toy for merging into the fit
466 // parameter dataset. Only converged fits get an entry in _fitParData, so
467 // the toys with failed fits have to be skipped here as well. The values
468 // are taken from _genParData because the fit changes the parameters.
470 genParDataForMerge->add(*_genParData->get(_genParData->numEntries()-1)) ;
471 }
472
473 // Call module between generation and fitting hook
475 mod->processAfterFit(fitOk) ;
476 }
477
478 // Optionally write to ascii file
480 char asciiFile[1024] ;
481 snprintf(asciiFile,1024,asciiFilePat,nSamples) ;
482 if (RooDataSet* unbinnedData = dynamic_cast<RooDataSet*>(_genSample)) {
483 unbinnedData->write(asciiFile) ;
484 } else {
485 coutE(InputArguments) << "RooMCStudy::run(" << GetName() << ") ERROR: ASCII writing of binned datasets is not supported" << std::endl ;
486 }
487 }
488
489 // Add to list or delete
490 if (!existingData) {
491 if (keepGenData) {
492 _genDataList.Add(ownedGenSample.release()) ;
493 }
494 }
495 }
496
498 if (RooDataSet* auxData = mod->finalizeRun()) {
499 _fitParData->merge(auxData) ;
500 }
501 }
502
504
505 if (genParDataForMerge) {
506 // Append the generator parameter values as additional "<name>_gen"
507 // columns to the fit parameter dataset
508 for(RooAbsArg * arg : *genParDataForMerge->get()) {
509 genParDataForMerge->changeObservableName(arg->GetName(),(std::string(arg->GetName()) + "_gen").c_str());
510 }
511
512 _fitParData->merge(genParDataForMerge.get());
513 }
514
515 if (DoFit) calcPulls() ;
516
517 if (_silence) {
518 RooMsgService::instance().setGlobalKillBelow(oldLevel) ;
519 }
520
521 return false ;
522}
523
524
525
526
527
528
529////////////////////////////////////////////////////////////////////////////////
530/// Generate and fit 'nSamples' samples of 'nEvtPerSample' events.
531/// If keepGenData is set, all generated data sets will be kept in memory and can be accessed
532/// later via genData().
533///
534/// Data sets will be written out in ascii form if the pattern string is supplied.
535/// The pattern, which is a template for snprintf, should look something like "data/toymc_%04d.dat"
536/// and should contain one integer field that encodes the sample serial number.
537///
538
540{
541 // Clear any previous data in memory
542 _fitResList.Delete() ; // even though the fit results are owned by gROOT, we still want to scratch them here.
544 _fitParData->reset() ;
545 if (_genParData) _genParData->reset() ;
546
547 return run(true,true,nSamples,nEvtPerSample,keepGenData,asciiFilePat) ;
548}
549
550
551
552////////////////////////////////////////////////////////////////////////////////
553/// Generate 'nSamples' samples of 'nEvtPerSample' events.
554/// If keepGenData is set, all generated data sets will be kept in memory
555/// and can be accessed later via genData().
556///
557/// Data sets will be written out in ascii form if the pattern string is supplied.
558/// The pattern, which is a template for snprintf, should look something like "data/toymc_%04d.dat"
559/// and should contain one integer field that encodes the sample serial number.
560///
561
563{
564 // Clear any previous data in memory
566 if (_genParData) _genParData->reset() ;
567
568 return run(true,false,nSamples,nEvtPerSample,keepGenData,asciiFilePat) ;
569}
570
571
572
573////////////////////////////////////////////////////////////////////////////////
574/// Fit 'nSamples' datasets, which are read from ASCII files.
575///
576/// The ascii file pattern, which is a template for snprintf, should look something like "data/toymc_%04d.dat"
577/// and should contain one integer field that encodes the sample serial number.
578///
579
580bool RooMCStudy::fit(Int_t nSamples, const char* asciiFilePat)
581{
582 // Clear any previous data in memory
583 _fitResList.Delete() ; // even though the fit results are owned by gROOT, we still want to scratch them here.
584 _fitParData->reset() ;
585
586 return run(false,true,nSamples,0,false,asciiFilePat) ;
587}
588
589
590
591////////////////////////////////////////////////////////////////////////////////
592/// Fit 'nSamples' datasets, as supplied in 'dataSetList'
593///
594
596{
597 // Clear any previous data in memory
598 _fitResList.Delete() ; // even though the fit results are owned by gROOT, we still want to scratch them here.
600 _fitParData->reset() ;
601
602 // Load list of data sets
605 }
606
607 return run(false,true,nSamples,0,true,nullptr) ;
608}
609
610
611
612////////////////////////////////////////////////////////////////////////////////
613/// Reset all fit parameters to the initial model
614/// parameters at the time of the RooMCStudy constructor
615
620
621
622
623////////////////////////////////////////////////////////////////////////////////
624/// Internal function. Performs actual fit according to specifications
625
627{
628 // Optionally bin dataset before fitting
629 std::unique_ptr<RooDataHist> ownedDataHist;
631 if (_binGenData) {
633 _fitModel->getObservables(genSample->get(), depList);
634 ownedDataHist = std::make_unique<RooDataHist>(genSample->GetName(),genSample->GetTitle(),depList,*genSample) ;
635 data = ownedDataHist.get();
636 } else {
637 data = genSample ;
638 }
639
640 RooCmdArg save = RooFit::Save() ;
643
644 RooLinkedList fitOptList(_fitOptList) ;
645 fitOptList.Add(&save) ;
646 if (!_projDeps.empty()) {
647 fitOptList.Add(&condo) ;
648 }
649 fitOptList.Add(&plevel) ;
650 return _fitModel->fitTo(*data,fitOptList);
651}
652
653
654
655////////////////////////////////////////////////////////////////////////////////
656/// Redo fit on 'current' toy sample, or if genSample is not nullptr
657/// do fit on given sample instead
658
660{
661 if (!genSample) {
662 genSample = _genSample ;
663 }
664
665 std::unique_ptr<RooFitResult> fr;
666 if (genSample->sumEntries()>0) {
667 fr = std::unique_ptr<RooFitResult>{doFit(genSample)};
668 }
669
670 return RooFit::makeOwningPtr(std::move(fr));
671}
672
673
674
675////////////////////////////////////////////////////////////////////////////////
676/// Internal method. Fit given dataset with fit model. If fit
677/// converges (TMinuit status code zero) The fit results are appended
678/// to the fit results dataset
679///
680/// If the fit option "r" is supplied, the RooFitResult
681/// objects will always be saved, regardless of the
682/// fit status. RooFitResults objects can be retrieved
683/// later via fitResult().
684///
685
687{
688 // Reset all fit parameters to their initial values
690
691 // Perform actual fit
692 bool ok ;
693 std::unique_ptr<RooFitResult> fr;
694 if (genSample->sumEntries()>0) {
695 fr = std::unique_ptr<RooFitResult>{doFit(genSample)};
696 ok = (fr->status()==0) ;
697 } else {
698 ok = false ;
699 }
700
701 // If fit converged, store parameters and NLL
702 if (ok) {
703 _nllVar->setVal(fr->minNll()) ;
705 tmp.add(*_nllVar) ;
706 tmp.add(*_ngenVar) ;
707
708 _fitParData->add(tmp) ;
709 }
710
711 // Store fit result if requested by user
712 if (_fitOptList.FindObject("Save")) {
713 _fitResList.Add(fr.release()) ;
714 }
715
716 return !ok ;
717}
718
719
720
721////////////////////////////////////////////////////////////////////////////////
722/// Utility function to add fit result from external fit to this RooMCStudy
723/// and process its results through the standard RooMCStudy statistics gathering tools.
724/// This function allows users to run the toy MC generation and/or fitting
725/// in a distributed way and to collect and analyze the results in a RooMCStudy
726/// as if they were run locally.
727///
728/// This method is only functional if this RooMCStudy object is cleanm, i.e. it was not used
729/// to generate and/or fit any samples.
730
732{
733 if (!_canAddFitResults) {
734 oocoutE(_fitModel,InputArguments) << "RooMCStudy::addFitResult: ERROR cannot add fit results in current state" << std::endl ;
735 return true ;
736 }
737
738 // Transfer contents of fit result to fitParams ;
740
741 // If fit converged, store parameters and NLL
742 bool ok = (fr.status()==0) ;
743 if (ok) {
744 _nllVar->setVal(fr.minNll()) ;
746 tmp.add(*_nllVar) ;
747 tmp.add(*_ngenVar) ;
748 _fitParData->add(tmp) ;
749 }
750
751 // Store fit result if requested by user
752 if (_fitOptList.FindObject("Save")) {
753 _fitResList.Add((TObject*)&fr) ;
754 }
755
756 return false ;
757}
758
759
760
761////////////////////////////////////////////////////////////////////////////////
762/// Calculate the pulls for all fit parameters in
763/// the fit results data set, and add them to that dataset.
764
766{
767 for (auto it = _fitParams.begin(); it != _fitParams.end(); ++it) {
768 const auto par = static_cast<RooRealVar*>(*it);
769 _fitParData->addColumn(*std::unique_ptr<RooErrorVar>{par->errorVar()});
770
771 TString name(par->GetName());
772 TString title(par->GetTitle());
773 name.Append("pull") ;
774 title.Append(" Pull") ;
775
776 if (!par->hasError(false)) {
777 coutW(Generation) << "Fit parameter '" << par->GetName() << "' does not have an error."
778 " A pull distribution cannot be generated. This might be caused by the parameter being constant or"
779 " because the fits were not run." << std::endl;
780 continue;
781 }
782
783 // First look in fitParDataset to see if per-experiment generated value has been stored
784 auto genParOrig = static_cast<RooAbsReal*>(_fitParData->get()->find(Form("%s_gen",par->GetName())));
786
787 RooPullVar pull(name,title,*par,*genParOrig) ;
788 _fitParData->addColumn(pull,false) ;
789
790 } else {
791 // If not use fixed generator value
792 genParOrig = static_cast<RooAbsReal*>(_genInitParams.find(par->GetName()));
793
794 if (!genParOrig) {
795 std::size_t index = it - _fitParams.begin();
797 static_cast<RooAbsReal*>(_genInitParams[index]) :
798 nullptr;
799
800 if (genParOrig) {
801 coutW(Generation) << "The fit parameter '" << par->GetName() << "' is not in the model that was used to generate toy data. "
802 "The parameter '" << genParOrig->GetName() << "'=" << genParOrig->getVal() << " was found at the same position in the generator model."
803 " It will be used to compute pulls."
804 "\nIf this is not desired, the parameters of the generator model need to be renamed or reordered." << std::endl;
805 }
806 }
807
808 if (genParOrig) {
809 std::unique_ptr<RooAbsReal> genPar(static_cast<RooAbsReal*>(genParOrig->Clone("truth")));
810 RooPullVar pull(name,title,*par,*genPar);
811
812 _fitParData->addColumn(pull,false) ;
813 } else {
814 coutE(Generation) << "Cannot generate pull distribution for the fit parameter '" << par->GetName() << "'."
815 "\nNo similar parameter was found in the set of parameters that were used to generate toy data." << std::endl;
816 }
817 }
818 }
819}
820
821
822
823
824////////////////////////////////////////////////////////////////////////////////
825/// Return a RooDataSet containing the post-fit parameters of each toy cycle.
826/// This dataset also contains any additional output that was generated
827/// by study modules that were added to this RooMCStudy.
828/// By default, the two following variables are added (apart from fit parameters):
829/// - NLL: The value of the negative log-likelihood for each run.
830/// - ngen: Number of events generated for each run.
832{
833 if (_canAddFitResults) {
834 calcPulls() ;
836 }
837
838 return *_fitParData ;
839}
840
841
842
843////////////////////////////////////////////////////////////////////////////////
844/// Return an argset with the fit parameters for the given sample number
845///
846/// NB: The fit parameters are only stored for successful fits,
847/// thus the maximum sampleNum can be less that the number
848/// of generated samples and if so, the indices will
849/// be out of synch with genData() and fitResult()
850
852{
853 // Check if sampleNum is in range
854 if (sampleNum<0 || sampleNum>=_fitParData->numEntries()) {
855 oocoutE(_fitModel,InputArguments) << "RooMCStudy::fitParams: ERROR, invalid sample number: " << sampleNum << std::endl ;
856 return nullptr ;
857 }
858
859 return _fitParData->get(sampleNum) ;
860}
861
862
863
864////////////////////////////////////////////////////////////////////////////////
865/// Return the RooFitResult of the fit with the given run number.
866///
867/// \note Fit results are not saved by default. This requires passing `FitOptions(Save(), ...)`
868/// to the constructor.
870{
871 // Check if sampleNum is in range
873 oocoutE(_fitModel,InputArguments) << "RooMCStudy::fitResult: ERROR, invalid sample number: " << sampleNum << std::endl ;
874 return nullptr ;
875 }
876
877 // Retrieve fit result object
878 const RooFitResult* fr = static_cast<RooFitResult*>(_fitResList.At(sampleNum)) ;
879 if (fr) {
880 return fr ;
881 } else {
882 oocoutE(_fitModel,InputArguments) << "RooMCStudy::fitResult: ERROR, no fit result saved for sample "
883 << sampleNum << ", did you use the 'r; fit option?" << std::endl ;
884 }
885 return nullptr ;
886}
887
888
889
890////////////////////////////////////////////////////////////////////////////////
891/// Return the given generated dataset. This method will only return datasets
892/// if during the run cycle it was indicated that generator data should be saved.
893
895{
896 // Check that generated data was saved
897 if (_genDataList.GetSize()==0) {
898 oocoutE(_fitModel,InputArguments) << "RooMCStudy::genData() ERROR, generated data was not saved" << std::endl ;
899 return nullptr ;
900 }
901
902 // Check if sampleNum is in range
904 oocoutE(_fitModel,InputArguments) << "RooMCStudy::genData() ERROR, invalid sample number: " << sampleNum << std::endl ;
905 return nullptr ;
906 }
907
908 return static_cast<RooAbsData*>(_genDataList.At(sampleNum)) ;
909}
910
911
912
913////////////////////////////////////////////////////////////////////////////////
914/// Plot the distribution of fitted values of a parameter. The parameter shown is the one from which the RooPlot
915/// was created, e.g.
916///
917/// RooPlot* frame = param.frame(100,-10,10) ;
918/// mcstudy.paramOn(frame,LineStyle(kDashed)) ;
919///
920/// Any named arguments passed to plotParamOn() are forwarded to the underlying plotOn() call
921
923 const RooCmdArg& arg5, const RooCmdArg& arg6, const RooCmdArg& arg7, const RooCmdArg& arg8)
924{
925 _fitParData->plotOn(frame,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ;
926 return frame ;
927}
928
929
930
931////////////////////////////////////////////////////////////////////////////////
932/// Plot the distribution of the fitted value of the given parameter on a newly created frame.
933///
934/// <table>
935/// <tr><th> Optional arguments <th>
936/// <tr><td> FrameRange(double lo, double hi) <td> Set range of frame to given specification
937/// <tr><td> FrameBins(int bins) <td> Set default number of bins of frame to given number
938/// <tr><td> Frame() <td> Pass supplied named arguments to RooAbsRealLValue::frame() function. See there
939/// for list of allowed arguments
940/// </table>
941/// If no frame specifications are given, the AutoRange() feature will be used to set the range
942/// Any other named argument is passed to the RooAbsData::plotOn() call. See that function for allowed options
943
945 const RooCmdArg& arg5, const RooCmdArg& arg6, const RooCmdArg& arg7, const RooCmdArg& arg8)
946{
947
948 // Find parameter in fitParDataSet
949 RooRealVar* param = static_cast<RooRealVar*>(_fitParData->get()->find(paramName)) ;
950 if (!param) {
951 oocoutE(_fitModel,InputArguments) << "RooMCStudy::plotParam: ERROR: no parameter defined with name " << paramName << std::endl ;
952 return nullptr ;
953 }
954
955 // Forward to implementation below
956 return plotParam(*param,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ;
957}
958
959
960
961////////////////////////////////////////////////////////////////////////////////
962/// Plot the distribution of the fitted value of the given parameter on a newly created frame.
963/// \copydetails RooMCStudy::plotParam(const char* paramName, const RooCmdArg& arg1, const RooCmdArg& arg2, const RooCmdArg& arg3, const RooCmdArg& arg4,
964/// const RooCmdArg& arg5, const RooCmdArg& arg6, const RooCmdArg& arg7, const RooCmdArg& arg8)
965
967 const RooCmdArg& arg5, const RooCmdArg& arg6, const RooCmdArg& arg7, const RooCmdArg& arg8)
968{
969 // Stuff all arguments in a list
971 cmdList.Add(const_cast<RooCmdArg*>(&arg1)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg2)) ;
972 cmdList.Add(const_cast<RooCmdArg*>(&arg3)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg4)) ;
973 cmdList.Add(const_cast<RooCmdArg*>(&arg5)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg6)) ;
974 cmdList.Add(const_cast<RooCmdArg*>(&arg7)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg8)) ;
975
976 RooPlot* frame = makeFrameAndPlotCmd(param, cmdList) ;
977 if (frame) {
978 _fitParData->plotOn(frame, cmdList) ;
979 }
980
981 return frame ;
982}
983
984
985
986////////////////////////////////////////////////////////////////////////////////
987/// Plot the distribution of the -log(L) values on a newly created frame.
988///
989/// <table>
990/// <tr><th> Optional arguments <th>
991/// <tr><td> FrameRange(double lo, double hi) <td> Set range of frame to given specification
992/// <tr><td> FrameBins(int bins) <td> Set default number of bins of frame to given number
993/// <tr><td> Frame() <td> Pass supplied named arguments to RooAbsRealLValue::frame() function. See there
994/// for list of allowed arguments
995/// </table>
996///
997/// If no frame specifications are given, the AutoRange() feature will be used to set the range.
998/// Any other named argument is passed to the RooAbsData::plotOn() call. See that function for allowed options
999
1001 const RooCmdArg& arg3, const RooCmdArg& arg4,
1002 const RooCmdArg& arg5, const RooCmdArg& arg6,
1003 const RooCmdArg& arg7, const RooCmdArg& arg8)
1004{
1006}
1007
1008
1009
1010////////////////////////////////////////////////////////////////////////////////
1011/// Plot the distribution of the fit errors for the specified parameter on a newly created frame.
1012///
1013/// <table>
1014/// <tr><th> Optional arguments <th>
1015/// <tr><td> FrameRange(double lo, double hi) <td> Set range of frame to given specification
1016/// <tr><td> FrameBins(int bins) <td> Set default number of bins of frame to given number
1017/// <tr><td> Frame() <td> Pass supplied named arguments to RooAbsRealLValue::frame() function. See there
1018/// for list of allowed arguments
1019/// </table>
1020///
1021/// If no frame specifications are given, the AutoRange() feature will be used to set a default range.
1022/// Any other named argument is passed to the RooAbsData::plotOn() call. See that function for allowed options.
1023
1025 const RooCmdArg& arg3, const RooCmdArg& arg4,
1026 const RooCmdArg& arg5, const RooCmdArg& arg6,
1027 const RooCmdArg& arg7, const RooCmdArg& arg8)
1028{
1029 if (_canAddFitResults) {
1030 calcPulls() ;
1032 }
1033
1034 std::unique_ptr<RooErrorVar> evar{param.errorVar()};
1035 std::unique_ptr<RooAbsArg> evar_rrv{evar->createFundamental()};
1036 RooPlot* frame = plotParam(static_cast<RooRealVar&>(*evar_rrv),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ;
1037
1038 // To make sure the frame has no dangling pointer to evar_rrv.
1040
1041 return frame ;
1042}
1043
1044namespace {
1045
1046// Fits a Gaussian to the pull distribution, plots the fit and prints the fit
1047// parameters on the canvas. Implementation detail of RooMCStudy::plotPull().
1049{
1050 // Build the Gaussian fit mode for the pulls, then fit it and plot it. We
1051 // have to use the RooWorkspace factory here, because different from the
1052 // RooMCStudy class, the RooGaussian is not in RooFitCore.
1053 RooWorkspace ws;
1054 auto plotVar = frame.getPlotVar();
1055 const std::string plotVarName = plotVar->GetName();
1056 ws.import(*plotVar);
1057 ws.factory("Gaussian::pullGauss(" + plotVarName + ", pullMean[0.0, -10.0, 10.0], pullSigma[1.0, 0.1, 5.0])");
1058
1059 RooRealVar& pullMean = *ws.var("pullMean");
1060 RooRealVar& pullSigma = *ws.var("pullSigma");
1061 RooAbsPdf& pullGauss = *ws.pdf("pullGauss");
1062
1064 pullGauss.plotOn(&frame) ;
1065
1066 // Instead of using paramOn() without command arguments to plot the fit
1067 // parameters, we are building the parameter label ourselves for more
1068 // flexibility and pass this together with an appropriate layout
1069 // parametrization to paramOn().
1070 const int sigDigits = 2;
1071 const char * options = "ELU";
1072 std::stringstream ss;
1073 ss << "Fit parameters:\n"
1074 << "#mu: " << pullMean.format(sigDigits, options)
1075 << "\n#sigma: " << pullSigma.format(sigDigits, options);
1076 // We set the parameters constant to disable the default label. Still, we
1077 // use param() on as a wrapper for the text box generation.
1078 pullMean.setConstant(true);
1079 pullSigma.setConstant(true);
1080 pullGauss.paramOn(&frame, RooFit::Label(ss.str().c_str()), RooFit::Layout(0.60, 0.9, 0.9));
1081}
1082
1083} // namespace
1084
1085
1086////////////////////////////////////////////////////////////////////////////////
1087/// Plot the distribution of pull values for the specified parameter on a newly created frame. If asymmetric
1088/// errors are calculated in the fit (by MINOS) those will be used in the pull calculation.
1089///
1090/// If the parameters of the models for generation and fit differ, simple heuristics are used to find the
1091/// corresponding parameters:
1092/// - Parameters have the same name: They will be used to compute pulls.
1093/// - Parameters have different names: The position of the fit parameter in the set of fit parameters will be
1094/// computed. The parameter at the same position in the set of generator parameters will be used.
1095///
1096/// Further options:
1097/// <table>
1098/// <tr><th> Arguments <th> Effect
1099/// <tr><td> FrameRange(double lo, double hi) <td> Set range of frame to given specification
1100/// <tr><td> FrameBins(int bins) <td> Set default number of bins of frame to given number
1101/// <tr><td> Frame() <td> Pass supplied named arguments to RooAbsRealLValue::frame() function. See there
1102/// for list of allowed arguments
1103/// <tr><td> FitGauss(bool flag) <td> Add a gaussian fit to the frame
1104/// </table>
1105///
1106/// If no frame specifications are given, the AutoSymRange() feature will be used to set a default range.
1107/// Any other named argument is passed to the RooAbsData::plotOn(). See that function for allowed options.
1108///
1109/// If you want to have more control over the Gaussian fit to the pull
1110/// distribution, you can also do it after the call to plotPull():
1111///
1112/// ~~~ {.cpp}
1113/// RooPlot *frame = mcstudy->plotPull(myVariable, RooFit::Bins(40), RooFit::FitGauss(false));
1114/// RooRealVar pullMean("pullMean","Mean of pull",0,-10,10) ;
1115/// RooRealVar pullSigma("pullSigma","Width of pull",1,0.1,5) ;
1116/// pullMean.setPlotLabel("pull #mu"); // optional (to get nicer plot labels if you want)
1117/// pullSigma.setPlotLabel("pull #sigma"); // optional
1118/// RooGaussian pullGauss("pullGauss","Gaussian of pull", *frame->getPlotVar(), pullMean, pullSigma);
1119/// pullGauss.fitTo(const_cast<RooDataSet&>(mcstudy->fitParDataSet()),
1120/// RooFit::Minos(0), RooFit::PrintLevel(-1)) ;
1121/// pullGauss.plotOn(frame) ;
1122/// pullGauss.paramOn(frame, RooFit::Layout(0.65, 0.9, 0.9)); // optionally specify label position (xmin, xmax, ymax)
1123/// ~~~
1124
1126 const RooCmdArg& arg3, const RooCmdArg& arg4,
1127 const RooCmdArg& arg5, const RooCmdArg& arg6,
1128 const RooCmdArg& arg7, const RooCmdArg& arg8)
1129{
1130 // Stuff all arguments in a list
1132 cmdList.Add(const_cast<RooCmdArg*>(&arg1)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg2)) ;
1133 cmdList.Add(const_cast<RooCmdArg*>(&arg3)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg4)) ;
1134 cmdList.Add(const_cast<RooCmdArg*>(&arg5)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg6)) ;
1135 cmdList.Add(const_cast<RooCmdArg*>(&arg7)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg8)) ;
1136
1137 TString name(param.GetName());
1138 TString title(param.GetTitle());
1139 name.Append("pull") ; title.Append(" Pull") ;
1140 RooRealVar pvar(name,title,-100,100) ;
1141 pvar.setBins(100) ;
1142
1143
1144 RooPlot* frame = makeFrameAndPlotCmd(pvar, cmdList, true) ;
1145 if (frame) {
1146
1147 // Pick up optional FitGauss command from list
1148 RooCmdConfig pc("RooMCStudy::plotPull(" + std::string(_genModel->GetName()) + ")");
1149 pc.defineInt("fitGauss","FitGauss",0,0) ;
1150 pc.allowUndefined() ;
1151 pc.process(cmdList) ;
1152 bool fitGauss=pc.getInt("fitGauss") ;
1153
1154 // Pass stripped command list to plotOn()
1156 const bool success = _fitParData->plotOn(frame,cmdList) ;
1157
1158 if (!success) {
1159 coutF(Plotting) << "No pull distribution for the parameter '" << param.GetName() << "'. Check logs for errors." << std::endl;
1160 return frame;
1161 }
1162
1163 // Add Gaussian fit if requested
1164 if (fitGauss) {
1165 fitGaussToPulls(*frame, *_fitParData);
1166 }
1167
1168 // To make sure the frame has no dangling pointer to pvar.
1170 }
1171 return frame;
1172}
1173
1174
1175
1176////////////////////////////////////////////////////////////////////////////////
1177/// Internal function. Construct RooPlot from given parameter and modify the list of named
1178/// arguments 'cmdList' to only contain the plot arguments that should be forwarded to
1179/// RooAbsData::plotOn()
1180
1182{
1183 // Select the frame-specific commands
1184 RooCmdConfig pc("RooMCStudy::plotParam(" + std::string(_genModel->GetName()) + ")");
1185 pc.defineInt("nbins","Bins",0,0) ;
1186 pc.defineDouble("xlo","Range",0,0) ;
1187 pc.defineDouble("xhi","Range",1,0) ;
1188 pc.defineInt("dummy","FrameArgs",0,0) ;
1189 pc.defineMutex("Bins","FrameArgs") ;
1190 pc.defineMutex("Range","FrameArgs") ;
1191
1192 // Process and check varargs
1193 pc.allowUndefined() ;
1194 pc.process(cmdList) ;
1195 if (!pc.ok(true)) {
1196 return nullptr ;
1197 }
1198
1199 // Make frame according to specs
1200 Int_t nbins = pc.getInt("nbins") ;
1201 double xlo = pc.getDouble("xlo") ;
1202 double xhi = pc.getDouble("xhi") ;
1203 RooPlot* frame ;
1204
1205 if (pc.hasProcessed("FrameArgs")) {
1206 // Explicit frame arguments are given, pass them on
1207 RooCmdArg* frameArg = static_cast<RooCmdArg*>(cmdList.FindObject("FrameArgs")) ;
1208 frame = param.frame(frameArg->subArgs()) ;
1209 } else {
1210 // FrameBins, FrameRange or none are given, build custom frame command list
1211 RooCmdArg bins = RooFit::Bins(nbins) ;
1212 RooCmdArg range = RooFit::Range(xlo,xhi) ;
1215
1216 if (pc.hasProcessed("Bins")) frameCmdList.Add(&bins) ;
1217 if (pc.hasProcessed("Range")) {
1218 frameCmdList.Add(&range) ;
1219 } else {
1220 frameCmdList.Add(&autoRange) ;
1221 }
1222 frame = param.frame(frameCmdList) ;
1223 }
1224
1225 // Filter frame command from list and pass on to plotOn()
1226 RooCmdConfig::stripCmdList(cmdList,"FrameArgs,Bins,Range") ;
1227
1228 return frame ;
1229}
1230
1231
1232
1233////////////////////////////////////////////////////////////////////////////////
1234/// Create a RooPlot of the -log(L) distribution in the range lo-hi
1235/// with 'nBins' bins
1236
1237RooPlot* RooMCStudy::plotNLL(double lo, double hi, Int_t nBins)
1238{
1239 RooPlot* frame = _nllVar->frame(lo,hi,nBins) ;
1240
1241 _fitParData->plotOn(frame) ;
1242 return frame ;
1243}
1244
1245
1246
1247////////////////////////////////////////////////////////////////////////////////
1248/// Create a RooPlot of the distribution of the fitted errors of the given parameter.
1249/// The frame is created with a range [lo,hi] and plotted data will be binned in 'nbins' bins
1250
1251RooPlot* RooMCStudy::plotError(const RooRealVar& param, double lo, double hi, Int_t nbins)
1252{
1253 if (_canAddFitResults) {
1254 calcPulls() ;
1256 }
1257
1258 std::unique_ptr<RooErrorVar> evar{param.errorVar()};
1259 RooPlot* frame = evar->frame(lo,hi,nbins) ;
1260 _fitParData->plotOn(frame) ;
1261
1262 return frame ;
1263}
1264
1265
1266
1267////////////////////////////////////////////////////////////////////////////////
1268/// Create a RooPlot of the pull distribution for the given
1269/// parameter. The range lo-hi is plotted in nbins. If fitGauss is
1270/// set, an unbinned ML fit of the distribution to a Gaussian p.d.f
1271/// is performed. The fit result is overlaid on the returned RooPlot
1272/// and a box with the fitted mean and sigma is added.
1273///
1274/// If the parameters of the models for generation and fit differ, simple heuristics are used to find the
1275/// corresponding parameters:
1276/// - Parameters have the same name: They will be used to compute pulls.
1277/// - Parameters have different names: The position of the fit parameter in the set of fit parameters will be
1278/// computed. The parameter at the same position in the set of generator parameters will be used.
1279
1280RooPlot* RooMCStudy::plotPull(const RooRealVar& param, double lo, double hi, Int_t nbins, bool fitGauss)
1281{
1282 if (_canAddFitResults) {
1283 calcPulls() ;
1285 }
1286
1287 TString name(param.GetName());
1288 TString title(param.GetTitle());
1289 name.Append("pull") ; title.Append(" Pull") ;
1290 RooRealVar pvar(name,title,lo,hi) ;
1291 pvar.setBins(nbins) ;
1292
1293 RooPlot* frame = pvar.frame() ;
1294 const bool success = _fitParData->plotOn(frame);
1295
1296 if (!success) {
1297 coutF(Plotting) << "No pull distribution for the parameter '" << param.GetName() << "'. Check logs for errors." << std::endl;
1298 return frame;
1299 }
1300
1301 if (fitGauss) {
1302 fitGaussToPulls(*frame, *_fitParData);
1303 }
1304
1305 return frame ;
1306}
1307
1308
1309////////////////////////////////////////////////////////////////////////////////
1310/// If one of the TObject we have a referenced to is deleted, remove the
1311/// reference.
1312
1314{
1318 if (_ngenVar.get() == obj) _ngenVar.reset();
1319
1320 if (_fitParData) _fitParData->RecursiveRemove(obj);
1321 if (_fitParData.get() == obj) _fitParData.reset();
1322
1323 if (_genParData) _genParData->RecursiveRemove(obj);
1324 if (_genParData.get() == obj) _genParData.reset();
1325}
1326
#define coutI(a)
#define oocoutW(o, a)
#define coutW(a)
#define coutF(a)
#define oocoutE(o, a)
#define oocoutI(o, a)
#define coutE(a)
#define ooccoutI(o, a)
#define ooccoutP(o, a)
#define oocoutP(o, a)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
char name[80]
Definition TGX11.cxx:148
#define hi
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2570
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
RooFit::OwningPtr< RooArgSet > getParameters(const RooAbsData *data, bool stripDisconnected=true) const
Create a list of leaf nodes in the arg tree starting with ourself as top node that don't match any of...
RooFit::OwningPtr< RooArgSet > getObservables(const RooArgSet &set, bool valueOnly=true) const
Given a set of possible observables, return the observables that this PDF depends on.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
const_iterator end() const
void assign(const RooAbsCollection &other) const
Sets the value, cache and constant attribute of any argument in our set that also appears in the othe...
Storage_t::size_type size() const
const_iterator begin() const
RooAbsArg * find(const char *name) const
Find object with given name in list.
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:56
virtual double sumEntries() const =0
Return effective number of entries in dataset, i.e., sum all weights.
virtual const RooArgSet * get() const
Definition RooAbsData.h:100
Base class for add-on modules to RooMCStudy that can perform additional calculations on each generate...
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
std::unique_ptr< RooArgSet > getAllConstraints(const RooArgSet &observables, RooArgSet &constrainedParams, bool stripDisconnected=true) const
This helper function finds and collects all constraints terms of all component p.d....
virtual double expectedEvents(const RooArgSet *nset) const
Return expected number of events to be used in calculation of extended likelihood.
Int_t * randomizeProtoOrder(Int_t nProto, Int_t nGen, bool resample=false) const
Return lookup table with randomized order for nProto prototype events.
RooFit::OwningPtr< RooFitResult > fitTo(RooAbsData &data, CmdArgs_t const &... cmdArgs)
Fit PDF to given dataset.
Definition RooAbsPdf.h:149
virtual RooFit::OwningPtr< RooDataHist > generateBinned(const RooArgSet &whatVars, double nEvents, const RooCmdArg &arg1, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}) const
As RooAbsPdf::generateBinned(const RooArgSet&, const RooCmdArg&,const RooCmdArg&, const RooCmdArg&,...
Definition RooAbsPdf.h:102
virtual RooAbsGenContext * genContext(const RooArgSet &vars, const RooDataSet *prototype=nullptr, const RooArgSet *auxProto=nullptr, bool verbose=false) const
Interface function to create a generator context from a p.d.f.
RooPlot * frame(const RooCmdArg &arg1, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}) const
Create a new RooPlot on the heap with a drawing frame initialized for this object,...
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
RooArgSet * snapshot(bool deepCopy=true) const
Use RooAbsCollection::snapshot(), but return as RooArgSet.
Definition RooArgSet.h:159
Named container for two doubles, two integers two object points and three string pointers that can be...
Definition RooCmdArg.h:26
TObject * Clone(const char *newName=nullptr) const override
Make a clone of an object using the Streamer facility.
Definition RooCmdArg.h:58
Configurable parser for RooCmdArg named arguments.
void defineMutex(const char *head, Args_t &&... tail)
Define arguments where any pair is mutually exclusive.
bool process(const RooCmdArg &arg)
Process given RooCmdArg.
bool hasProcessed(const char *cmdName) const
Return true if RooCmdArg with name 'cmdName' has been processed.
double getDouble(const char *name, double defaultValue=0.0) const
Return double property registered with name 'name'.
bool defineDouble(const char *name, const char *argName, int doubleNum, double defValue=0.0)
Define double property name 'name' mapped to double in slot 'doubleNum' in RooCmdArg with name argNam...
static void stripCmdList(RooLinkedList &cmdList, const char *cmdsToPurge)
Utility function that strips command names listed (comma separated) in cmdsToPurge from cmdList.
RooArgSet * getSet(const char *name, RooArgSet *set=nullptr) const
Return RooArgSet property registered with name 'name'.
bool defineSet(const char *name, const char *argName, int setNum, const RooArgSet *set=nullptr)
Define TObject property name 'name' mapped to object in slot 'setNum' in RooCmdArg with name argName ...
bool ok(bool verbose) const
Return true of parsing was successful.
bool defineObject(const char *name, const char *argName, int setNum, const TObject *obj=nullptr, bool isArray=false)
Define TObject property name 'name' mapped to object in slot 'setNum' in RooCmdArg with name argName ...
bool defineInt(const char *name, const char *argName, int intNum, int defValue=0)
Define integer property name 'name' mapped to integer in slot 'intNum' in RooCmdArg with name argName...
void allowUndefined(bool flag=true)
If flag is true the processing of unrecognized RooCmdArgs is not considered an error.
int getInt(const char *name, int defaultValue=0) const
Return integer property registered with name 'name'.
TObject * getObject(const char *name, TObject *obj=nullptr) const
Return TObject property registered with name 'name'.
Container class to hold unbinned data.
Definition RooDataSet.h:32
static RooDataSet * read(const char *filename, const RooArgList &variables, const char *opts="", const char *commonPath="", const char *indexCatName=nullptr)
Read data from a text file and create a dataset from it.
RooFitResult is a container class to hold the input and output of a PDF fit to a dataset.
const RooArgList & floatParsFinal() const
Return list of floating parameters after fit.
Int_t status() const
Return MINUIT status code.
double minNll() const
Return minimized -log(L) value.
Collection class for internal use, storing a collection of RooAbsArg pointers in a doubly linked list...
void RecursiveRemove(TObject *obj) override
If one of the TObject we have a referenced to is deleted, remove the reference.
void Delete(Option_t *o=nullptr) override
Remove all elements in collection and delete all elements NB: Collection does not own elements,...
virtual void Add(TObject *arg)
TObject * FindObject(const char *name) const override
Return pointer to object with given name.
bool addFitResult(const RooFitResult &fr)
Utility function to add fit result from external fit to this RooMCStudy and process its results throu...
RooPlot * plotParam(const RooRealVar &param, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={})
Plot the distribution of the fitted value of the given parameter on a newly created frame.
RooAbsData * _genSample
Currently generated sample.
Definition RooMCStudy.h:115
RooPlot * makeFrameAndPlotCmd(const RooRealVar &param, RooLinkedList &cmdList, bool symRange=false) const
Internal function.
RooArgSet _projDeps
List of projected dependents in fit.
Definition RooMCStudy.h:121
RooArgSet _genParams
List of actual generator parameters.
Definition RooMCStudy.h:119
const RooArgSet * fitParams(Int_t sampleNum) const
Return an argset with the fit parameters for the given sample number.
void calcPulls()
Calculate the pulls for all fit parameters in the fit results data set, and add them to that dataset.
~RooMCStudy() override
RooArgSet _dependents
List of dependents.
Definition RooMCStudy.h:126
bool _verboseGen
Verbose generation?
Definition RooMCStudy.h:145
std::list< RooAbsMCStudyModule * > _modList
List of additional study modules ;.
Definition RooMCStudy.h:149
std::unique_ptr< RooDataSet > _genParData
Definition RooMCStudy.h:136
RooArgSet _genInitParams
List of original generator parameters.
Definition RooMCStudy.h:118
TList _fitResList
Definition RooMCStudy.h:135
double _nExpGen
Definition RooMCStudy.h:141
bool fitSample(RooAbsData *genSample)
Internal method.
RooPlot * plotNLL(const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={})
Plot the distribution of the -log(L) values on a newly created frame.
std::unique_ptr< RooDataSet > _fitParData
Definition RooMCStudy.h:137
bool generate(Int_t nSamples, Int_t nEvtPerSample=0, bool keepGenData=false, const char *asciiFilePat=nullptr)
Generate 'nSamples' samples of 'nEvtPerSample' events.
bool _extendedGen
Definition RooMCStudy.h:139
const RooDataSet * _genProtoData
Generator prototype data set.
Definition RooMCStudy.h:120
bool _canAddFitResults
Allow adding of external fit results?
Definition RooMCStudy.h:144
const RooFitResult * fitResult(Int_t sampleNum) const
Return the RooFitResult of the fit with the given run number.
RooFit::OwningPtr< RooFitResult > doFit(RooAbsData *genSample)
Internal function. Performs actual fit according to specifications.
std::unique_ptr< RooAbsGenContext > _constrGenContext
Generator context for constraints p.d.f.
Definition RooMCStudy.h:124
bool _perExptGenParams
Do generation parameter change per event?
Definition RooMCStudy.h:146
bool _binGenData
Definition RooMCStudy.h:140
bool _silence
Silent running mode?
Definition RooMCStudy.h:147
RooPlot * plotParamOn(RooPlot *frame, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={})
Plot the distribution of fitted values of a parameter.
RooArgSet _fitParams
List of actual fit parameters.
Definition RooMCStudy.h:130
RooPlot * plotError(const RooRealVar &param, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={})
Plot the distribution of the fit errors for the specified parameter on a newly created frame.
std::unique_ptr< RooAbsGenContext > _genContext
Generator context.
Definition RooMCStudy.h:117
RooMCStudy(const RooAbsPdf &model, const RooArgSet &observables, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={})
Construct Monte Carlo Study Manager.
RooFit::OwningPtr< RooFitResult > refit(RooAbsData *genSample=nullptr)
Redo fit on 'current' toy sample, or if genSample is not nullptr do fit on given sample instead.
RooAbsData * genData(Int_t sampleNum) const
Return the given generated dataset.
void RecursiveRemove(TObject *obj) override
If one of the TObject we have a referenced to is deleted, remove the reference.
RooAbsPdf * _genModel
Generator model.
Definition RooMCStudy.h:116
const RooDataSet & fitParDataSet()
Return a RooDataSet containing the post-fit parameters of each toy cycle.
std::unique_ptr< RooRealVar > _nllVar
Definition RooMCStudy.h:131
RooLinkedList _fitOptList
Definition RooMCStudy.h:138
std::unique_ptr< RooAbsPdf > _constrPdf
Constraints p.d.f.
Definition RooMCStudy.h:123
RooArgSet _allDependents
List of generate + prototype dependents.
Definition RooMCStudy.h:127
bool run(bool generate, bool fit, Int_t nSamples, Int_t nEvtPerSample, bool keepGenData, const char *asciiFilePat)
Run engine method.
void resetFitParams()
Reset all fit parameters to the initial model parameters at the time of the RooMCStudy constructor.
RooAbsPdf * _fitModel
Fit model.
Definition RooMCStudy.h:128
bool fit(Int_t nSamples, const char *asciiFilePat)
Fit 'nSamples' datasets, which are read from ASCII files.
bool generateAndFit(Int_t nSamples, Int_t nEvtPerSample=0, bool keepGenData=false, const char *asciiFilePat=nullptr)
Generate and fit 'nSamples' samples of 'nEvtPerSample' events.
RooPlot * plotPull(const RooRealVar &param, const RooCmdArg &arg1, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={})
Plot the distribution of pull values for the specified parameter on a newly created frame.
TList _genDataList
Definition RooMCStudy.h:134
bool _randProto
Definition RooMCStudy.h:142
void addModule(RooAbsMCStudyModule &module)
Insert given RooMCStudy add-on module to the processing chain of this MCStudy object.
RooArgSet _fitInitParams
List of initial values of fit parameters.
Definition RooMCStudy.h:129
std::unique_ptr< RooRealVar > _ngenVar
Definition RooMCStudy.h:132
static RooMsgService & instance()
Return reference to singleton instance.
Plot frame and a container for graphics objects within that frame.
Definition RooPlot.h:43
RooAbsRealLValue * getPlotVar() const
Definition RooPlot.h:137
void createInternalPlotVarClone()
Replaces the pointer to the plot variable with a pointer to a clone of the plot variable that is owne...
Definition RooPlot.cxx:1401
Represents the pull of a measurement w.r.t.
Definition RooPullVar.h:24
static TRandom * randomGenerator()
Return a pointer to a singleton random-number generator implementation.
Definition RooRandom.cxx:47
Variable that can be changed from the outside.
Definition RooRealVar.h:37
RooErrorVar * errorVar() const
Return a RooAbsRealLValue representing the error associated with this variable.
Persistable container for RooFit projects.
RooAbsPdf * pdf(RooStringView name) const
Retrieve p.d.f (RooAbsPdf) with given name. A null pointer is returned if not found.
RooFactoryWSTool & factory()
Return instance to factory tool.
RooRealVar * var(RooStringView name) const
Retrieve real-valued variable (RooRealVar) with given name. A null pointer is returned if not found.
bool import(const RooAbsArg &arg, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}, const RooCmdArg &arg9={})
Import a RooAbsArg object, e.g.
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
A doubly linked list.
Definition TList.h:38
void RecursiveRemove(TObject *obj) override
Remove object from this collection and recursively remove the object from all other objects (and coll...
Definition TList.cxx:894
void Add(TObject *obj) override
Definition TList.h:81
void Delete(Option_t *option="") override
Remove all objects from the list AND delete all heap based objects.
Definition TList.cxx:600
TObject * At(Int_t idx) const override
Returns the object at position idx. Returns 0 if idx is out of range.
Definition TList.cxx:487
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
Mother of all ROOT objects.
Definition TObject.h:42
Basic string class.
Definition TString.h:138
TString & Append(const char *cs)
Definition TString.h:583
RooCmdArg AutoRange(const RooAbsData &data, double marginFactor=0.1)
RooCmdArg Label(const char *str)
RooCmdArg AutoSymRange(const RooAbsData &data, double marginFactor=0.1)
RooCmdArg Bins(Int_t nbin)
RooCmdArg Layout(double xmin, double xmax=0.99, double ymin=0.95)
RooCmdArg Constrain(const RooArgSet &params)
RooCmdArg Save(bool flag=true)
RooCmdArg ExternalConstraints(const RooArgSet &constraintPdfs)
RooCmdArg Minos(bool flag=true)
RooCmdArg PrintLevel(Int_t code)
RooCmdArg ConditionalObservables(Args_t &&... argsOrArgSet)
Create a RooCmdArg to declare conditional observables.
RooCmdArg Range(const char *rangeName, bool adjustNorm=true)
T * OwningPtr
An alias for raw pointers for indicating that the return type of a RooFit function is an owning point...
Definition Config.h:35
MsgLevel
Verbosity level for RooMsgService::StreamConfig in RooMsgService.
OwningPtr< T > makeOwningPtr(std::unique_ptr< T > &&ptr)
Internal helper to turn a std::unique_ptr<T> into an OwningPtr.
Definition Config.h:40