Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooAbsPdf.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/** \class RooAbsPdf
19 \ingroup Roofitcore
20
21## RooAbsPdf, the base class of all PDFs
22
23RooAbsPdf is the abstract interface for all probability density
24functions. The class provides hybrid analytical/numerical
25normalization for its implementations, error tracing, and a Monte Carlo
26generator interface.
27
28### A Minimal PDF Implementation
29
30A minimal implementation of a PDF class derived from RooAbsPdf
31should override the `evaluate()` function. This function should
32return the PDF's value (which does not need to be normalised).
33
34
35#### Normalization/Integration
36
37Although the normalization of a PDF is an integral part of a
38probability density function, normalization is treated separately
39in RooAbsPdf. The reason is that a RooAbsPdf object is more than a
40PDF: it can be a building block for a more complex composite PDF
41if any of its variables are functions instead of variables. In
42such cases, the normalization of the composite PDF may not simply be
43integral over the dependents of the top-level PDF: these are
44functions with potentially non-trivial Jacobian terms themselves.
45\note Therefore, no explicit attempt should be made to normalize the
46function output in evaluate(). In particular, normalisation constants
47can be omitted to speed up the function evaluations, and included later
48in the integration of the PDF (see below), which is rarely called in
49comparison to the `evaluate()` function.
50
51In addition, RooAbsPdf objects do not have a static concept of what
52variables are parameters, and what variables are dependents (which
53need to be integrated over for a correct PDF normalization).
54Instead, the choice of normalization is always specified each time a
55normalized value is requested from the PDF via the getVal()
56method.
57
58RooAbsPdf manages the entire normalization logic of each PDF with
59the help of a RooRealIntegral object, which coordinates the integration
60of a given choice of normalization. By default, RooRealIntegral will
61perform an entirely numeric integration of all dependents. However,
62PDFs can advertise one or more (partial) analytical integrals of
63their function, and these will be used by RooRealIntegral, if it
64determines that this is safe (i.e., no hidden Jacobian terms,
65multiplication with other PDFs that have one or more dependents in
66common, etc).
67
68#### Implementing analytical integrals
69To implement analytical integrals, two functions must be implemented. First,
70
71```
72Int_t getAnalyticalIntegral(const RooArgSet& integSet, RooArgSet& anaIntSet)
73```
74should return the analytical integrals that are supported. `integSet`
75is the set of dependents for which integration is requested. The
76function should copy the subset of dependents it can analytically
77integrate to `anaIntSet`, and return a unique identification code for
78this integration configuration. If no integration can be
79performed, zero should be returned. Second,
80
81```
82double analyticalIntegral(Int_t code)
83```
84
85implements the actual analytical integral(s) advertised by
86`getAnalyticalIntegral()`. This function will only be called with
87codes returned by `getAnalyticalIntegral()`, except code zero.
88
89The integration range for each dependent to be integrated can
90be obtained from the dependent's proxy functions `min()` and
91`max()`. Never call these proxy functions for any proxy not known to
92be a dependent via the integration code. Doing so may be
93ill-defined, e.g., in case the proxy holds a function, and will
94trigger an assert. Integrated category dependents should always be
95summed over all of their states.
96
97
98
99### Direct generation of observables
100
101Distributions for any PDF can be generated with the accept/reject method,
102but for certain PDFs, more efficient methods may be implemented. To
103implement direct generation of one or more observables, two
104functions need to be implemented, similar to those for analytical
105integrals:
106
107```
108Int_t getGenerator(const RooArgSet& generateVars, RooArgSet& directVars)
109```
110and
111```
112void generateEvent(Int_t code)
113```
114
115The first function advertises observables, for which distributions can be generated,
116similar to the way analytical integrals are advertised. The second
117function implements the actual generator for the advertised observables.
118
119The generated dependent values should be stored in the proxy
120objects. For this, the assignment operator can be used (i.e. `xProxy
121= 3.0` ). Never call assign to any proxy not known to be a dependent
122via the generation code. Doing so may be ill-defined, e.g. in case
123the proxy holds a function, and will trigger an assert.
124
125
126### Batched function evaluations (Advanced usage)
127
128To speed up computations with large numbers of data events in unbinned fits,
129it is beneficial to override `computeBatch()`. Like this, large spans of
130computations can be done, without having to call `evaluate()` for each single data event.
131`computeBatch()` should execute the same computation as `evaluate()`, but it
132may choose an implementation that is capable of SIMD computations.
133If computeBatch is not implemented, the classic and slower `evaluate()` will be
134called for each data event.
135*/
136
137#include "RooAbsPdf.h"
138
139#include "FitHelpers.h"
140#include "RooNormalizedPdf.h"
141#include "RooMsgService.h"
142#include "RooArgSet.h"
143#include "RooArgProxy.h"
144#include "RooRealProxy.h"
145#include "RooRealVar.h"
146#include "RooGenContext.h"
147#include "RooBinnedGenContext.h"
148#include "RooPlot.h"
149#include "RooCurve.h"
150#include "RooNLLVar.h"
151#include "RooCategory.h"
152#include "RooNameReg.h"
153#include "RooCmdConfig.h"
154#include "RooGlobalFunc.h"
155#include "RooAddition.h"
156#include "RooRandom.h"
157#include "RooNumIntConfig.h"
158#include "RooProjectedPdf.h"
159#include "RooParamBinning.h"
160#include "RooNumCdf.h"
161#include "RooFitResult.h"
162#include "RooNumGenConfig.h"
163#include "RooCachedReal.h"
164#include "RooRealIntegral.h"
165#include "RooWorkspace.h"
166#include "RooNaNPacker.h"
167#include "RooHelpers.h"
168#include "RooFormulaVar.h"
169#include "RooDerivative.h"
173#include "ConstraintHelpers.h"
174#include "RooFit/Evaluator.h"
175#include "RooEvaluatorWrapper.h"
176#include "RooSimultaneous.h"
177#include "RooFuncWrapper.h"
178
179#include "ROOT/StringUtils.hxx"
180#include "TMath.h"
181#include "TPaveText.h"
182#include "TMatrixD.h"
183#include "TMatrixDSym.h"
184
185#include <algorithm>
186#include <iostream>
187#include <string>
188#include <cmath>
189#include <stdexcept>
190
191bool RooAbsPdf::interpretExtendedCmdArg(int extendedCmdArg) const
192{
193 // Process automatic extended option
194 if (extendedCmdArg == RooFit::FitHelpers::extendedFitDefault) {
196 if (ext) {
197 coutI(Minimization) << "p.d.f. provides expected number of events, including extended term in likelihood."
198 << std::endl;
199 }
200 return ext;
201 }
202 // If Extended(false) was explicitly set, but the pdf MUST be extended, then
203 // it's time to print an error. This happens when you're fitting a RooAddPdf
204 // with coefficient that represent yields, and without the additional
205 // constraint these coefficients are degenerate because the RooAddPdf
206 // normalizes itself. Nothing correct can come out of this.
207 if (extendedCmdArg == 0) {
208 if (this->extendMode() == RooAbsPdf::MustBeExtended) {
209 std::string errMsg = "You used the Extended(false) option on a pdf where the fit MUST be extended! "
210 "The parameters are not well defined and you're getting nonsensical results.";
211 coutE(InputArguments) << errMsg << std::endl;
212 }
213 }
214 return extendedCmdArg;
215}
216
217namespace {
218
219inline double getLog(double prob, RooAbsReal const *caller)
220{
221
222 if (std::abs(prob) > 1e6) {
223 oocoutW(caller, Eval) << "RooAbsPdf::getLogVal(" << caller->GetName()
224 << ") WARNING: top-level pdf has a large value: " << prob << std::endl;
225 }
226
227 if (prob < 0) {
228 caller->logEvalError("getLogVal() top-level p.d.f evaluates to a negative number");
229 return RooNaNPacker::packFloatIntoNaN(-prob);
230 }
231
232 if (prob == 0) {
233 caller->logEvalError("getLogVal() top-level p.d.f evaluates to zero");
234
235 return -std::numeric_limits<double>::infinity();
236 }
237
238 if (TMath::IsNaN(prob)) {
239 caller->logEvalError("getLogVal() top-level p.d.f evaluates to NaN");
240
241 return prob;
242 }
243
244 return std::log(prob);
245}
246
247/// To set the fitrange attribute of the PDF and custom ranges for the
248/// observables so that RooPlot can automatically plot the fitting range.
249void resetFitrangeAttributes(RooAbsArg& pdf, RooAbsData const& data, std::string const& baseName,
250 const char* rangeName, bool splitRange)
251{
252 // Clear possible range attributes from previous fits.
253 pdf.removeStringAttribute("fitrange");
254
255 // No fitrange was specified, so we do nothing. Or "SplitRange" is used, and
256 // then there are no uniquely defined ranges for the observables (as they
257 // are different in each category).
258 if(!rangeName || splitRange) return;
259
260 RooArgSet observables;
261 pdf.getObservables(data.get(), observables) ;
262
263 std::string fitrangeValue;
264 auto subranges = ROOT::Split(rangeName, ",");
265 for (auto const &subrange : subranges) {
266 if (subrange.empty())
267 continue;
268 std::string fitrangeValueSubrange = std::string("fit_") + baseName;
269 if (subranges.size() > 1) {
270 fitrangeValueSubrange += "_" + subrange;
271 }
272 fitrangeValue += fitrangeValueSubrange + ",";
273 for (RooAbsArg *arg : observables) {
274
275 if(arg->isCategory()) continue;
276 auto& observable = static_cast<RooRealVar&>(*arg);
277
278 observable.setRange(fitrangeValueSubrange.c_str(), observable.getMin(subrange.c_str()),
279 observable.getMax(subrange.c_str()));
280 }
281 }
282 pdf.setStringAttribute("fitrange", fitrangeValue.substr(0, fitrangeValue.size() - 1).c_str());
283}
284
285
286} // namespace
287
288using namespace std;
289
291
293
295
296
299
300////////////////////////////////////////////////////////////////////////////////
301/// Default constructor
302
303RooAbsPdf::RooAbsPdf() :_normMgr(this,10)
304{
306 _negCount = 0 ;
307 _rawValue = 0 ;
308 _selectComp = false ;
309 _traceCount = 0 ;
310}
311
312
313
314////////////////////////////////////////////////////////////////////////////////
315/// Constructor with name and title only
316
317RooAbsPdf::RooAbsPdf(const char *name, const char *title) :
318 RooAbsReal(name,title), _normMgr(this,10), _selectComp(true)
319{
321 setTraceCounter(0) ;
322}
323
324
325
326////////////////////////////////////////////////////////////////////////////////
327/// Constructor with name, title, and plot range
328
329RooAbsPdf::RooAbsPdf(const char *name, const char *title,
330 double plotMin, double plotMax) :
331 RooAbsReal(name,title,plotMin,plotMax), _normMgr(this,10), _selectComp(true)
332{
334 setTraceCounter(0) ;
335}
336
337
338
339////////////////////////////////////////////////////////////////////////////////
340/// Copy constructor
341
342RooAbsPdf::RooAbsPdf(const RooAbsPdf& other, const char* name) :
343 RooAbsReal(other,name),
344 _normMgr(other._normMgr,this), _selectComp(other._selectComp), _normRange(other._normRange)
345{
348
349 if (other._specGeneratorConfig) {
350 _specGeneratorConfig = std::make_unique<RooNumGenConfig>(*other._specGeneratorConfig);
351 }
352}
353
354
355
356////////////////////////////////////////////////////////////////////////////////
357/// Destructor
358
360{
361}
362
363
364double RooAbsPdf::normalizeWithNaNPacking(double rawVal, double normVal) const {
365
366 if (normVal < 0. || (normVal == 0. && rawVal != 0)) {
367 //Unreasonable normalisations. A zero integral can be tolerated if the function vanishes, though.
368 const std::string msg = "p.d.f normalization integral is zero or negative: " + std::to_string(normVal);
369 logEvalError(msg.c_str());
371 return RooNaNPacker::packFloatIntoNaN(-normVal + (rawVal < 0. ? -rawVal : 0.));
372 }
373
374 if (rawVal < 0.) {
375 logEvalError(Form("p.d.f value is less than zero (%f), trying to recover", rawVal));
377 return RooNaNPacker::packFloatIntoNaN(-rawVal);
378 }
379
380 if (TMath::IsNaN(rawVal)) {
381 logEvalError("p.d.f value is Not-a-Number");
383 return rawVal;
384 }
385
386 return (rawVal == 0. && normVal == 0.) ? 0. : rawVal / normVal;
387}
388
389
390////////////////////////////////////////////////////////////////////////////////
391/// Return current value, normalized by integrating over
392/// the observables in `nset`. If `nset` is 0, the unnormalized value
393/// is returned. All elements of `nset` must be lvalues.
394///
395/// Unnormalized values are not cached.
396/// Doing so would be complicated as `_norm->getVal()` could
397/// spoil the cache and interfere with returning the cached
398/// return value. Since unnormalized calls are typically
399/// done in integration calls, there is no performance hit.
400
401double RooAbsPdf::getValV(const RooArgSet* nset) const
402{
403
404 // Special handling of case without normalization set (used in numeric integration of pdfs)
405 if (!nset) {
406 RooArgSet const* tmp = _normSet ;
407 _normSet = nullptr ;
408 double val = evaluate() ;
409 _normSet = tmp ;
410
411 return TMath::IsNaN(val) ? 0. : val;
412 }
413
414
415 // Process change in last data set used
416 bool nintChanged(false) ;
417 if (!isActiveNormSet(nset) || _norm==0) {
418 nintChanged = syncNormalization(nset) ;
419 }
420
421 // Return value of object. Calculated if dirty, otherwise cached value is returned.
422 if (isValueDirty() || nintChanged || _norm->isValueDirty()) {
423
424 // Evaluate numerator
425 const double rawVal = evaluate();
426
427 // Evaluate denominator
428 const double normVal = _norm->getVal();
429
430 _value = normalizeWithNaNPacking(rawVal, normVal);
431
433 }
434
435 return _value ;
436}
437
438
439////////////////////////////////////////////////////////////////////////////////
440/// Analytical integral with normalization (see RooAbsReal::analyticalIntegralWN() for further information).
441///
442/// This function applies the normalization specified by `normSet` to the integral returned
443/// by RooAbsReal::analyticalIntegral(). The passthrough scenario (code=0) is also changed
444/// to return a normalized answer.
445
446double RooAbsPdf::analyticalIntegralWN(Int_t code, const RooArgSet* normSet, const char* rangeName) const
447{
448 cxcoutD(Eval) << "RooAbsPdf::analyticalIntegralWN(" << GetName() << ") code = " << code << " normset = " << (normSet?*normSet:RooArgSet()) << endl ;
449
450
451 if (code==0) return getVal(normSet) ;
452 if (normSet) {
453 return analyticalIntegral(code,rangeName) / getNorm(normSet) ;
454 } else {
455 return analyticalIntegral(code,rangeName) ;
456 }
457}
458
459
460
461////////////////////////////////////////////////////////////////////////////////
462/// Check that passed value is positive and not 'not-a-number'. If
463/// not, print an error, until the error counter reaches its set
464/// maximum.
465
467{
468 // check for a math error or negative value
469 bool error(false) ;
470 if (TMath::IsNaN(value)) {
471 logEvalError(Form("p.d.f value is Not-a-Number (%f), forcing value to zero",value)) ;
472 error=true ;
473 }
474 if (value<0) {
475 logEvalError(Form("p.d.f value is less than zero (%f), forcing value to zero",value)) ;
476 error=true ;
477 }
478
479 // do nothing if we are no longer tracing evaluations and there was no error
480 if(!error) return error ;
481
482 // otherwise, print out this evaluations input values and result
483 if(++_errorCount <= 10) {
484 cxcoutD(Tracing) << "*** Evaluation Error " << _errorCount << " ";
485 if(_errorCount == 10) cxcoutD(Tracing) << "(no more will be printed) ";
486 }
487 else {
488 return error ;
489 }
490
491 Print() ;
492 return error ;
493}
494
495
496////////////////////////////////////////////////////////////////////////////////
497/// Get normalisation term needed to normalise the raw values returned by
498/// getVal(). Note that `getVal(normalisationVariables)` will automatically
499/// apply the normalisation term returned here.
500/// \param nset Set of variables to normalise over.
501double RooAbsPdf::getNorm(const RooArgSet* nset) const
502{
503 if (!nset) return 1 ;
504
505 syncNormalization(nset,true) ;
506 if (_verboseEval>1) cxcoutD(Tracing) << ClassName() << "::getNorm(" << GetName() << "): norm(" << _norm << ") = " << _norm->getVal() << endl ;
507
508 double ret = _norm->getVal() ;
509 if (ret==0.) {
510 if(++_errorCount <= 10) {
511 coutW(Eval) << "RooAbsPdf::getNorm(" << GetName() << ":: WARNING normalization is zero, nset = " ; nset->Print("1") ;
512 if(_errorCount == 10) coutW(Eval) << "RooAbsPdf::getNorm(" << GetName() << ") INFO: no more messages will be printed " << endl ;
513 }
514 }
515
516 return ret ;
517}
518
519
520
521////////////////////////////////////////////////////////////////////////////////
522/// Return pointer to RooAbsReal object that implements calculation of integral over observables iset in range
523/// rangeName, optionally taking the integrand normalized over observables nset
524
525const RooAbsReal* RooAbsPdf::getNormObj(const RooArgSet* nset, const RooArgSet* iset, const TNamed* rangeName) const
526{
527 // Check normalization is already stored
528 CacheElem* cache = (CacheElem*) _normMgr.getObj(nset,iset,0,rangeName) ;
529 if (cache) {
530 return cache->_norm ;
531 }
532
533 // If not create it now
534 RooArgSet depList;
535 getObservables(iset, depList);
536
537 // Normalization is always over all pdf components. Overriding the global
538 // component selection temporarily makes all RooRealIntegrals created during
539 // that time always include all components.
540 GlobalSelectComponentRAII globalSelComp(true);
541 RooAbsReal* norm = std::unique_ptr<RooAbsReal>{createIntegral(depList,*nset, *getIntegratorConfig(), RooNameReg::str(rangeName))}.release();
542
543 // Store it in the cache
544 cache = new CacheElem(*norm) ;
545 _normMgr.setObj(nset,iset,cache,rangeName) ;
546
547 // And return the newly created integral
548 return norm ;
549}
550
551
552
553////////////////////////////////////////////////////////////////////////////////
554/// Verify that the normalization integral cached with this PDF
555/// is valid for given set of normalization observables.
556///
557/// If not, the cached normalization integral (if any) is deleted
558/// and a new integral is constructed for use with 'nset'.
559/// Elements in 'nset' can be discrete and real, but must be lvalues.
560///
561/// For functions that declare to be self-normalized by overloading the
562/// selfNormalized() function, a unit normalization is always constructed.
563
564bool RooAbsPdf::syncNormalization(const RooArgSet* nset, bool adjustProxies) const
565{
566 setActiveNormSet(nset);
567
568 // Check if data sets are identical
569 CacheElem* cache = (CacheElem*) _normMgr.getObj(nset) ;
570 if (cache) {
571
572 bool nintChanged = (_norm!=cache->_norm) ;
573 _norm = cache->_norm ;
574
575 // In the past, this condition read `if (nintChanged && adjustProxies)`.
576 // However, the cache checks if the nset was already cached **by content**,
577 // and not by RooArgSet instance! So it can happen that the normalization
578 // set object is different, but the integral object is the same, in which
579 // case it would be wrong to not adjust the proxies. They always have to be
580 // adjusted when the nset changed, which is always the case when
581 // `syncNormalization()` is called.
582 if (adjustProxies) {
583 // Update dataset pointers of proxies
584 ((RooAbsPdf*) this)->setProxyNormSet(nset) ;
585 }
586
587 return nintChanged ;
588 }
589
590 // Update dataset pointers of proxies
591 if (adjustProxies) {
592 ((RooAbsPdf*) this)->setProxyNormSet(nset) ;
593 }
594
595 RooArgSet depList;
596 getObservables(nset, depList);
597
598 if (_verboseEval>0) {
599 if (!selfNormalized()) {
600 cxcoutD(Tracing) << ClassName() << "::syncNormalization(" << GetName()
601 << ") recreating normalization integral " << endl ;
602 depList.printStream(ccoutD(Tracing),kName|kValue|kArgs,kSingleLine) ;
603 } else {
604 cxcoutD(Tracing) << ClassName() << "::syncNormalization(" << GetName() << ") selfNormalized, creating unit norm" << endl;
605 }
606 }
607
608 // Destroy old normalization & create new
609 if (selfNormalized() || !dependsOn(depList)) {
610 auto ntitle = std::string(GetTitle()) + " Unit Normalization";
611 auto nname = std::string(GetName()) + "_UnitNorm";
612 _norm = new RooRealVar(nname.c_str(),ntitle.c_str(),1) ;
613 } else {
614 const char* nr = (_normRangeOverride.Length()>0 ? _normRangeOverride.Data() : (_normRange.Length()>0 ? _normRange.Data() : 0)) ;
615
616// cout << "RooAbsPdf::syncNormalization(" << GetName() << ") rangeName for normalization is " << (nr?nr:"<null>") << endl ;
617 RooAbsReal* normInt;
618 {
619 // Normalization is always over all pdf components. Overriding the global
620 // component selection temporarily makes all RooRealIntegrals created during
621 // that time always include all components.
622 GlobalSelectComponentRAII selCompRAII(true);
623 normInt = std::unique_ptr<RooAbsReal>{createIntegral(depList,*getIntegratorConfig(),nr)}.release();
624 }
625 static_cast<RooRealIntegral*>(normInt)->setAllowComponentSelection(false);
626 normInt->getVal() ;
627// cout << "resulting normInt = " << normInt->GetName() << endl ;
628
629 const char* cacheParamsStr = getStringAttribute("CACHEPARAMINT") ;
630 if (cacheParamsStr && strlen(cacheParamsStr)) {
631
632 std::unique_ptr<RooArgSet> intParams{normInt->getVariables()} ;
633
634 RooArgSet cacheParams = RooHelpers::selectFromArgSet(*intParams, cacheParamsStr);
635
636 if (!cacheParams.empty()) {
637 cxcoutD(Caching) << "RooAbsReal::createIntObj(" << GetName() << ") INFO: constructing " << cacheParams.getSize()
638 << "-dim value cache for integral over " << depList << " as a function of " << cacheParams << " in range " << (nr?nr:"<default>") << endl ;
639 string name = Form("%s_CACHE_[%s]",normInt->GetName(),cacheParams.contentsString().c_str()) ;
640 RooCachedReal* cachedIntegral = new RooCachedReal(name.c_str(),name.c_str(),*normInt,cacheParams) ;
641 cachedIntegral->setInterpolationOrder(2) ;
642 cachedIntegral->addOwnedComponents(*normInt) ;
643 cachedIntegral->setCacheSource(true) ;
644 if (normInt->operMode()==ADirty) {
645 cachedIntegral->setOperMode(ADirty) ;
646 }
647 normInt= cachedIntegral ;
648 }
649
650 }
651 _norm = normInt ;
652 }
653
654 // Register new normalization with manager (takes ownership)
655 cache = new CacheElem(*_norm) ;
656 _normMgr.setObj(nset,cache) ;
657
658// cout << "making new object " << _norm->GetName() << endl ;
659
660 return true ;
661}
662
663
664
665////////////////////////////////////////////////////////////////////////////////
666/// Reset error counter to given value, limiting the number
667/// of future error messages for this pdf to 'resetValue'
668
670{
671 _errorCount = resetValue ;
672 _negCount = resetValue ;
673}
674
675
676
677////////////////////////////////////////////////////////////////////////////////
678/// Reset trace counter to given value, limiting the
679/// number of future trace messages for this pdf to 'value'
680
682{
683 if (!allNodes) {
685 return ;
686 } else {
687 RooArgList branchList ;
688 branchNodeServerList(&branchList) ;
689 for(auto * pdf : dynamic_range_cast<RooAbsPdf*>(branchList)) {
690 if (pdf) pdf->setTraceCounter(value,false) ;
691 }
692 }
693
694}
695
696
697
698
699////////////////////////////////////////////////////////////////////////////////
700/// Return the log of the current value with given normalization
701/// An error message is printed if the argument of the log is negative.
702
703double RooAbsPdf::getLogVal(const RooArgSet* nset) const
704{
705 return getLog(getVal(nset), this);
706}
707
708
709////////////////////////////////////////////////////////////////////////////////
710/// Check for infinity or NaN.
711/// \param[in] inputs Array to check
712/// \return True if either infinity or NaN were found.
713namespace {
714template<class T>
715bool checkInfNaNNeg(const T& inputs) {
716 // check for a math error or negative value
717 bool inf = false;
718 bool nan = false;
719 bool neg = false;
720
721 for (double val : inputs) { //CHECK_VECTORISE
722 inf |= !std::isfinite(val);
723 nan |= TMath::IsNaN(val); // Works also during fast math
724 neg |= val < 0;
725 }
726
727 return inf || nan || neg;
728}
729}
730
731
732////////////////////////////////////////////////////////////////////////////////
733/// Scan through outputs and fix+log all nans and negative values.
734/// \param[in,out] outputs Array to be scanned & fixed.
735/// \param[in] begin Begin of event range. Only needed to print the correct event number
736/// where the error occurred.
737void RooAbsPdf::logBatchComputationErrors(std::span<const double>& outputs, std::size_t begin) const {
738 for (unsigned int i=0; i<outputs.size(); ++i) {
739 const double value = outputs[i];
740 if (TMath::IsNaN(outputs[i])) {
741 logEvalError(Form("p.d.f value of (%s) is Not-a-Number (%f) for entry %zu",
742 GetName(), value, begin+i));
743 } else if (!std::isfinite(outputs[i])){
744 logEvalError(Form("p.d.f value of (%s) is (%f) for entry %zu",
745 GetName(), value, begin+i));
746 } else if (outputs[i] < 0.) {
747 logEvalError(Form("p.d.f value of (%s) is less than zero (%f) for entry %zu",
748 GetName(), value, begin+i));
749 }
750 }
751}
752
753
754void RooAbsPdf::getLogProbabilities(std::span<const double> pdfValues, double * output) const {
755 for (std::size_t i = 0; i < pdfValues.size(); ++i) {
756 output[i] = getLog(pdfValues[i], this);
757 }
758}
759
760////////////////////////////////////////////////////////////////////////////////
761/// Return the extended likelihood term (\f$ N_\mathrm{expect} - N_\mathrm{observed} \cdot \log(N_\mathrm{expect} \f$)
762/// of this PDF for the given number of observed events.
763///
764/// For successful operation, the PDF implementation must indicate that
765/// it is extendable by overloading `canBeExtended()`, and must
766/// implement the `expectedEvents()` function.
767///
768/// \param[in] observed The number of observed events.
769/// \param[in] nset The normalization set when asking the pdf for the expected
770/// number of events.
771/// \param[in] observedSumW2 The number of observed events when weighting with
772/// squared weights. If non-zero, the weight-squared error
773/// correction is applied to the extended term.
774/// \param[in] doOffset Offset the extended term by a counterterm where the
775/// expected number of events equals the observed number of events.
776/// This constant shift results in a term closer to zero that is
777/// approximately chi-square distributed. It is useful to do this
778/// also when summing multiple NLL terms to avoid numeric precision
779/// loss that happens if you sum multiple terms of different orders
780/// of magnitude.
781///
782/// The weight-squared error correction works as follows:
783/// adjust poisson such that
784/// estimate of \f$N_\mathrm{expect}\f$ stays at the same value, but has a different variance, rescale
785/// both the observed and expected count of the Poisson with a factor \f$ \sum w_{i} / \sum w_{i}^2 \f$
786/// (the effective weight of the Poisson term),
787/// i.e., change \f$\mathrm{Poisson}(N_\mathrm{observed} = \sum w_{i} | N_\mathrm{expect} )\f$
788/// to \f$ \mathrm{Poisson}(\sum w_{i} \cdot \sum w_{i} / \sum w_{i}^2 | N_\mathrm{expect} \cdot \sum w_{i} / \sum w_{i}^2 ) \f$,
789/// weighted by the effective weight \f$ \sum w_{i}^2 / \sum w_{i} \f$ in the likelihood.
790/// Since here we compute the likelihood with the weight square, we need to multiply by the
791/// square of the effective weight:
792/// - \f$ W_\mathrm{expect} = N_\mathrm{expect} \cdot \sum w_{i} / \sum w_{i}^2 \f$ : effective expected entries
793/// - \f$ W_\mathrm{observed} = \sum w_{i} \cdot \sum w_{i} / \sum w_{i}^2 \f$ : effective observed entries
794///
795/// The extended term for the likelihood weighted by the square of the weight will be then:
796///
797/// \f$ \left(\sum w_{i}^2 / \sum w_{i}\right)^2 \cdot W_\mathrm{expect} - (\sum w_{i}^2 / \sum w_{i})^2 \cdot W_\mathrm{observed} \cdot \log{W_\mathrm{expect}} \f$
798///
799/// aund this is using the previous expressions for \f$ W_\mathrm{expect} \f$ and \f$ W_\mathrm{observed} \f$:
800///
801/// \f$ \sum w_{i}^2 / \sum w_{i} \cdot N_\mathrm{expect} - \sum w_{i}^2 \cdot \log{W_\mathrm{expect}} \f$
802///
803/// Since the weights are constants in the likelihood we can use \f$\log{N_\mathrm{expect}}\f$ instead of \f$\log{W_\mathrm{expect}}\f$.
804///
805/// See also RooAbsPdf::extendedTerm(RooAbsData const& data, bool weightSquared, bool doOffset),
806/// which takes a dataset to extract \f$N_\mathrm{observed}\f$ and the
807/// normalization set.
808double RooAbsPdf::extendedTerm(double sumEntries, RooArgSet const* nset, double sumEntriesW2, bool doOffset) const
809{
810 return extendedTerm(sumEntries, expectedEvents(nset), sumEntriesW2, doOffset);
811}
812
813double RooAbsPdf::extendedTerm(double sumEntries, double expected, double sumEntriesW2, bool doOffset) const
814{
815 // check if this PDF supports extended maximum likelihood fits
816 if(!canBeExtended()) {
817 coutE(InputArguments) << GetName() << ": this PDF does not support extended maximum likelihood"
818 << std::endl;
819 return 0.0;
820 }
821
822 if(expected < 0.0) {
823 coutE(InputArguments) << GetName() << ": calculated negative expected events: " << expected
824 << std::endl;
825 logEvalError("extendedTerm #expected events is <0 return a NaN");
826 return TMath::QuietNaN();
827 }
828
829
830 // Explicitly handle case Nobs=Nexp=0
831 if (std::abs(expected)<1e-10 && std::abs(sumEntries)<1e-10) {
832 return 0.0;
833 }
834
835 // Check for errors in Nexpected
836 if (TMath::IsNaN(expected)) {
837 logEvalError("extendedTerm #expected events is a NaN") ;
838 return TMath::QuietNaN() ;
839 }
840
841 double extra = doOffset
842 ? (expected - sumEntries) - sumEntries * (std::log(expected) - std::log(sumEntries))
843 : expected - sumEntries * std::log(expected);
844
845 if(sumEntriesW2 != 0.0) {
846 extra *= sumEntriesW2 / sumEntries;
847 }
848
849 return extra;
850}
851
852////////////////////////////////////////////////////////////////////////////////
853/// Return the extended likelihood term (\f$ N_\mathrm{expect} - N_\mathrm{observed} \cdot \log(N_\mathrm{expect} \f$)
854/// of this PDF for the given number of observed events.
855///
856/// This function is a wrapper around
857/// RooAbsPdf::extendedTerm(double, RooArgSet const *, double, bool) const,
858/// where the number of observed events and observables to be used as the
859/// normalization set for the pdf is extracted from a RooAbsData.
860///
861/// For successful operation, the PDF implementation must indicate that
862/// it is extendable by overloading `canBeExtended()`, and must
863/// implement the `expectedEvents()` function.
864///
865/// \param[in] data The RooAbsData to retrieve the set of observables and
866/// number of expected events.
867/// \param[in] weightSquared If set to `true`, the extended term will be scaled by
868/// the ratio of squared event weights over event weights:
869/// \f$ \sum w_{i}^2 / \sum w_{i} \f$.
870/// Intended to be used by fits with the `SumW2Error()` option that
871/// can be passed to RooAbsPdf::fitTo()
872/// (see the documentation of said function to learn more about the
873/// interpretation of fits with squared weights).
874/// \param[in] doOffset See RooAbsPdf::extendedTerm(double, RooArgSet const*, double, bool) const.
875
876double RooAbsPdf::extendedTerm(RooAbsData const& data, bool weightSquared, bool doOffset) const {
877 double sumW = data.sumEntries();
878 double sumW2 = 0.0;
879 if (weightSquared) {
880 sumW2 = data.sumEntriesW2();
881 }
882 return extendedTerm(sumW, data.get(), sumW2, doOffset);
883}
884
885
886/** @fn RooAbsPdf::createNLL()
887 *
888 * @brief Construct representation of -log(L) of PDF with given dataset.
889 *
890 * If dataset is unbinned, an unbinned likelihood is constructed.
891 * If the dataset is binned, a binned likelihood is constructed.
892 *
893 * @param data Reference to a RooAbsData object representing the dataset.
894 * @param cmdArgs Variadic template arguments representing optional command arguments.
895 * You can pass either an arbitrary number of RooCmdArg instances
896 * or a single RooLinkedList that points to the RooCmdArg objects.
897 * @return An owning pointer to the created RooAbsReal NLL object.
898 *
899 * @tparam CmdArgs_t Template types for optional command arguments.
900 * Can either be an arbitrary number of RooCmdArg or a single RooLinkedList.
901 *
902 * \note This front-end function should not be re-implemented in derived PDF types.
903 * If you mean to customize the NLL creation routine,
904 * you need to override the virtual RooAbsPdf::createNLLImpl() method.
905 *
906 * The following named arguments are supported:
907 *
908 * <table>
909 * <tr><th> Type of CmdArg <th> Effect on NLL
910 * <tr><td> `ConditionalObservables(Args_t &&... argsOrArgSet)` <td> Do not normalize PDF over listed observables.
911 * Arguments can either be multiple RooRealVar or a single RooArgSet containing them.
912 * <tr><td> `Range(const char* name)` <td> Fit only data inside range with given name. Multiple comma-separated range names can be specified.
913 * In this case, the unnormalized PDF \f$f(x)\f$ is normalized by the integral over all ranges \f$r_i\f$:
914 * \f[
915 * p(x) = \frac{f(x)}{\sum_i \int_{r_i} f(x) dx}.
916 * \f]
917 * <tr><td> `Range(double lo, double hi)` <td> Fit only data inside given range. A range named "fit" is created on the fly on all observables.
918 * <tr><td> `SumCoefRange(const char* name)` <td> Set the range in which to interpret the coefficients of RooAddPdf components
919 * <tr><td> `NumCPU(int num, int istrat)` <td> Parallelize NLL calculation on num CPUs
920 * <table>
921 * <tr><th> Strategy <th> Effect
922 * <tr><td> 0 = RooFit::BulkPartition - *default* <td> Divide events in N equal chunks
923 * <tr><td> 1 = RooFit::Interleave <td> Process event i%N in process N. Recommended for binned data with
924 * a substantial number of zero-bins, which will be distributed across processes more equitably in this strategy
925 * <tr><td> 2 = RooFit::SimComponents <td> Process each component likelihood of a RooSimultaneous fully in a single process
926 * and distribute components over processes. This approach can be beneficial if normalization calculation time
927 * dominates the total computation time of a component (since the normalization calculation must be performed
928 * in each process in strategies 0 and 1. However beware that if the RooSimultaneous components do not share many
929 * parameters this strategy is inefficient: as most minuit-induced likelihood calculations involve changing
930 * a single parameter, only 1 of the N processes will be active most of the time if RooSimultaneous components
931 * do not share many parameters
932 * <tr><td> 3 = RooFit::Hybrid <td> Follow strategy 0 for all RooSimultaneous components, except those with less than
933 * 30 dataset entries, for which strategy 2 is followed.
934 * </table>
935 * <tr><td> `EvalBackend(std::string const&)` <td> Choose a likelihood evaluation backend:
936 * <table>
937 * <tr><th> Backend <th> Description
938 * <tr><td> **legacy** - *default* <td> The original likelihood evaluation method.
939 * Evaluates the PDF for each single data entry at a time before summing the negative log probabilities.
940 * This is the default if `EvalBackend()` is not passed.
941 * <tr><td> **cpu** <td> New vectorized evaluation mode, using faster math functions and auto-vectorisation.
942 * If all RooAbsArg objects in the model support it, likelihood computations are 2 to 10 times faster,
943 * unless your dataset is so small that the vectorization is not worth it.
944 * The relative difference of the single log-likelihoods w.r.t. the legacy mode is usually better than \f$10^{-12}\f$,
945 * and for fit parameters it's usually better than \f$10^{-6}\f$. In past ROOT releases, this backend could be activated with the now deprecated `BatchMode()` option.
946 * <tr><td> **cuda** <td> Evaluate the likelihood on a GPU that supports CUDA.
947 * This backend re-uses code from the **cpu** backend, but compiled in CUDA kernels.
948 * Hence, the results are expected to be identical, modulo some numerical differences that can arise from the different order in which the GPU is summing the log probabilities.
949 * This backend can drastically speed up the fit if all RooAbsArg object in the model support it.
950 * <tr><td> **codegen** <td> **Experimental** - Generates and compiles minimal C++ code for the NLL on-the-fly and wraps it in the returned RooAbsReal.
951 * Also generates and compiles the code for the gradient using Automatic Differentiation (AD) with [Clad](https://github.com/vgvassilev/clad).
952 * This analytic gradient is passed to the minimizer, which can result in significant speedups for many-parameter fits,
953 * even compared to the **cpu** backend. However, if one of the RooAbsArg objects in the model does not support the code generation,
954 * this backend can't be used.
955 * <tr><td> **codegen_no_grad** <td> **Experimental** - Same as **codegen**, but doesn't generate and compile the gradient code and use the regular numerical differentiation instead.
956 * This is expected to be slower, but useful for debugging problems with the analytic gradient.
957 * </table>
958 * <tr><td> `Optimize(bool flag)` <td> Activate constant term optimization (on by default)
959 * <tr><td> `SplitRange(bool flag)` <td> Use separate fit ranges in a simultaneous fit. Actual range name for each subsample is assumed to
960 * be `rangeName_indexState`, where `indexState` is the state of the master index category of the simultaneous fit.
961 * Using `Range("range"), SplitRange()` as switches, different ranges could be set like this:
962 * ```
963 * myVariable.setRange("range_pi0", 135, 210);
964 * myVariable.setRange("range_gamma", 50, 210);
965 * ```
966 * <tr><td> `Constrain(const RooArgSet&pars)` <td> For p.d.f.s that contain internal parameter constraint terms (that is usually product PDFs, where one
967 * term of the product depends on parameters but not on the observable(s),), only apply constraints to the given subset of parameters.
968 * <tr><td> `ExternalConstraints(const RooArgSet& )` <td> Include given external constraints to likelihood by multiplying them with the original likelihood.
969 * <tr><td> `GlobalObservables(const RooArgSet&)` <td> Define the set of normalization observables to be used for the constraint terms.
970 * If none are specified the constrained parameters are used.
971 * <tr><td> `GlobalObservablesSource(const char* sourceName)` <td> Which source to prioritize for global observable values.
972 * Can be either:
973 * - `data`: to take the values from the dataset,
974 * falling back to the pdf value if a given global observable is not available.
975 * If no `GlobalObservables` or `GlobalObservablesTag` command argument is given, the set
976 * of global observables will be automatically defined to be the set stored in the data.
977 * - `model`: to take all values from the pdf and completely ignore the set of global observables stored in the data
978 * (not even using it to automatically define the set of global observables
979 * if the `GlobalObservables` or `GlobalObservablesTag` command arguments are not given).
980 * The default option is `data`.
981 * <tr><td> `GlobalObservablesTag(const char* tagName)` <td> Define the set of normalization observables to be used for the constraint terms by
982 * a string attribute associated with pdf observables that match the given tagName.
983 * <tr><td> `Verbose(bool flag)` <td> Controls RooFit informational messages in likelihood construction
984 * <tr><td> `CloneData(bool flag)` <td> Use clone of dataset in NLL (default is true).
985 * \warning Deprecated option that is ignored. It is up to the implementation of the NLL creation method if the data is cloned or not.
986 * <tr><td> `Offset(std::string const& mode)` <td> Likelihood offsetting mode. Can be either:
987 * <table>
988 * <tr><th> Mode <th> Description
989 * <tr><td> **none** - *default* <td> No offsetting.
990 * <tr><td> **initial** <td> Offset likelihood by initial value (so that starting value of FCN in minuit is zero).
991 * This can improve numeric stability in simultaneous fits with components with large likelihood values.
992 * <tr><td> **bin** <td> Offset likelihood bin-by-bin with a template histogram model based on the obersved data.
993 * This results in per-bin values that are all in the same order of magnitude, which reduces precision loss in the sum,
994 * which can drastically improve numeric stability.
995 * Furthermore, \f$2\cdot \text{NLL}\f$ defined like this is approximately chi-square distributed, allowing for goodness-of-fit tests.
996 * </table>
997 * <tr><td> `IntegrateBins(double precision)` <td> In binned fits, integrate the PDF over the bins instead of using the probability density at the bin centre.
998 * This can reduce the bias observed when fitting functions with high curvature to binned data.
999 * - precision > 0: Activate bin integration everywhere. Use precision between 0.01 and 1.E-6, depending on binning.
1000 * Note that a low precision such as 0.01 might yield identical results to 1.E-4, since the integrator might reach 1.E-4 already in its first
1001 * integration step. If lower precision is desired (more speed), a RooBinSamplingPdf has to be created manually, and its integrator
1002 * has to be manipulated directly.
1003 * - precision = 0: Activate bin integration only for continuous PDFs fit to a RooDataHist.
1004 * - precision < 0: Deactivate.
1005 * \see RooBinSamplingPdf
1006 * <tr><td> `ModularL(bool flag)` <td> Enable or disable modular likelihoods, which will become the default in a future release.
1007 * This does not change any user-facing code, but only enables a different likelihood class in the back-end. Note that this
1008 * should be set to true for parallel minimization of likelihoods!
1009 * Note that it is currently not recommended to use Modular likelihoods without any parallelization enabled in the minimization, since
1010 * some features such as offsetting might not yet work in this case.
1011 * </table>
1012 */
1013
1014
1015/** @brief Protected implementation of the NLL creation routine.
1016 *
1017 * This virtual function can be overridden in case you want to change the NLL creation logic for custom PDFs.
1018 *
1019 * \note Never call this function directly. Instead, call RooAbsPdf::createNLL().
1020 */
1021
1022std::unique_ptr<RooAbsReal> RooAbsPdf::createNLLImpl(RooAbsData& data, const RooLinkedList& cmdList)
1023{
1024 auto baseName = std::string("nll_") + GetName() + "_" + data.GetName();
1025
1026 // Select the pdf-specific commands
1027 RooCmdConfig pc("RooAbsPdf::createNLL(" + std::string(GetName()) + ")");
1028
1029 pc.defineString("rangeName","RangeWithName",0,"",true) ;
1030 pc.defineString("addCoefRange","SumCoefRange",0,"") ;
1031 pc.defineString("globstag","GlobalObservablesTag",0,"") ;
1032 pc.defineString("globssource","GlobalObservablesSource",0,"data") ;
1033 pc.defineDouble("rangeLo","Range",0,-999.) ;
1034 pc.defineDouble("rangeHi","Range",1,-999.) ;
1035 pc.defineInt("splitRange","SplitRange",0,0) ;
1036 pc.defineInt("ext","Extended",0,RooFit::FitHelpers::extendedFitDefault) ;
1037 pc.defineInt("numcpu","NumCPU",0,1) ;
1038 pc.defineInt("interleave","NumCPU",1,0) ;
1039 pc.defineInt("verbose","Verbose",0,0) ;
1040 pc.defineInt("optConst","Optimize",0,0) ;
1041 pc.defineInt("cloneData","CloneData", 0, 2);
1042 pc.defineSet("projDepSet","ProjectedObservables",0,0) ;
1043 pc.defineSet("cPars","Constrain",0,0) ;
1044 pc.defineSet("glObs","GlobalObservables",0,0) ;
1045 pc.defineInt("doOffset","OffsetLikelihood",0,0) ;
1046 pc.defineSet("extCons","ExternalConstraints",0,0) ;
1047 pc.defineInt("EvalBackend", "EvalBackend", 0, static_cast<int>(RooFit::EvalBackend::defaultValue()));
1048 pc.defineDouble("IntegrateBins", "IntegrateBins", 0, -1.);
1049 pc.defineMutex("Range","RangeWithName") ;
1050 pc.defineMutex("GlobalObservables","GlobalObservablesTag") ;
1051 pc.defineInt("ModularL", "ModularL", 0, 0);
1052
1053 // New style likelihoods define parallelization through Parallelize(...) on fitTo or attributes on RooMinimizer::Config.
1054 pc.defineMutex("ModularL", "NumCPU");
1055
1056 // New style likelihoods define offsetting on minimizer, not on likelihood
1057 pc.defineMutex("ModularL", "OffsetLikelihood");
1058
1059 // Process and check varargs
1060 pc.process(cmdList) ;
1061 if (!pc.ok(true)) {
1062 return 0 ;
1063 }
1064
1065 if (pc.getInt("ModularL")) {
1066 int lut[3] = {2, 1, 0};
1068 static_cast<RooFit::TestStatistics::RooAbsL::Extended>(lut[pc.getInt("ext")])};
1069
1070 RooArgSet cParsSet;
1071 RooArgSet extConsSet;
1072 RooArgSet glObsSet;
1073
1074 if (auto tmp = pc.getSet("cPars"))
1075 cParsSet.add(*tmp);
1076
1077 if (auto tmp = pc.getSet("extCons"))
1078 extConsSet.add(*tmp);
1079
1080 if (auto tmp = pc.getSet("glObs"))
1081 glObsSet.add(*tmp);
1082
1083 const std::string rangeName = pc.getString("globstag", "", false);
1084
1086 builder.Extended(ext)
1087 .ConstrainedParameters(cParsSet)
1088 .ExternalConstraints(extConsSet)
1089 .GlobalObservables(glObsSet)
1090 .GlobalObservablesTag(rangeName.c_str());
1091
1092 return std::make_unique<RooFit::TestStatistics::RooRealL>("likelihood", "", builder.build());
1093 }
1094
1095 // Decode command line arguments
1096 const char* rangeName = pc.getString("rangeName",0,true) ;
1097 const char* addCoefRangeName = pc.getString("addCoefRange",0,true) ;
1098 const bool ext = this->interpretExtendedCmdArg(pc.getInt("ext")) ;
1099 Int_t numcpu = pc.getInt("numcpu") ;
1100 Int_t numcpu_strategy = pc.getInt("interleave");
1101 // strategy 3 works only for RooSimultaneous.
1102 if (numcpu_strategy==3 && !this->InheritsFrom("RooSimultaneous") ) {
1103 coutW(Minimization) << "Cannot use a NumCpu Strategy = 3 when the pdf is not a RooSimultaneous, "
1104 "falling back to default strategy = 0" << endl;
1105 numcpu_strategy = 0;
1106 }
1107 RooFit::MPSplit interl = (RooFit::MPSplit) numcpu_strategy;
1108
1109 Int_t splitRange = pc.getInt("splitRange") ;
1110 bool verbose = pc.getInt("verbose") ;
1111 Int_t optConst = pc.getInt("optConst") ;
1112 Int_t cloneData = pc.getInt("cloneData") ;
1113 auto offset = static_cast<RooFit::OffsetMode>(pc.getInt("doOffset"));
1114
1115 // If no explicit cloneData command is specified, cloneData is set to true if optimization is activated
1116 if (cloneData==2) {
1117 cloneData = optConst ;
1118 }
1119
1120 if (pc.hasProcessed("Range")) {
1121 double rangeLo = pc.getDouble("rangeLo") ;
1122 double rangeHi = pc.getDouble("rangeHi") ;
1123
1124 // Create range with name 'fit' with above limits on all observables
1125 RooArgSet obs;
1126 getObservables(data.get(), obs) ;
1127 for (auto arg : obs) {
1128 RooRealVar* rrv = dynamic_cast<RooRealVar*>(arg) ;
1129 if (rrv) rrv->setRange("fit",rangeLo,rangeHi) ;
1130 }
1131
1132 // Set range name to be fitted to "fit"
1133 rangeName = "fit" ;
1134 }
1135
1136 // Set the fitrange attribute of th PDF, add observables ranges for plotting
1137 resetFitrangeAttributes(*this, data, baseName, rangeName, splitRange);
1138
1139 RooArgSet projDeps ;
1140 auto tmp = pc.getSet("projDepSet");
1141 if (tmp) {
1142 projDeps.add(*tmp) ;
1143 }
1144
1145 const std::string globalObservablesSource = pc.getString("globssource","data",false);
1146 if(globalObservablesSource != "data" && globalObservablesSource != "model") {
1147 std::string errMsg = "RooAbsPdf::fitTo: GlobalObservablesSource can only be \"data\" or \"model\"!";
1148 coutE(InputArguments) << errMsg << std::endl;
1149 throw std::invalid_argument(errMsg);
1150 }
1151 const bool takeGlobalObservablesFromData = globalObservablesSource == "data";
1152
1153 // Lambda function to create the correct constraint term for a PDF. In old
1154 // RooFit, we use this PDF itself as the argument, for the new BatchMode
1155 // we're passing a clone.
1156 auto createConstr = [&](RooAbsPdf const& pdf, bool removeConstraintsFromPdf=false) -> std::unique_ptr<RooAbsReal> {
1157 return createConstraintTerm(
1158 baseName + "_constr", // name
1159 pdf, // pdf
1160 data, // data
1161 pc.getSet("cPars"), // Constrain RooCmdArg
1162 pc.getSet("extCons"), // ExternalConstraints RooCmdArg
1163 pc.getSet("glObs"), // GlobalObservables RooCmdArg
1164 pc.getString("globstag",0,true), // GlobalObservablesTag RooCmdArg
1165 takeGlobalObservablesFromData, // From GlobalObservablesSource RooCmdArg
1166 removeConstraintsFromPdf
1167 );
1168 };
1169
1170 auto evalBackend = static_cast<RooFit::EvalBackend::Value>(pc.getInt("EvalBackend"));
1171
1172 // Construct BatchModeNLL if requested
1173 if (evalBackend != RooFit::EvalBackend::Value::Legacy) {
1174
1175 // Set the normalization range. We need to do it now, because it will be
1176 // considered in `compileForNormSet`.
1177 TString oldNormRange = _normRange;
1178 setNormRange(rangeName);
1179
1180 RooArgSet normSet;
1181 getObservables(data.get(), normSet);
1182 normSet.remove(projDeps, true, true);
1183
1184 this->setAttribute("SplitRange", splitRange);
1185 this->setStringAttribute("RangeName", rangeName);
1186
1187 RooFit::Detail::CompileContext ctx{normSet};
1188 ctx.setLikelihoodMode(true);
1189 std::unique_ptr<RooAbsArg> head = this->compileForNormSet(normSet, ctx);
1190 std::unique_ptr<RooAbsPdf> pdfClone = std::unique_ptr<RooAbsPdf>{static_cast<RooAbsPdf *>(head.release())};
1191
1192 // reset attributes
1193 this->setAttribute("SplitRange", false);
1194 this->setStringAttribute("RangeName", nullptr);
1195
1196 // Reset the normalization range
1197 _normRange = oldNormRange;
1198
1199 if (addCoefRangeName) {
1200 cxcoutI(Fitting) << "RooAbsPdf::fitTo(" << GetName()
1201 << ") fixing interpretation of coefficients of any component to range "
1202 << addCoefRangeName << "\n";
1203 pdfClone->fixAddCoefRange(addCoefRangeName, false);
1204 }
1205
1206 std::unique_ptr<RooAbsReal> compiledConstr;
1207 if(std::unique_ptr<RooAbsReal> constr = createConstr(*this)) {
1208 compiledConstr = RooFit::Detail::compileForNormSet(*constr, *data.get());
1209 compiledConstr->addOwnedComponents(std::move(constr));
1210 }
1211
1213 *pdfClone,
1214 data,
1215 std::move(compiledConstr),
1216 rangeName ? rangeName : "",
1217 projDeps,
1218 ext,
1219 pc.getDouble("IntegrateBins"),
1220 offset);
1221
1222 std::unique_ptr<RooAbsReal> nllWrapper;
1223
1225 static int iFuncWrapper = 0;
1226 std::string wrapperName = "nll_func_wrapper_" + std::to_string(iFuncWrapper++);
1227 bool createGradient = evalBackend == RooFit::EvalBackend::Value::Codegen;
1228 auto simPdf = dynamic_cast<RooSimultaneous const *>(pdfClone.get());
1229 nllWrapper = std::make_unique<RooFuncWrapper>(wrapperName.c_str(), wrapperName.c_str(), *nll, normSet, &data,
1230 simPdf, createGradient);
1231 } else {
1232 auto evaluator = std::make_unique<RooFit::Evaluator>(*nll, evalBackend == RooFit::EvalBackend::Value::Cuda);
1233 nllWrapper = std::make_unique<RooEvaluatorWrapper>(*nll,
1234 std::move(evaluator), rangeName ? rangeName : "", dynamic_cast<RooSimultaneous *>(pdfClone.get()), takeGlobalObservablesFromData);
1235 nllWrapper->setData(data, false);
1236 }
1237
1238 nllWrapper->addOwnedComponents(std::move(nll));
1239 nllWrapper->addOwnedComponents(std::move(pdfClone));
1240 return nllWrapper;
1241 }
1242
1243 auto binnedLInfo = RooHelpers::getBinnedL(*this);
1244 RooAbsPdf &actualPdf = binnedLInfo.binnedPdf ? *binnedLInfo.binnedPdf : *this;
1245
1246 // Construct NLL
1248 std::unique_ptr<RooAbsReal> nll ;
1250 cfg.addCoefRangeName = addCoefRangeName ? addCoefRangeName : "";
1251 cfg.nCPU = numcpu;
1252 cfg.interleave = interl;
1253 cfg.verbose = verbose;
1254 cfg.splitCutRange = static_cast<bool>(splitRange);
1255 cfg.cloneInputData = static_cast<bool>(cloneData);
1256 cfg.integrateOverBinsPrecision = pc.getDouble("IntegrateBins");
1257 cfg.binnedL = binnedLInfo.isBinnedL;
1258 cfg.takeGlobalObservablesFromData = takeGlobalObservablesFromData;
1259 cfg.rangeName = rangeName ? rangeName : "";
1260 auto nllVar = std::make_unique<RooNLLVar>(baseName.c_str(),"-log(likelihood)",actualPdf,data,projDeps, ext, cfg);
1261 nllVar->enableBinOffsetting(offset == RooFit::OffsetMode::Bin);
1262 nll = std::move(nllVar);
1264
1265 // Include constraints, if any, in likelihood
1266 if (std::unique_ptr<RooAbsReal> constraintTerm = createConstr(*this)) {
1267
1268 // Even though it is technically only required when the computation graph
1269 // is changed because global observables are taken from data, it is safer
1270 // to clone the constraint model in general to reset the normalization
1271 // integral caches and avoid ASAN build failures (the PDF of the main
1272 // measurement is cloned too anyway, so not much overhead). This can be
1273 // reconsidered after the caching of normalization sets by pointer is changed
1274 // to a more memory-safe solution.
1275 constraintTerm = RooHelpers::cloneTreeWithSameParameters(*constraintTerm, data.get());
1276
1277 // Redirect the global observables to the ones from the dataset if applicable.
1278 constraintTerm->setData(data, false);
1279
1280 // The computation graph for the constraints is very small, no need to do
1281 // the tracking of clean and dirty nodes here.
1282 constraintTerm->setOperMode(RooAbsArg::ADirty);
1283
1284 auto orignll = std::move(nll) ;
1285 nll = std::make_unique<RooAddition>((baseName + "_with_constr").c_str(),"nllWithCons",RooArgSet(*orignll,*constraintTerm)) ;
1286 nll->addOwnedComponents(std::move(orignll),std::move(constraintTerm)) ;
1287 }
1288
1289 if (optConst) {
1290 nll->constOptimizeTestStatistic(RooAbsArg::Activate,optConst>1) ;
1291 }
1292
1294 nll->enableOffsetting(true) ;
1295 }
1296
1297 return nll;
1298}
1299
1300
1301
1302/** @fn RooAbsPdf::fitTo()
1303 *
1304 * @brief Fit PDF to given dataset.
1305 *
1306 * If dataset is unbinned, an unbinned maximum likelihood is performed.
1307 * If the dataset is binned, a binned maximum likelihood is performed.
1308 * By default the fit is executed through the MINUIT commands MIGRAD, HESSE in succession.
1309 *
1310 * @param data Reference to a RooAbsData object representing the dataset.
1311 * @param cmdArgs Variadic template arguments representing optional command arguments.
1312 * You can pass either an arbitrary number of RooCmdArg instances
1313 * or a single RooLinkedList that points to the RooCmdArg objects.
1314 * @return An owning pointer to the created RooAbsReal NLL object.
1315 * @return RooFitResult with fit status and parameters if option Save() is used, `nullptr` otherwise. The user takes ownership of the fit result.
1316 *
1317 * @tparam CmdArgs_t Template types for optional command arguments.
1318 * Can either be an arbitrary number of RooCmdArg or a single RooLinkedList.
1319 *
1320 * \note This front-end function should not be re-implemented in derived PDF types.
1321 * If you mean to customize the likelihood fitting routine,
1322 * you need to override the virtual RooAbsPdf::fitToImpl() method.
1323 *
1324 * The following named arguments are supported:
1325 *
1326 * <table>
1327 * <tr><th> Type of CmdArg <th> Options to control construction of -log(L)
1328 * <tr><td> <td> All command arguments that can also be passed to the NLL creation method.
1329 * \see RooAbsPdf::createNLL()
1330 *
1331 * <tr><th><th> Options to control flow of fit procedure
1332 * <tr><td> `Minimizer("<type>", "<algo>")` <td> Choose minimization package and optionally the algorithm to use. Default is MINUIT/MIGRAD through the RooMinimizer interface,
1333 * but others can be specified (through RooMinimizer interface).
1334 * <table>
1335 * <tr><th> Type <th> Algorithm
1336 * <tr><td> Minuit <td> migrad, simplex, minimize (=migrad+simplex), migradimproved (=migrad+improve)
1337 * <tr><td> Minuit2 <td> migrad, simplex, minimize, scan
1338 * <tr><td> GSLMultiMin <td> conjugatefr, conjugatepr, bfgs, bfgs2, steepestdescent
1339 * <tr><td> GSLSimAn <td> -
1340 * </table>
1341 *
1342 * <tr><td> `InitialHesse(bool flag)` <td> Flag controls if HESSE before MIGRAD as well, off by default
1343 * <tr><td> `Optimize(bool flag)` <td> Activate constant term optimization of test statistic during minimization (on by default)
1344 * <tr><td> `Hesse(bool flag)` <td> Flag controls if HESSE is run after MIGRAD, on by default
1345 * <tr><td> `Minos(bool flag)` <td> Flag controls if MINOS is run after HESSE, off by default
1346 * <tr><td> `Minos(const RooArgSet& set)` <td> Only run MINOS on given subset of arguments
1347 * <tr><td> `Save(bool flag)` <td> Flag controls if RooFitResult object is produced and returned, off by default
1348 * <tr><td> `Strategy(Int_t flag)` <td> Set Minuit strategy (0 to 2, default is 1)
1349 * <tr><td> `MaxCalls(int n)` <td> Change maximum number of likelihood function calls from MINUIT (if `n <= 0`, the default of 500 * #%parameters is used)
1350 * <tr><td> `EvalErrorWall(bool flag=true)` <td> When parameters are in disallowed regions (e.g. PDF is negative), return very high value to fitter
1351 * to force it out of that region. This can, however, mean that the fitter gets lost in this region. If
1352 * this happens, try switching it off.
1353 * <tr><td> `RecoverFromUndefinedRegions(double strength)` <td> When PDF is invalid (e.g. parameter in undefined region), try to direct minimiser away from that region.
1354 * `strength` controls the magnitude of the penalty term. Leaving out this argument defaults to 10. Switch off with `strength = 0.`.
1355 *
1356 * <tr><td> `SumW2Error(bool flag)` <td> Apply correction to errors and covariance matrix.
1357 * This uses two covariance matrices, one with the weights, the other with squared weights,
1358 * to obtain the correct errors for weighted likelihood fits. If this option is activated, the
1359 * corrected covariance matrix is calculated as \f$ V_\mathrm{corr} = V C^{-1} V \f$, where \f$ V \f$ is the original
1360 * covariance matrix and \f$ C \f$ is the inverse of the covariance matrix calculated using the
1361 * squared weights. This allows to switch between two interpretations of errors:
1362 * <table>
1363 * <tr><th> SumW2Error <th> Interpretation
1364 * <tr><td> true <td> The errors reflect the uncertainty of the Monte Carlo simulation.
1365 * Use this if you want to know how much accuracy you can get from the available Monte Carlo statistics.
1366 *
1367 * **Example**: Simulation with 1000 events, the average weight is 0.1.
1368 * The errors are as big as if one fitted to 1000 events.
1369 * <tr><td> false <td> The errors reflect the errors of a dataset, which is as big as the sum of weights.
1370 * Use this if you want to know what statistical errors you would get if you had a dataset with as many
1371 * events as the (weighted) Monte Carlo simulation represents.
1372 *
1373 * **Example** (Data as above):
1374 * The errors are as big as if one fitted to 100 events.
1375 * </table>
1376 * \note If the `SumW2Error` correction is enabled, the covariance matrix quality stored in the RooFitResult
1377 * object will be the minimum of the original covariance matrix quality and the quality of the covariance
1378 * matrix calculated with the squared weights.
1379 * <tr><td> `AsymptoticError()` <td> Use the asymptotically correct approach to estimate errors in the presence of weights.
1380 * This is slower but more accurate than `SumW2Error`. See also https://arxiv.org/abs/1911.01303).
1381 * <tr><td> `PrefitDataFraction(double fraction)`
1382 * <td> Runs a prefit on a small dataset of size fraction*(actual data size). This can speed up fits
1383 * by finding good starting values for the parameters for the actual fit.
1384 * \warning Prefitting may give bad results when used in binned analysis.
1385 *
1386 * <tr><th><th> Options to control informational output
1387 * <tr><td> `Verbose(bool flag)` <td> Flag controls if verbose output is printed (NLL, parameter changes during fit).
1388 * <tr><td> `Timer(bool flag)` <td> Time CPU and wall clock consumption of fit steps, off by default.
1389 * <tr><td> `PrintLevel(Int_t level)` <td> Set Minuit print level (-1 to 3, default is 1). At -1 all RooFit informational messages are suppressed as well.
1390 * See RooMinimizer::PrintLevel for the meaning of the levels.
1391 * <tr><td> `Warnings(bool flag)` <td> Enable or disable MINUIT warnings (enabled by default)
1392 * <tr><td> `PrintEvalErrors(Int_t numErr)` <td> Control number of p.d.f evaluation errors printed per likelihood evaluation.
1393 * A negative value suppresses output completely, a zero value will only print the error count per p.d.f component,
1394 * a positive value will print details of each error up to `numErr` messages per p.d.f component.
1395 * <tr><td> `Parallelize(Int_t nWorkers)` <td> Control global parallelization settings. Arguments 1 and above enable the use of RooFit's parallel minimization
1396 * backend and uses the number given as the number of workers to use in the parallelization. -1 also enables
1397 * RooFit's parallel minimization backend, and sets the number of workers to the number of available processes.
1398 * 0 disables this feature.
1399 * In case parallelization is requested, this option implies `ModularL(true)` in the internal call to the NLL creation method.
1400 * <tr><td> `ParallelGradientOptions(bool enable=true, int orderStrategy=0, int chainFactor=1)` <td> **Experimental** - Control gradient parallelization settings. The first argument
1401 * only disables or enables gradient parallelization, this is on by default.
1402 * The second argument determines the internal partial derivative calculation
1403 * ordering strategy. The third argument determines the number of partial
1404 * derivatives that are executed per task package on each worker.
1405 * <tr><td> `ParallelDescentOptions(bool enable=false, int splitStrategy=0, int numSplits=4)` <td> **Experimental** - Control settings related to the parallelization of likelihoods
1406 * outside of the gradient calculation but in the minimization, most prominently
1407 * in the linesearch step. The first argument this disables or enables likelihood
1408 * parallelization. The second argument determines whether to split the task batches
1409 * per event or per likelihood component. And the third argument how many events or
1410 * respectively components to include in each batch.
1411 * <tr><td> `TimingAnalysis(bool flag)` <td> **Experimental** - Log timings. This feature logs timings with NewStyle likelihoods on multiple processes simultaneously
1412 * and outputs the timings at the end of a run to json log files, which can be analyzed with the
1413 * `RooFit::MultiProcess::HeatmapAnalyzer`. Only works with simultaneous likelihoods.
1414 * </table>
1415 */
1416
1417
1418/** @brief Protected implementation of the likelihood fitting routine.
1419 *
1420 * This virtual function can be overridden in case you want to change the likelihood fitting logic for custom PDFs.
1421 *
1422 * \note Never call this function directly. Instead, call RooAbsPdf::fitTo().
1423 */
1424
1425std::unique_ptr<RooFitResult> RooAbsPdf::fitToImpl(RooAbsData& data, const RooLinkedList& cmdList)
1426{
1427 // Select the pdf-specific commands
1428 RooCmdConfig pc("RooAbsPdf::fitTo(" + std::string(GetName()) + ")");
1429
1430 RooLinkedList fitCmdList(cmdList) ;
1431 std::string nllCmdListString = "ProjectedObservables,Extended,Range,"
1432 "RangeWithName,SumCoefRange,NumCPU,SplitRange,Constrained,Constrain,ExternalConstraints,"
1433 "CloneData,GlobalObservables,GlobalObservablesSource,GlobalObservablesTag,"
1434 "EvalBackend,IntegrateBins,ModularL";
1435
1436 if (!cmdList.FindObject("ModularL") || static_cast<RooCmdArg*>(cmdList.FindObject("ModularL"))->getInt(0) == 0)
1437 nllCmdListString += ",OffsetLikelihood";
1438
1439 RooLinkedList nllCmdList = pc.filterCmdList(fitCmdList, nllCmdListString.c_str());
1440
1441 pc.defineDouble("prefit", "Prefit",0,0);
1443
1444 // Process and check varargs
1445 pc.process(fitCmdList) ;
1446 if (!pc.ok(true)) {
1447 return nullptr;
1448 }
1449
1450 // TimingAnalysis works only for RooSimultaneous.
1451 if (pc.getInt("timingAnalysis") && !this->InheritsFrom("RooSimultaneous") ) {
1452 coutW(Minimization) << "The timingAnalysis feature was built for minimization with RooSimultaneous "
1453 "and is not implemented for other PDF's. Please create a RooSimultaneous to "
1454 "enable this feature." << endl;
1455 }
1456
1457 // Decode command line arguments
1458 double prefit = pc.getDouble("prefit");
1459
1460 if (prefit != 0) {
1461 size_t nEvents = static_cast<size_t>(prefit*data.numEntries());
1462 if (prefit > 0.5 || nEvents < 100) {
1463 coutW(InputArguments) << "PrefitDataFraction should be in suitable range."
1464 << "With the current PrefitDataFraction=" << prefit
1465 << ", the number of events would be " << nEvents<< " out of "
1466 << data.numEntries() << ". Skipping prefit..." << endl;
1467 }
1468 else {
1469 size_t step = data.numEntries()/nEvents;
1470
1471 RooDataSet tiny("tiny", "tiny", *data.get(),
1472 data.isWeighted() ? RooFit::WeightVar() : RooCmdArg());
1473
1474 for (int i=0; i<data.numEntries(); i+=step)
1475 {
1476 const RooArgSet *event = data.get(i);
1477 tiny.add(*event, data.weight());
1478 }
1479 RooLinkedList tinyCmdList(cmdList) ;
1480 pc.filterCmdList(tinyCmdList,"Prefit,Hesse,Minos,Verbose,Save,Timer");
1481 RooCmdArg hesse_option = RooFit::Hesse(false);
1482 RooCmdArg print_option = RooFit::PrintLevel(-1);
1483
1484 tinyCmdList.Add(&hesse_option);
1485 tinyCmdList.Add(&print_option);
1486
1487 fitTo(tiny,tinyCmdList);
1488 }
1489 }
1490
1491 RooCmdArg modularL_option;
1492 if (pc.getInt("parallelize") != 0 || pc.getInt("enableParallelGradient") || pc.getInt("enableParallelDescent")) {
1493 // Set to new style likelihood if parallelization is requested
1494 modularL_option = RooFit::ModularL(true);
1495 nllCmdList.Add(&modularL_option);
1496 }
1497
1498 std::unique_ptr<RooAbsReal> nll{createNLL(data,nllCmdList)};
1499
1500 return RooFit::FitHelpers::minimize(*this, *nll, data, pc);
1501}
1502
1503
1504////////////////////////////////////////////////////////////////////////////////
1505/// Print value of p.d.f, also print normalization integral that was last used, if any
1506
1507void RooAbsPdf::printValue(ostream& os) const
1508{
1509 // silent warning messages coming when evaluating a RooAddPdf without a normalization set
1511
1512 getVal() ;
1513
1514 if (_norm) {
1515 os << getVal() << "/" << _norm->getVal() ;
1516 } else {
1517 os << getVal();
1518 }
1519}
1520
1521
1522
1523////////////////////////////////////////////////////////////////////////////////
1524/// Print multi line detailed information of this RooAbsPdf
1525
1526void RooAbsPdf::printMultiline(ostream& os, Int_t contents, bool verbose, TString indent) const
1527{
1528 RooAbsReal::printMultiline(os,contents,verbose,indent);
1529 os << indent << "--- RooAbsPdf ---" << endl;
1530 os << indent << "Cached value = " << _value << endl ;
1531 if (_norm) {
1532 os << indent << " Normalization integral: " << endl ;
1533 auto moreIndent = std::string(indent.Data()) + " " ;
1534 _norm->printStream(os,kName|kAddress|kTitle|kValue|kArgs,kSingleLine,moreIndent.c_str()) ;
1535 }
1536}
1537
1538
1539
1540////////////////////////////////////////////////////////////////////////////////
1541/// Return a binned generator context
1542
1544{
1545 return new RooBinnedGenContext(*this,vars,0,0,verbose) ;
1546}
1547
1548
1549////////////////////////////////////////////////////////////////////////////////
1550/// Interface function to create a generator context from a p.d.f. This default
1551/// implementation returns a 'standard' context that works for any p.d.f
1552
1554 const RooArgSet* auxProto, bool verbose) const
1555{
1556 return new RooGenContext(*this,vars,prototype,auxProto,verbose) ;
1557}
1558
1559
1560////////////////////////////////////////////////////////////////////////////////
1561
1562RooAbsGenContext* RooAbsPdf::autoGenContext(const RooArgSet &vars, const RooDataSet* prototype, const RooArgSet* auxProto,
1563 bool verbose, bool autoBinned, const char* binnedTag) const
1564{
1565 if (prototype || (auxProto && auxProto->getSize()>0)) {
1566 return genContext(vars,prototype,auxProto,verbose);
1567 }
1568
1569 RooAbsGenContext *context(0) ;
1570 if ( (autoBinned && isBinnedDistribution(vars)) || ( binnedTag && strlen(binnedTag) && (getAttribute(binnedTag)||string(binnedTag)=="*"))) {
1571 context = binnedGenContext(vars,verbose) ;
1572 } else {
1573 context= genContext(vars,0,0,verbose);
1574 }
1575 return context ;
1576}
1577
1578
1579
1580////////////////////////////////////////////////////////////////////////////////
1581/// Generate a new dataset containing the specified variables with events sampled from our distribution.
1582/// Generate the specified number of events or expectedEvents() if not specified.
1583/// \param[in] whatVars Choose variables in which to generate events. Variables not listed here will remain
1584/// constant and not be used for event generation.
1585/// \param[in] arg1,arg2,arg3,arg4,arg5,arg6 Optional RooCmdArg() to change behaviour of generate().
1586/// \return RooDataSet *, owned by caller.
1587///
1588/// Any variables of this PDF that are not in whatVars will use their
1589/// current values and be treated as fixed parameters. Returns zero
1590/// in case of an error.
1591///
1592/// <table>
1593/// <tr><th> Type of CmdArg <th> Effect on generate
1594/// <tr><td> `Name(const char* name)` <td> Name of the output dataset
1595/// <tr><td> `Verbose(bool flag)` <td> Print informational messages during event generation
1596/// <tr><td> `NumEvents(int nevt)` <td> Generate specified number of events
1597/// <tr><td> `Extended()` <td> If no number of events to be generated is given,
1598/// use expected number of events from extended likelihood term.
1599/// This evidently only works for extended PDFs.
1600/// <tr><td> `GenBinned(const char* tag)` <td> Use binned generation for all component pdfs that have 'setAttribute(tag)' set
1601/// <tr><td> `AutoBinned(bool flag)` <td> Automatically deploy binned generation for binned distributions (e.g. RooHistPdf, sums and products of
1602/// RooHistPdfs etc)
1603/// \note Datasets that are generated in binned mode are returned as weighted unbinned datasets. This means that
1604/// for each bin, there will be one event in the dataset with a weight corresponding to the (possibly randomised) bin content.
1605///
1606///
1607/// <tr><td> `AllBinned()` <td> As above, but for all components.
1608/// \note The notion of components is only meaningful for simultaneous PDFs
1609/// as binned generation is always executed at the top-level node for a regular
1610/// PDF, so for those it only mattes that the top-level node is tagged.
1611///
1612/// <tr><td> ProtoData(const RooDataSet& data, bool randOrder)
1613/// <td> Use specified dataset as prototype dataset. If randOrder in ProtoData() is set to true,
1614/// the order of the events in the dataset will be read in a random order if the requested
1615/// number of events to be generated does not match the number of events in the prototype dataset.
1616/// \note If ProtoData() is used, the specified existing dataset as a prototype: the new dataset will contain
1617/// the same number of events as the prototype (unless otherwise specified), and any prototype variables not in
1618/// whatVars will be copied into the new dataset for each generated event and also used to set our PDF parameters.
1619/// The user can specify a number of events to generate that will override the default. The result is a
1620/// copy of the prototype dataset with only variables in whatVars randomized. Variables in whatVars that
1621/// are not in the prototype will be added as new columns to the generated dataset.
1622///
1623/// </table>
1624///
1625/// #### Accessing the underlying event generator
1626/// Depending on the fit model (if it is difficult to sample), it may be necessary to change generator settings.
1627/// For the default generator (RooFoamGenerator), the number of samples or cells could be increased by e.g. using
1628/// myPdf->specialGeneratorConfig()->getConfigSection("RooFoamGenerator").setRealValue("nSample",1e4);
1629///
1630/// The foam generator e.g. has the following config options:
1631/// - nCell[123N]D
1632/// - nSample
1633/// - chatLevel
1634/// \see rf902_numgenconfig.C
1635
1637 const RooCmdArg& arg3,const RooCmdArg& arg4, const RooCmdArg& arg5,const RooCmdArg& arg6)
1638{
1639 // Select the pdf-specific commands
1640 RooCmdConfig pc("RooAbsPdf::generate(" + std::string(GetName()) + ")");
1641 pc.defineObject("proto","PrototypeData",0,0) ;
1642 pc.defineString("dsetName","Name",0,"") ;
1643 pc.defineInt("randProto","PrototypeData",0,0) ;
1644 pc.defineInt("resampleProto","PrototypeData",1,0) ;
1645 pc.defineInt("verbose","Verbose",0,0) ;
1646 pc.defineInt("extended","Extended",0,0) ;
1647 pc.defineInt("nEvents","NumEvents",0,0) ;
1648 pc.defineInt("autoBinned","AutoBinned",0,1) ;
1649 pc.defineInt("expectedData","ExpectedData",0,0) ;
1650 pc.defineDouble("nEventsD","NumEventsD",0,-1.) ;
1651 pc.defineString("binnedTag","GenBinned",0,"") ;
1652 pc.defineMutex("GenBinned","ProtoData") ;
1653 pc.defineMutex("Extended", "NumEvents");
1654
1655 // Process and check varargs
1656 pc.process(arg1,arg2,arg3,arg4,arg5,arg6) ;
1657 if (!pc.ok(true)) {
1658 return nullptr;
1659 }
1660
1661 // Decode command line arguments
1662 RooDataSet* protoData = static_cast<RooDataSet*>(pc.getObject("proto",0)) ;
1663 const char* dsetName = pc.getString("dsetName") ;
1664 bool verbose = pc.getInt("verbose") ;
1665 bool randProto = pc.getInt("randProto") ;
1666 bool resampleProto = pc.getInt("resampleProto") ;
1667 bool extended = pc.getInt("extended") ;
1668 bool autoBinned = pc.getInt("autoBinned") ;
1669 const char* binnedTag = pc.getString("binnedTag") ;
1670 Int_t nEventsI = pc.getInt("nEvents") ;
1671 double nEventsD = pc.getInt("nEventsD") ;
1672 //bool verbose = pc.getInt("verbose") ;
1673 bool expectedData = pc.getInt("expectedData") ;
1674
1675 double nEvents = (nEventsD>0) ? nEventsD : double(nEventsI);
1676
1677 // Force binned mode for expected data mode
1678 if (expectedData) {
1679 binnedTag="*" ;
1680 }
1681
1682 if (extended) {
1683 if (nEvents == 0) nEvents = expectedEvents(&whatVars);
1684 } else if (nEvents==0) {
1685 cxcoutI(Generation) << "No number of events specified , number of events generated is "
1686 << GetName() << "::expectedEvents() = " << expectedEvents(&whatVars)<< endl ;
1687 }
1688
1689 if (extended && protoData && !randProto) {
1690 cxcoutI(Generation) << "WARNING Using generator option Extended() (Poisson distribution of #events) together "
1691 << "with a prototype dataset implies incomplete sampling or oversampling of proto data. "
1692 << "Set randomize flag in ProtoData() option to randomize prototype dataset order and thus "
1693 << "to randomize the set of over/undersampled prototype events for each generation cycle." << endl ;
1694 }
1695
1696
1697 // Forward to appropriate implementation
1698 std::unique_ptr<RooDataSet> data;
1699 if (protoData) {
1700 data = std::unique_ptr<RooDataSet>{generate(whatVars,*protoData,Int_t(nEvents),verbose,randProto,resampleProto)};
1701 } else {
1702 data = std::unique_ptr<RooDataSet>{generate(whatVars,nEvents,verbose,autoBinned,binnedTag,expectedData, extended)};
1703 }
1704
1705 // Rename dataset to given name if supplied
1706 if (dsetName && strlen(dsetName)>0) {
1707 data->SetName(dsetName) ;
1708 }
1709
1710 return RooFit::Detail::owningPtr(std::move(data));
1711}
1712
1713
1714
1715
1716
1717
1718////////////////////////////////////////////////////////////////////////////////
1719/// \note This method does not perform any generation. To generate according to generations specification call RooAbsPdf::generate(RooAbsPdf::GenSpec&) const
1720///
1721/// Details copied from RooAbsPdf::generate():
1722/// --------------------------------------------
1723/// \copydetails RooAbsPdf::generate(const RooArgSet&,const RooCmdArg&,const RooCmdArg&,const RooCmdArg&,const RooCmdArg&,const RooCmdArg&,const RooCmdArg&)
1724
1726 const RooCmdArg& arg1,const RooCmdArg& arg2,
1727 const RooCmdArg& arg3,const RooCmdArg& arg4,
1728 const RooCmdArg& arg5,const RooCmdArg& arg6)
1729{
1730
1731 // Select the pdf-specific commands
1732 RooCmdConfig pc("RooAbsPdf::generate(" + std::string(GetName()) + ")");
1733 pc.defineObject("proto","PrototypeData",0,0) ;
1734 pc.defineString("dsetName","Name",0,"") ;
1735 pc.defineInt("randProto","PrototypeData",0,0) ;
1736 pc.defineInt("resampleProto","PrototypeData",1,0) ;
1737 pc.defineInt("verbose","Verbose",0,0) ;
1738 pc.defineInt("extended","Extended",0,0) ;
1739 pc.defineInt("nEvents","NumEvents",0,0) ;
1740 pc.defineInt("autoBinned","AutoBinned",0,1) ;
1741 pc.defineString("binnedTag","GenBinned",0,"") ;
1742 pc.defineMutex("GenBinned","ProtoData") ;
1743
1744
1745 // Process and check varargs
1746 pc.process(arg1,arg2,arg3,arg4,arg5,arg6) ;
1747 if (!pc.ok(true)) {
1748 return 0 ;
1749 }
1750
1751 // Decode command line arguments
1752 RooDataSet* protoData = static_cast<RooDataSet*>(pc.getObject("proto",0)) ;
1753 const char* dsetName = pc.getString("dsetName") ;
1754 Int_t nEvents = pc.getInt("nEvents") ;
1755 bool verbose = pc.getInt("verbose") ;
1756 bool randProto = pc.getInt("randProto") ;
1757 bool resampleProto = pc.getInt("resampleProto") ;
1758 bool extended = pc.getInt("extended") ;
1759 bool autoBinned = pc.getInt("autoBinned") ;
1760 const char* binnedTag = pc.getString("binnedTag") ;
1761
1762 RooAbsGenContext* cx = autoGenContext(whatVars,protoData,0,verbose,autoBinned,binnedTag) ;
1763
1764 return new GenSpec(cx,whatVars,protoData,nEvents,extended,randProto,resampleProto,dsetName) ;
1765}
1766
1767
1768////////////////////////////////////////////////////////////////////////////////
1769/// If many identical generation requests
1770/// are needed, e.g. in toy MC studies, it is more efficient to use the prepareMultiGen()/generate()
1771/// combination than calling the standard generate() multiple times as
1772/// initialization overhead is only incurred once.
1773
1775{
1776 //Int_t nEvt = spec._extended ? RooRandom::randomGenerator()->Poisson(spec._nGen) : spec._nGen ;
1777 //Int_t nEvt = spec._extended ? RooRandom::randomGenerator()->Poisson(spec._nGen==0?expectedEvents(spec._whatVars):spec._nGen) : spec._nGen ;
1778 //Int_t nEvt = spec._nGen == 0 ? RooRandom::randomGenerator()->Poisson(expectedEvents(spec._whatVars)) : spec._nGen;
1779
1780 double nEvt = spec._nGen == 0 ? expectedEvents(spec._whatVars) : spec._nGen;
1781
1782 std::unique_ptr<RooDataSet> ret{generate(*spec._genContext,spec._whatVars,spec._protoData, nEvt,false,spec._randProto,spec._resampleProto,
1783 spec._init,spec._extended)};
1784 spec._init = true ;
1785 return RooFit::Detail::owningPtr(std::move(ret));
1786}
1787
1788
1789
1790
1791
1792////////////////////////////////////////////////////////////////////////////////
1793/// Generate a new dataset containing the specified variables with
1794/// events sampled from our distribution.
1795///
1796/// \param[in] whatVars Generate a dataset with the variables (and categories) in this set.
1797/// Any variables of this PDF that are not in `whatVars` will use their
1798/// current values and be treated as fixed parameters.
1799/// \param[in] nEvents Generate the specified number of events or else try to use
1800/// expectedEvents() if nEvents <= 0 (default).
1801/// \param[in] verbose Show which generator strategies are being used.
1802/// \param[in] autoBinned If original distribution is binned, return bin centers and randomise weights
1803/// instead of generating single events.
1804/// \param[in] binnedTag
1805/// \param[in] expectedData Call setExpectedData on the genContext.
1806/// \param[in] extended Randomise number of events generated according to Poisson(nEvents). Only useful
1807/// if PDF is extended.
1808/// \return New dataset. Returns zero in case of an error. The caller takes ownership of the returned
1809/// dataset.
1810
1811RooFit::OwningPtr<RooDataSet> RooAbsPdf::generate(const RooArgSet &whatVars, double nEvents, bool verbose, bool autoBinned, const char* binnedTag, bool expectedData, bool extended) const
1812{
1813 if (nEvents==0 && extendMode()==CanNotBeExtended) {
1814 return RooFit::Detail::owningPtr(std::make_unique<RooDataSet>("emptyData","emptyData",whatVars));
1815 }
1816
1817 // Request for binned generation
1818 std::unique_ptr<RooAbsGenContext> context{autoGenContext(whatVars,0,0,verbose,autoBinned,binnedTag)};
1819 if (expectedData) {
1820 context->setExpectedData(true) ;
1821 }
1822
1823 std::unique_ptr<RooDataSet> generated;
1824 if(0 != context && context->isValid()) {
1825 generated = std::unique_ptr<RooDataSet>{context->generate(nEvents, false, extended)};
1826 }
1827 else {
1828 coutE(Generation) << "RooAbsPdf::generate(" << GetName() << ") cannot create a valid context" << endl;
1829 }
1830 return RooFit::Detail::owningPtr(std::move(generated));
1831}
1832
1833
1834
1835
1836////////////////////////////////////////////////////////////////////////////////
1837/// Internal method
1838
1839std::unique_ptr<RooDataSet> RooAbsPdf::generate(RooAbsGenContext& context, const RooArgSet &whatVars, const RooDataSet *prototype,
1840 double nEvents, bool /*verbose*/, bool randProtoOrder, bool resampleProto,
1841 bool skipInit, bool extended) const
1842{
1843 if (nEvents==0 && (prototype==0 || prototype->numEntries()==0)) {
1844 return std::make_unique<RooDataSet>("emptyData","emptyData",whatVars);
1845 }
1846
1847 std::unique_ptr<RooDataSet> generated;
1848
1849 // Resampling implies reshuffling in the implementation
1850 if (resampleProto) {
1851 randProtoOrder=true ;
1852 }
1853
1854 if (randProtoOrder && prototype && prototype->numEntries()!=nEvents) {
1855 coutI(Generation) << "RooAbsPdf::generate (Re)randomizing event order in prototype dataset (Nevt=" << nEvents << ")" << endl ;
1856 Int_t* newOrder = randomizeProtoOrder(prototype->numEntries(),Int_t(nEvents),resampleProto) ;
1857 context.setProtoDataOrder(newOrder) ;
1858 delete[] newOrder ;
1859 }
1860
1861 if(context.isValid()) {
1862 generated = std::unique_ptr<RooDataSet>{context.generate(nEvents,skipInit,extended)};
1863 }
1864 else {
1865 coutE(Generation) << "RooAbsPdf::generate(" << GetName() << ") do not have a valid generator context" << endl;
1866 }
1867 return generated;
1868}
1869
1870
1871
1872
1873////////////////////////////////////////////////////////////////////////////////
1874/// Generate a new dataset using a prototype dataset as a model,
1875/// with values of the variables in `whatVars` sampled from our distribution.
1876///
1877/// \param[in] whatVars Generate for these variables.
1878/// \param[in] prototype Use this dataset
1879/// as a prototype: the new dataset will contain the same number of
1880/// events as the prototype (by default), and any prototype variables not in
1881/// whatVars will be copied into the new dataset for each generated
1882/// event and also used to set our PDF parameters. The user can specify a
1883/// number of events to generate that will override the default. The result is a
1884/// copy of the prototype dataset with only variables in whatVars
1885/// randomized. Variables in whatVars that are not in the prototype
1886/// will be added as new columns to the generated dataset.
1887/// \param[in] nEvents Number of events to generate. Defaults to 0, which means number
1888/// of event in prototype dataset.
1889/// \param[in] verbose Show which generator strategies are being used.
1890/// \param[in] randProtoOrder Randomise order of retrieval of events from proto dataset.
1891/// \param[in] resampleProto Resample from the proto dataset.
1892/// \return The new dataset. Returns zero in case of an error. The caller takes ownership of the
1893/// returned dataset.
1894
1896 Int_t nEvents, bool verbose, bool randProtoOrder, bool resampleProto) const
1897{
1898 std::unique_ptr<RooAbsGenContext> context{genContext(whatVars,&prototype,0,verbose)};
1899 if (context) {
1900 return RooFit::Detail::owningPtr(generate(*context,whatVars,&prototype,nEvents,verbose,randProtoOrder,resampleProto));
1901 }
1902 coutE(Generation) << "RooAbsPdf::generate(" << GetName() << ") ERROR creating generator context" << endl ;
1903 return nullptr;
1904}
1905
1906
1907
1908////////////////////////////////////////////////////////////////////////////////
1909/// Return lookup table with randomized order for nProto prototype events.
1910
1911Int_t* RooAbsPdf::randomizeProtoOrder(Int_t nProto, Int_t, bool resampleProto) const
1912{
1913 // Make output list
1914 Int_t* lut = new Int_t[nProto] ;
1915
1916 // Randomly sample input list into output list
1917 if (!resampleProto) {
1918 // In this mode, randomization is a strict reshuffle of the order
1919 std::iota(lut, lut + nProto, 0); // fill the vector with 0 to nProto - 1
1920 // Shuffle code taken from https://en.cppreference.com/w/cpp/algorithm/random_shuffle.
1921 // The std::random_shuffle function was deprecated in C++17. We could have
1922 // used std::shuffle instead, but this is not straight-forward to use with
1923 // RooRandom::integer() and we didn't want to change the random number
1924 // generator. It might cause unwanted effects like reproducibility problems.
1925 for (int i = nProto-1; i > 0; --i) {
1926 std::swap(lut[i], lut[RooRandom::integer(i+1)]);
1927 }
1928 } else {
1929 // In this mode, we resample, i.e. events can be used more than once
1930 std::generate(lut, lut + nProto, [&]{ return RooRandom::integer(nProto); });
1931 }
1932
1933
1934 return lut ;
1935}
1936
1937
1938
1939////////////////////////////////////////////////////////////////////////////////
1940/// Load generatedVars with the subset of directVars that we can generate events for,
1941/// and return a code that specifies the generator algorithm we will use. A code of
1942/// zero indicates that we cannot generate any of the directVars (in this case, nothing
1943/// should be added to generatedVars). Any non-zero codes will be passed to our generateEvent()
1944/// implementation, but otherwise its value is arbitrary. The default implementation of
1945/// this method returns zero. Subclasses will usually implement this method using the
1946/// matchArgs() methods to advertise the algorithms they provide.
1947
1948Int_t RooAbsPdf::getGenerator(const RooArgSet &/*directVars*/, RooArgSet &/*generatedVars*/, bool /*staticInitOK*/) const
1949{
1950 return 0 ;
1951}
1952
1953
1954
1955////////////////////////////////////////////////////////////////////////////////
1956/// Interface for one-time initialization to setup the generator for the specified code.
1957
1959{
1960}
1961
1962
1963
1964////////////////////////////////////////////////////////////////////////////////
1965/// Interface for generation of an event using the algorithm
1966/// corresponding to the specified code. The meaning of each code is
1967/// defined by the getGenerator() implementation. The default
1968/// implementation does nothing.
1969
1971{
1972}
1973
1974
1975
1976////////////////////////////////////////////////////////////////////////////////
1977/// Check if given observable can be safely generated using the
1978/// pdfs internal generator mechanism (if that existsP). Observables
1979/// on which a PDF depends via more than route are not safe
1980/// for use with internal generators because they introduce
1981/// correlations not known to the internal generator
1982
1984{
1985 // Arg must be direct server of self
1986 if (!findServer(arg.GetName())) return false ;
1987
1988 // There must be no other dependency routes
1989 for (const auto server : _serverList) {
1990 if(server == &arg) continue;
1991 if(server->dependsOn(arg)) {
1992 return false ;
1993 }
1994 }
1995
1996 return true ;
1997}
1998
1999
2000////////////////////////////////////////////////////////////////////////////////
2001/// Generate a new dataset containing the specified variables with events sampled from our distribution.
2002/// \param[in] whatVars Choose variables in which to generate events. Variables not listed here will remain
2003/// constant and not be used for event generation
2004/// \param[in] arg1,arg2,arg3,arg4,arg5,arg6 Optional RooCmdArg to change behaviour of generateBinned()
2005/// \return RooDataHist *, to be managed by caller.
2006///
2007/// Generate the specified number of events or expectedEvents() if not specified.
2008///
2009/// Any variables of this PDF that are not in whatVars will use their
2010/// current values and be treated as fixed parameters. Returns zero
2011/// in case of an error. The caller takes ownership of the returned
2012/// dataset.
2013///
2014/// The following named arguments are supported
2015/// | Type of CmdArg | Effect on generation
2016/// |---------------------------|-----------------------
2017/// | `Name(const char* name)` | Name of the output dataset
2018/// | `Verbose(bool flag)` | Print informational messages during event generation
2019/// | `NumEvents(int nevt)` | Generate specified number of events
2020/// | `Extended()` | The actual number of events generated will be sampled from a Poisson distribution with mu=nevt. This can be *much* faster for peaked PDFs, but the number of events is not exactly what was requested.
2021/// | `ExpectedData()` | Return a binned dataset _without_ statistical fluctuations (also aliased as Asimov())
2022///
2023
2025 const RooCmdArg& arg3,const RooCmdArg& arg4, const RooCmdArg& arg5,const RooCmdArg& arg6) const
2026{
2027
2028 // Select the pdf-specific commands
2029 RooCmdConfig pc("RooAbsPdf::generate(" + std::string(GetName()) + ")");
2030 pc.defineString("dsetName","Name",0,"") ;
2031 pc.defineInt("verbose","Verbose",0,0) ;
2032 pc.defineInt("extended","Extended",0,0) ;
2033 pc.defineInt("nEvents","NumEvents",0,0) ;
2034 pc.defineDouble("nEventsD","NumEventsD",0,-1.) ;
2035 pc.defineInt("expectedData","ExpectedData",0,0) ;
2036
2037 // Process and check varargs
2038 pc.process(arg1,arg2,arg3,arg4,arg5,arg6) ;
2039 if (!pc.ok(true)) {
2040 return nullptr;
2041 }
2042
2043 // Decode command line arguments
2044 double nEvents = pc.getDouble("nEventsD") ;
2045 if (nEvents<0) {
2046 nEvents = pc.getInt("nEvents") ;
2047 }
2048 //bool verbose = pc.getInt("verbose") ;
2049 bool extended = pc.getInt("extended") ;
2050 bool expectedData = pc.getInt("expectedData") ;
2051 const char* dsetName = pc.getString("dsetName") ;
2052
2053 if (extended) {
2054 //nEvents = (nEvents==0?Int_t(expectedEvents(&whatVars)+0.5):nEvents) ;
2055 nEvents = (nEvents==0 ? expectedEvents(&whatVars) :nEvents) ;
2056 cxcoutI(Generation) << " Extended mode active, number of events generated (" << nEvents << ") is Poisson fluctuation on "
2057 << GetName() << "::expectedEvents() = " << nEvents << endl ;
2058 // If Poisson fluctuation results in zero events, stop here
2059 if (nEvents==0) {
2060 return 0 ;
2061 }
2062 } else if (nEvents==0) {
2063 cxcoutI(Generation) << "No number of events specified , number of events generated is "
2064 << GetName() << "::expectedEvents() = " << expectedEvents(&whatVars)<< endl ;
2065 }
2066
2067 // Forward to appropriate implementation
2068 auto data = generateBinned(whatVars,nEvents,expectedData,extended);
2069
2070 // Rename dataset to given name if supplied
2071 if (dsetName && strlen(dsetName)>0) {
2072 data->SetName(dsetName) ;
2073 }
2074
2075 return data;
2076}
2077
2078
2079
2080
2081////////////////////////////////////////////////////////////////////////////////
2082/// Generate a new dataset containing the specified variables with
2083/// events sampled from our distribution.
2084///
2085/// \param[in] whatVars Variables that values should be generated for.
2086/// \param[in] nEvents How many events to generate. If `nEvents <=0`, use the value returned by expectedEvents() as target.
2087/// \param[in] expectedData If set to true (false by default), the returned histogram returns the 'expected'
2088/// data sample, i.e. no statistical fluctuations are present.
2089/// \param[in] extended For each bin, generate Poisson(x, mu) events, where `mu` is chosen such that *on average*,
2090/// one would obtain `nEvents` events. This means that the true number of events will fluctuate around the desired value,
2091/// but the generation happens a lot faster.
2092/// Especially if the PDF is sharply peaked, the multinomial event generation necessary to generate *exactly* `nEvents` events can
2093/// be very slow.
2094///
2095/// The binning used for generation of events is the currently set binning for the variables.
2096/// It can e.g. be changed using
2097/// ```
2098/// x.setBins(15);
2099/// x.setRange(-5., 5.);
2100/// pdf.generateBinned(RooArgSet(x), 1000);
2101/// ```
2102///
2103/// Any variables of this PDF that are not in `whatVars` will use their
2104/// current values and be treated as fixed parameters.
2105/// \return RooDataHist* owned by the caller. Returns `nullptr` in case of an error.
2106RooFit::OwningPtr<RooDataHist> RooAbsPdf::generateBinned(const RooArgSet &whatVars, double nEvents, bool expectedData, bool extended) const
2107{
2108 // Create empty RooDataHist
2109 auto hist = std::make_unique<RooDataHist>("genData","genData",whatVars);
2110
2111 // Scale to number of events and introduce Poisson fluctuations
2112 if (nEvents<=0) {
2113 if (!canBeExtended()) {
2114 coutE(InputArguments) << "RooAbsPdf::generateBinned(" << GetName() << ") ERROR: No event count provided and p.d.f does not provide expected number of events" << endl ;
2115 return nullptr;
2116 } else {
2117
2118 // Don't round in expectedData or extended mode
2119 if (expectedData || extended) {
2120 nEvents = expectedEvents(&whatVars) ;
2121 } else {
2122 nEvents = std::round(expectedEvents(&whatVars));
2123 }
2124 }
2125 }
2126
2127 // Sample p.d.f. distribution
2128 fillDataHist(hist.get(),&whatVars,1,true) ;
2129
2130 vector<int> histOut(hist->numEntries()) ;
2131 double histMax(-1) ;
2132 Int_t histOutSum(0) ;
2133 for (int i=0 ; i<hist->numEntries() ; i++) {
2134 hist->get(i) ;
2135 if (expectedData) {
2136
2137 // Expected data, multiply p.d.f by nEvents
2138 double w=hist->weight()*nEvents ;
2139 hist->set(i, w, sqrt(w));
2140
2141 } else if (extended) {
2142
2143 // Extended mode, set contents to Poisson(pdf*nEvents)
2144 double w = RooRandom::randomGenerator()->Poisson(hist->weight()*nEvents) ;
2145 hist->set(w,sqrt(w)) ;
2146
2147 } else {
2148
2149 // Regular mode, fill array of weights with Poisson(pdf*nEvents), but to not fill
2150 // histogram yet.
2151 if (hist->weight()>histMax) {
2152 histMax = hist->weight() ;
2153 }
2154 histOut[i] = RooRandom::randomGenerator()->Poisson(hist->weight()*nEvents) ;
2155 histOutSum += histOut[i] ;
2156 }
2157 }
2158
2159
2160 if (!expectedData && !extended) {
2161
2162 // Second pass for regular mode - Trim/Extend dataset to exact number of entries
2163
2164 // Calculate difference between what is generated so far and what is requested
2165 Int_t nEvtExtra = std::abs(Int_t(nEvents)-histOutSum) ;
2166 Int_t wgt = (histOutSum>nEvents) ? -1 : 1 ;
2167
2168 // Perform simple binned accept/reject procedure to get to exact event count
2169 std::size_t counter = 0;
2170 bool havePrintedInfo = false;
2171 while(nEvtExtra>0) {
2172
2173 Int_t ibinRand = RooRandom::randomGenerator()->Integer(hist->numEntries()) ;
2174 hist->get(ibinRand) ;
2175 double ranY = RooRandom::randomGenerator()->Uniform(histMax) ;
2176
2177 if (ranY<hist->weight()) {
2178 if (wgt==1) {
2179 histOut[ibinRand]++ ;
2180 } else {
2181 // If weight is negative, prior bin content must be at least 1
2182 if (histOut[ibinRand]>0) {
2183 histOut[ibinRand]-- ;
2184 } else {
2185 continue ;
2186 }
2187 }
2188 nEvtExtra-- ;
2189 }
2190
2191 if ((counter++ > 10*nEvents || nEvents > 1.E7) && !havePrintedInfo) {
2192 havePrintedInfo = true;
2193 coutP(Generation) << "RooAbsPdf::generateBinned(" << GetName() << ") Performing costly accept/reject sampling. If this takes too long, use "
2194 << "extended mode to speed up the process." << std::endl;
2195 }
2196 }
2197
2198 // Transfer working array to histogram
2199 for (int i=0 ; i<hist->numEntries() ; i++) {
2200 hist->get(i) ;
2201 hist->set(histOut[i],sqrt(1.0*histOut[i])) ;
2202 }
2203
2204 } else if (expectedData) {
2205
2206 // Second pass for expectedData mode -- Normalize to exact number of requested events
2207 // Minor difference may be present in first round due to difference between
2208 // bin average and bin integral in sampling bins
2209 double corr = nEvents/hist->sumEntries() ;
2210 for (int i=0 ; i<hist->numEntries() ; i++) {
2211 hist->get(i) ;
2212 hist->set(hist->weight()*corr,sqrt(hist->weight()*corr)) ;
2213 }
2214
2215 }
2216
2217 return RooFit::Detail::owningPtr(std::move(hist));
2218}
2219
2220
2221
2222////////////////////////////////////////////////////////////////////////////////
2223/// Special generator interface for generation of 'global observables' -- for RooStats tools
2224
2226{
2227 return generate(whatVars,nEvents) ;
2228}
2229
2230namespace {
2231void removeRangeOverlap(std::vector<std::pair<double, double>>& ranges) {
2232 //Sort from left to right
2233 std::sort(ranges.begin(), ranges.end());
2234
2235 for (auto it = ranges.begin(); it != ranges.end(); ++it) {
2236 double& startL = it->first;
2237 double& endL = it->second;
2238
2239 for (auto innerIt = it+1; innerIt != ranges.end(); ++innerIt) {
2240 const double startR = innerIt->first;
2241 const double endR = innerIt->second;
2242
2243 if (startL <= startR && startR <= endL) {
2244 //Overlapping ranges, extend left one
2245 endL = std::max(endL, endR);
2246 *innerIt = make_pair(0., 0.);
2247 }
2248 }
2249 }
2250
2251 auto newEnd = std::remove_if(ranges.begin(), ranges.end(),
2252 [](const std::pair<double,double>& input){
2253 return input.first == input.second;
2254 });
2255 ranges.erase(newEnd, ranges.end());
2256}
2257}
2258
2259
2260////////////////////////////////////////////////////////////////////////////////
2261/// Plot (project) PDF on specified frame.
2262/// - If a PDF is plotted in an empty frame, it
2263/// will show a unit-normalized curve in the frame variable. When projecting a multi-
2264/// dimensional PDF onto the frame axis, hidden parameters are taken are taken at
2265/// their current value.
2266/// - If a PDF is plotted in a frame in which a dataset has already been plotted, it will
2267/// show a projection integrated over all variables that were present in the shown
2268/// dataset (except for the one on the x-axis). The normalization of the curve will
2269/// be adjusted to the event count of the plotted dataset. An informational message
2270/// will be printed for each projection step that is performed.
2271/// - If a PDF is plotted in a frame showing a dataset *after* a fit, the above happens,
2272/// but the PDF will be drawn and normalised only in the fit range. If this is not desired,
2273/// plotting and normalisation range can be overridden using Range() and NormRange() as
2274/// documented in the table below.
2275///
2276/// This function takes the following named arguments (for more arguments, see also
2277/// RooAbsReal::plotOn(RooPlot*,const RooCmdArg&,const RooCmdArg&,const RooCmdArg&,const RooCmdArg&,
2278/// const RooCmdArg&,const RooCmdArg&,const RooCmdArg&,const RooCmdArg&,const RooCmdArg&,
2279/// const RooCmdArg&) const )
2280///
2281///
2282/// <table>
2283/// <tr><th> Type of argument <th> Controlling normalisation
2284/// <tr><td> `NormRange(const char* name)` <td> Calculate curve normalization w.r.t. specified range[s].
2285/// See the tutorial rf212_plottingInRanges_blinding.C
2286/// \note Setting a Range() by default also sets a NormRange() on the same range, meaning that the
2287/// PDF is plotted and normalised in the same range. Overriding this can be useful if the PDF was fit
2288/// in limited range[s] such as side bands, `NormRange("sidebandLeft,sidebandRight")`, but the PDF
2289/// should be drawn in the full range, `Range("")`.
2290///
2291/// <tr><td> `Normalization(double scale, ScaleType code)` <td> Adjust normalization by given scale factor.
2292/// Interpretation of number depends on code:
2293/// `RooAbsReal::Relative`: relative adjustment factor
2294/// `RooAbsReal::NumEvent`: scale to match given number of events.
2295///
2296/// <tr><th> Type of argument <th> Misc control
2297/// <tr><td> `Name(const chat* name)` <td> Give curve specified name in frame. Useful if curve is to be referenced later
2298/// <tr><td> `Asymmetry(const RooCategory& c)` <td> Show the asymmetry of the PDF in given two-state category
2299/// \f$ \frac{F(+)-F(-)}{F(+)+F(-)} \f$ rather than the PDF projection. Category must have two
2300/// states with indices -1 and +1 or three states with indices -1,0 and +1.
2301/// <tr><td> `ShiftToZero(bool flag)` <td> Shift entire curve such that lowest visible point is at exactly zero.
2302/// Mostly useful when plotting -log(L) or \f$ \chi^2 \f$ distributions
2303/// <tr><td> `AddTo(const char* name, double_t wgtSelf, double_t wgtOther)` <td> Create a projection of this PDF onto the x-axis, but
2304/// instead of plotting it directly, add it to an existing curve with given name (and relative weight factors).
2305/// <tr><td> `Components(const char* names)` <td> When plotting sums of PDFs, plot only the named components (*e.g.* only
2306/// the signal of a signal+background model).
2307/// <tr><td> `Components(const RooArgSet& compSet)` <td> As above, but pass a RooArgSet of the components themselves.
2308///
2309/// <tr><th> Type of argument <th> Projection control
2310/// <tr><td> `Slice(const RooArgSet& set)` <td> Override default projection behaviour by omitting observables listed
2311/// in set from the projection, i.e. by not integrating over these.
2312/// Slicing is usually only sensible in discrete observables, by e.g. creating a slice
2313/// of the PDF at the current value of the category observable.
2314/// <tr><td> `Slice(RooCategory& cat, const char* label)` <td> Override default projection behaviour by omitting the specified category
2315/// observable from the projection, i.e., by not integrating over all states of this category.
2316/// The slice is positioned at the given label value. Multiple Slice() commands can be given to specify slices
2317/// in multiple observables, e.g.
2318/// ```{.cpp}
2319/// pdf.plotOn(frame, Slice(tagCategory, "2tag"), Slice(jetCategory, "3jet"));
2320/// ```
2321/// <tr><td> `Project(const RooArgSet& set)` <td> Override default projection behaviour by projecting
2322/// over observables given in set, completely ignoring the default projection behavior. Advanced use only.
2323/// <tr><td> `ProjWData(const RooAbsData& d)` <td> Override default projection _technique_ (integration). For observables
2324/// present in given dataset projection of PDF is achieved by constructing an average over all observable
2325/// values in given set. Consult RooFit plotting tutorial for further explanation of meaning & use of this technique
2326/// <tr><td> `ProjWData(const RooArgSet& s, const RooAbsData& d)` <td> As above but only consider subset 's' of
2327/// observables in dataset 'd' for projection through data averaging
2328/// <tr><td> `ProjectionRange(const char* rn)` <td> When projecting the PDF onto the plot axis, it is usually integrated
2329/// over the full range of the invisible variables. The ProjectionRange overrides this.
2330/// This is useful if the PDF was fitted in a limited range in y, but it is now projected onto x. If
2331/// `ProjectionRange("<name of fit range>")` is passed, the projection is normalised correctly.
2332///
2333/// <tr><th> Type of argument <th> Plotting control
2334/// <tr><td> `LineStyle(Int_t style)` <td> Select line style by ROOT line style code, default is solid
2335/// <tr><td> `LineColor(Int_t color)` <td> Select line color by ROOT color code, default is blue
2336/// <tr><td> `LineWidth(Int_t width)` <td> Select line with in pixels, default is 3
2337/// <tr><td> `FillStyle(Int_t style)` <td> Select fill style, default is not filled. If a filled style is selected,
2338/// also use VLines() to add vertical downward lines at end of curve to ensure proper closure
2339/// <tr><td> `FillColor(Int_t color)` <td> Select fill color by ROOT color code
2340/// <tr><td> `Range(const char* name)` <td> Only draw curve in range defined by given name. Multiple comma-separated ranges can be given.
2341/// An empty string "" or `nullptr` means to use the default range of the variable.
2342/// <tr><td> `Range(double lo, double hi)` <td> Only draw curve in specified range
2343/// <tr><td> `VLines()` <td> Add vertical lines to y=0 at end points of curve
2344/// <tr><td> `Precision(double eps)` <td> Control precision of drawn curve w.r.t to scale of plot, default is 1e-3. A higher precision will
2345/// result in more and more densely spaced curve points. A negative precision value will disable
2346/// adaptive point spacing and restrict sampling to the grid point of points defined by the binning
2347/// of the plotted observable (recommended for expensive functions such as profile likelihoods)
2348/// <tr><td> `Invisible(bool flag)` <td> Add curve to frame, but do not display. Useful in combination AddTo()
2349/// <tr><td> `VisualizeError(const RooFitResult& fitres, double Z=1, bool linearMethod=true)`
2350/// <td> Visualize the uncertainty on the parameters, as given in fitres, at 'Z' sigma.
2351/// The linear method is fast but may not be accurate in the presence of strong correlations (~>0.9) and at Z>2 due to linear and Gaussian approximations made.
2352/// Intervals from the sampling method can be asymmetric, and may perform better in the presence of strong correlations, but may take (much) longer to calculate
2353/// \note To include the uncertainty from the expected number of events,
2354/// the Normalization() argument with `ScaleType` `RooAbsReal::RelativeExpected` has to be passed, e.g.
2355/// ```{.cpp}
2356/// pdf.plotOn(frame, VisualizeError(fitResult), Normalization(1.0, RooAbsReal::RelativeExpected));
2357/// ```
2358///
2359/// <tr><td> `VisualizeError(const RooFitResult& fitres, const RooArgSet& param, double Z=1, bool linearMethod=true)`
2360/// <td> Visualize the uncertainty on the subset of parameters 'param', as given in fitres, at 'Z' sigma
2361/// </table>
2362
2364{
2365
2366 // Pre-processing if p.d.f. contains a fit range and there is no command specifying one,
2367 // add a fit range as default range
2368 std::unique_ptr<RooCmdArg> plotRange;
2369 std::unique_ptr<RooCmdArg> normRange2;
2370 if (getStringAttribute("fitrange") && !cmdList.FindObject("Range") &&
2371 !cmdList.FindObject("RangeWithName")) {
2372 plotRange.reset(static_cast<RooCmdArg*>(RooFit::Range(getStringAttribute("fitrange")).Clone()));
2373 cmdList.Add(plotRange.get());
2374 }
2375
2376 if (getStringAttribute("fitrange") && !cmdList.FindObject("NormRange")) {
2377 normRange2.reset(static_cast<RooCmdArg*>(RooFit::NormRange(getStringAttribute("fitrange")).Clone()));
2378 cmdList.Add(normRange2.get());
2379 }
2380
2381 if (plotRange || normRange2) {
2382 coutI(Plotting) << "RooAbsPdf::plotOn(" << GetName() << ") p.d.f was fitted in a subrange and no explicit "
2383 << (plotRange?"Range()":"") << ((plotRange&&normRange2)?" and ":"")
2384 << (normRange2?"NormRange()":"") << " was specified. Plotting / normalising in fit range. To override, do one of the following"
2385 << "\n\t- Clear the automatic fit range attribute: <pdf>.removeStringAttribute(\"fitrange\");"
2386 << "\n\t- Explicitly specify the plotting range: Range(\"<rangeName>\")."
2387 << "\n\t- Explicitly specify where to compute the normalisation: NormRange(\"<rangeName>\")."
2388 << "\n\tThe default (full) range can be denoted with Range(\"\") / NormRange(\"\")."<< endl ;
2389 }
2390
2391 // Sanity checks
2392 if (plotSanityChecks(frame)) return frame ;
2393
2394 // Select the pdf-specific commands
2395 RooCmdConfig pc("RooAbsPdf::plotOn(" + std::string(GetName()) + ")");
2396 pc.defineDouble("scaleFactor","Normalization",0,1.0) ;
2397 pc.defineInt("scaleType","Normalization",0,Relative) ;
2398 pc.defineSet("compSet","SelectCompSet",0) ;
2399 pc.defineString("compSpec","SelectCompSpec",0) ;
2400 pc.defineObject("asymCat","Asymmetry",0) ;
2401 pc.defineDouble("rangeLo","Range",0,-999.) ;
2402 pc.defineDouble("rangeHi","Range",1,-999.) ;
2403 pc.defineString("rangeName","RangeWithName",0,"") ;
2404 pc.defineString("normRangeName","NormRange",0,"") ;
2405 pc.defineInt("rangeAdjustNorm","Range",0,0) ;
2406 pc.defineInt("rangeWNAdjustNorm","RangeWithName",0,0) ;
2407 pc.defineMutex("SelectCompSet","SelectCompSpec") ;
2408 pc.defineMutex("Range","RangeWithName") ;
2409 pc.allowUndefined() ; // unknowns may be handled by RooAbsReal
2410
2411 // Process and check varargs
2412 pc.process(cmdList) ;
2413 if (!pc.ok(true)) {
2414 return frame ;
2415 }
2416
2417 // Decode command line arguments
2418 ScaleType stype = (ScaleType) pc.getInt("scaleType") ;
2419 double scaleFactor = pc.getDouble("scaleFactor") ;
2420 const RooAbsCategoryLValue* asymCat = (const RooAbsCategoryLValue*) pc.getObject("asymCat") ;
2421 const char* compSpec = pc.getString("compSpec") ;
2422 const RooArgSet* compSet = pc.getSet("compSet");
2423 bool haveCompSel = ( (compSpec && strlen(compSpec)>0) || compSet) ;
2424
2425 // Suffix for curve name
2426 std::string nameSuffix ;
2427 if (compSpec && strlen(compSpec)>0) {
2428 nameSuffix.append("_Comp[") ;
2429 nameSuffix.append(compSpec) ;
2430 nameSuffix.append("]") ;
2431 } else if (compSet) {
2432 nameSuffix += "_Comp[" + compSet->contentsString() + "]";
2433 }
2434
2435 // Remove PDF-only commands from command list
2436 RooCmdConfig::stripCmdList(cmdList,"SelectCompSet,SelectCompSpec") ;
2437
2438 // Adjust normalization, if so requested
2439 if (asymCat) {
2440 RooCmdArg cnsuffix("CurveNameSuffix",0,0,0,0,nameSuffix.c_str(),0,0,0) ;
2441 cmdList.Add(&cnsuffix);
2442 return RooAbsReal::plotOn(frame,cmdList) ;
2443 }
2444
2445 // More sanity checks
2446 double nExpected(1) ;
2447 if (stype==RelativeExpected) {
2448 if (!canBeExtended()) {
2449 coutE(Plotting) << "RooAbsPdf::plotOn(" << GetName()
2450 << "): ERROR the 'Expected' scale option can only be used on extendable PDFs" << endl ;
2451 return frame ;
2452 }
2453 frame->updateNormVars(*frame->getPlotVar()) ;
2454 nExpected = expectedEvents(frame->getNormVars()) ;
2455 }
2456
2457 if (stype != Raw) {
2458
2459 if (frame->getFitRangeNEvt() && stype==Relative) {
2460
2461 bool hasCustomRange(false), adjustNorm(false) ;
2462
2463 std::vector<pair<double,double> > rangeLim;
2464
2465 // Retrieve plot range to be able to adjust normalization to data
2466 if (pc.hasProcessed("Range")) {
2467
2468 double rangeLo = pc.getDouble("rangeLo") ;
2469 double rangeHi = pc.getDouble("rangeHi") ;
2470 rangeLim.push_back(make_pair(rangeLo,rangeHi)) ;
2471 adjustNorm = pc.getInt("rangeAdjustNorm") ;
2472 hasCustomRange = true ;
2473
2474 coutI(Plotting) << "RooAbsPdf::plotOn(" << GetName() << ") only plotting range ["
2475 << rangeLo << "," << rangeHi << "]" ;
2476 if (!pc.hasProcessed("NormRange")) {
2477 ccoutI(Plotting) << ", curve is normalized to data in " << (adjustNorm?"given":"full") << " range" << endl ;
2478 } else {
2479 ccoutI(Plotting) << endl ;
2480 }
2481
2482 nameSuffix.append(Form("_Range[%f_%f]",rangeLo,rangeHi)) ;
2483
2484 } else if (pc.hasProcessed("RangeWithName")) {
2485
2486 for (const std::string& rangeNameToken : ROOT::Split(pc.getString("rangeName", "", false), ",")) {
2487 const char* thisRangeName = rangeNameToken.empty() ? nullptr : rangeNameToken.c_str();
2488 if (thisRangeName && !frame->getPlotVar()->hasRange(thisRangeName)) {
2489 coutE(Plotting) << "Range '" << rangeNameToken << "' not defined for variable '"
2490 << frame->getPlotVar()->GetName() << "'. Ignoring ..." << std::endl;
2491 continue;
2492 }
2493 rangeLim.push_back(frame->getPlotVar()->getRange(thisRangeName));
2494 }
2495 adjustNorm = pc.getInt("rangeWNAdjustNorm") ;
2496 hasCustomRange = true ;
2497
2498 coutI(Plotting) << "RooAbsPdf::plotOn(" << GetName() << ") only plotting range '" << pc.getString("rangeName", "", false) << "'" ;
2499 if (!pc.hasProcessed("NormRange")) {
2500 ccoutI(Plotting) << ", curve is normalized to data in " << (adjustNorm?"given":"full") << " range" << endl ;
2501 } else {
2502 ccoutI(Plotting) << endl ;
2503 }
2504
2505 nameSuffix.append("_Range[" + std::string(pc.getString("rangeName")) + "]");
2506 }
2507 // Specification of a normalization range override those in a regular range
2508 if (pc.hasProcessed("NormRange")) {
2509 rangeLim.clear();
2510 for (const auto& rangeNameToken : ROOT::Split(pc.getString("normRangeName", "", false), ",")) {
2511 const char* thisRangeName = rangeNameToken.empty() ? nullptr : rangeNameToken.c_str();
2512 if (thisRangeName && !frame->getPlotVar()->hasRange(thisRangeName)) {
2513 coutE(Plotting) << "Range '" << rangeNameToken << "' not defined for variable '"
2514 << frame->getPlotVar()->GetName() << "'. Ignoring ..." << std::endl;
2515 continue;
2516 }
2517 rangeLim.push_back(frame->getPlotVar()->getRange(thisRangeName));
2518 }
2519 adjustNorm = true ;
2520 hasCustomRange = true ;
2521 coutI(Plotting) << "RooAbsPdf::plotOn(" << GetName() << ") p.d.f. curve is normalized using explicit choice of ranges '" << pc.getString("normRangeName", "", false) << "'" << endl ;
2522
2523 nameSuffix.append("_NormRange[" + std::string(pc.getString("rangeName")) + "]");
2524
2525 }
2526
2527 if (hasCustomRange && adjustNorm) {
2528 // If overlapping ranges were given, remove them now
2529 const std::size_t oldSize = rangeLim.size();
2530 removeRangeOverlap(rangeLim);
2531
2532 if (oldSize != rangeLim.size() && !pc.hasProcessed("NormRange")) {
2533 // User gave overlapping ranges. This leads to double-counting events and integrals, and must
2534 // therefore be avoided. If a NormRange has been given, the overlap is already gone.
2535 // It's safe to plot even with overlap now.
2536 coutE(Plotting) << "Requested plot/integration ranges overlap. For correct plotting, new ranges "
2537 "will be defined." << std::endl;
2538 auto plotVar = dynamic_cast<RooRealVar*>(frame->getPlotVar());
2539 assert(plotVar);
2540 std::string rangesNoOverlap;
2541 for (auto it = rangeLim.begin(); it != rangeLim.end(); ++it) {
2542 std::stringstream rangeName;
2543 rangeName << "Remove_overlap_range_" << it - rangeLim.begin();
2544 plotVar->setRange(rangeName.str().c_str(), it->first, it->second);
2545 if (!rangesNoOverlap.empty())
2546 rangesNoOverlap += ",";
2547 rangesNoOverlap += rangeName.str();
2548 }
2549
2550 auto rangeArg = static_cast<RooCmdArg*>(cmdList.FindObject("RangeWithName"));
2551 if (rangeArg)
2552 rangeArg->setString(0, rangesNoOverlap.c_str());
2553 else {
2554 plotRange = std::make_unique<RooCmdArg>(RooFit::Range(rangesNoOverlap.c_str()));
2555 cmdList.Add(plotRange.get());
2556 }
2557 }
2558
2559 double rangeNevt(0) ;
2560 for (const auto& riter : rangeLim) {
2561 double nevt= frame->getFitRangeNEvt(riter.first, riter.second);
2562 rangeNevt += nevt ;
2563 }
2564
2565 scaleFactor *= rangeNevt/nExpected ;
2566
2567 } else {
2568 scaleFactor *= frame->getFitRangeNEvt()/nExpected ;
2569 }
2570 } else if (stype==RelativeExpected) {
2571 scaleFactor *= nExpected ;
2572 } else if (stype==NumEvent) {
2573 scaleFactor /= nExpected ;
2574 }
2575 scaleFactor *= frame->getFitRangeBinW() ;
2576 }
2577 frame->updateNormVars(*frame->getPlotVar()) ;
2578
2579 // Append overriding scale factor command at end of original command list
2580 RooCmdArg tmp = RooFit::Normalization(scaleFactor,Raw) ;
2581 tmp.setInt(1,1) ; // Flag this normalization command as created for internal use (so that VisualizeError can strip it)
2582 cmdList.Add(&tmp) ;
2583
2584 // Was a component selected requested
2585 if (haveCompSel) {
2586
2587 // Get complete set of tree branch nodes
2588 RooArgSet branchNodeSet ;
2589 branchNodeServerList(&branchNodeSet) ;
2590
2591 // Discard any non-RooAbsReal nodes
2592 for (const auto arg : branchNodeSet) {
2593 if (!dynamic_cast<RooAbsReal*>(arg)) {
2594 branchNodeSet.remove(*arg) ;
2595 }
2596 }
2597
2598 // Obtain direct selection
2599 std::unique_ptr<RooArgSet> dirSelNodes;
2600 if (compSet) {
2601 dirSelNodes.reset(static_cast<RooArgSet*>(branchNodeSet.selectCommon(*compSet)));
2602 } else {
2603 dirSelNodes.reset(static_cast<RooArgSet*>(branchNodeSet.selectByName(compSpec)));
2604 }
2605 if (dirSelNodes->getSize()>0) {
2606 coutI(Plotting) << "RooAbsPdf::plotOn(" << GetName() << ") directly selected PDF components: " << *dirSelNodes << endl ;
2607
2608 // Do indirect selection and activate both
2609 plotOnCompSelect(dirSelNodes.get());
2610 } else {
2611 if (compSet) {
2612 coutE(Plotting) << "RooAbsPdf::plotOn(" << GetName() << ") ERROR: component selection set " << *compSet << " does not match any components of p.d.f." << endl ;
2613 } else {
2614 coutE(Plotting) << "RooAbsPdf::plotOn(" << GetName() << ") ERROR: component selection expression '" << compSpec << "' does not select any components of p.d.f." << endl ;
2615 }
2616 return 0 ;
2617 }
2618 }
2619
2620
2621 RooCmdArg cnsuffix("CurveNameSuffix",0,0,0,0,nameSuffix.c_str(),0,0,0) ;
2622 cmdList.Add(&cnsuffix);
2623
2624 RooPlot* ret = RooAbsReal::plotOn(frame,cmdList) ;
2625
2626 // Restore selection status ;
2627 if (haveCompSel) plotOnCompSelect(0) ;
2628
2629 return ret ;
2630}
2631
2632
2633//_____________________________________________________________________________
2634/// Plot oneself on 'frame'. In addition to features detailed in RooAbsReal::plotOn(),
2635/// the scale factor for a PDF can be interpreted in three different ways. The interpretation
2636/// is controlled by ScaleType
2637/// ```
2638/// Relative - Scale factor is applied on top of PDF normalization scale factor
2639/// NumEvent - Scale factor is interpreted as a number of events. The surface area
2640/// under the PDF curve will match that of a histogram containing the specified
2641/// number of event
2642/// Raw - Scale factor is applied to the raw (projected) probability density.
2643/// Not too useful, option provided for completeness.
2644/// ```
2645// coverity[PASS_BY_VALUE]
2647{
2648
2649 // Sanity checks
2650 if (plotSanityChecks(frame)) return frame ;
2651
2652 // More sanity checks
2653 double nExpected(1) ;
2654 if (o.stype==RelativeExpected) {
2655 if (!canBeExtended()) {
2656 coutE(Plotting) << "RooAbsPdf::plotOn(" << GetName()
2657 << "): ERROR the 'Expected' scale option can only be used on extendable PDFs" << endl ;
2658 return frame ;
2659 }
2660 frame->updateNormVars(*frame->getPlotVar()) ;
2661 nExpected = expectedEvents(frame->getNormVars()) ;
2662 }
2663
2664 // Adjust normalization, if so requested
2665 if (o.stype != Raw) {
2666
2667 if (frame->getFitRangeNEvt() && o.stype==Relative) {
2668 // If non-default plotting range is specified, adjust number of events in fit range
2669 o.scaleFactor *= frame->getFitRangeNEvt()/nExpected ;
2670 } else if (o.stype==RelativeExpected) {
2671 o.scaleFactor *= nExpected ;
2672 } else if (o.stype==NumEvent) {
2673 o.scaleFactor /= nExpected ;
2674 }
2675 o.scaleFactor *= frame->getFitRangeBinW() ;
2676 }
2677 frame->updateNormVars(*frame->getPlotVar()) ;
2678
2679 return RooAbsReal::plotOn(frame,o) ;
2680}
2681
2682
2683
2684
2685////////////////////////////////////////////////////////////////////////////////
2686/// The following named arguments are supported
2687/// <table>
2688/// <tr><th> Type of CmdArg <th> Effect on parameter box
2689/// <tr><td> `Parameters(const RooArgSet& param)` <td> Only the specified subset of parameters will be shown. By default all non-constant parameters are shown.
2690/// <tr><td> `ShowConstants(bool flag)` <td> Also display constant parameters
2691/// <tr><td> `Format(const char* what,...)` <td> Parameter formatting options.
2692/// | Parameter | Format
2693/// | ---------------------- | --------------------------
2694/// | `const char* what` | Controls what is shown. "N" adds name (alternatively, "T" adds the title), "E" adds error, "A" shows asymmetric error, "U" shows unit, "H" hides the value
2695/// | `FixedPrecision(int n)`| Controls precision, set fixed number of digits
2696/// | `AutoPrecision(int n)` | Controls precision. Number of shown digits is calculated from error + n specified additional digits (1 is sensible default)
2697/// <tr><td> `Label(const chat* label)` <td> Add label to parameter box. Use `\n` for multi-line labels.
2698/// <tr><td> `Layout(double xmin, double xmax, double ymax)` <td> Specify relative position of left/right side of box and top of box.
2699/// Coordinates are given as position on the pad between 0 and 1.
2700/// The lower end of the box is calculated automatically from the number of lines in the box.
2701/// </table>
2702///
2703///
2704/// Example use:
2705/// ```
2706/// pdf.paramOn(frame, Label("fit result"), Format("NEU",AutoPrecision(1)) ) ;
2707/// ```
2708///
2709
2710RooPlot* RooAbsPdf::paramOn(RooPlot* frame, const RooCmdArg& arg1, const RooCmdArg& arg2,
2711 const RooCmdArg& arg3, const RooCmdArg& arg4, const RooCmdArg& arg5,
2712 const RooCmdArg& arg6, const RooCmdArg& arg7, const RooCmdArg& arg8)
2713{
2714 // Stuff all arguments in a list
2715 RooLinkedList cmdList;
2716 cmdList.Add(const_cast<RooCmdArg*>(&arg1)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg2)) ;
2717 cmdList.Add(const_cast<RooCmdArg*>(&arg3)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg4)) ;
2718 cmdList.Add(const_cast<RooCmdArg*>(&arg5)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg6)) ;
2719 cmdList.Add(const_cast<RooCmdArg*>(&arg7)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg8)) ;
2720
2721 // Select the pdf-specific commands
2722 RooCmdConfig pc("RooAbsPdf::paramOn(" + std::string(GetName()) + ")");
2723 pc.defineString("label","Label",0,"") ;
2724 pc.defineDouble("xmin","Layout",0,0.65) ;
2725 pc.defineDouble("xmax","Layout",1,0.9) ;
2726 pc.defineInt("ymaxi","Layout",0,Int_t(0.9*10000)) ;
2727 pc.defineInt("showc","ShowConstants",0,0) ;
2728 pc.defineSet("params","Parameters",0,0) ;
2729 pc.defineInt("dummy","FormatArgs",0,0) ;
2730
2731 // Process and check varargs
2732 pc.process(cmdList) ;
2733 if (!pc.ok(true)) {
2734 return frame ;
2735 }
2736
2737 auto formatCmd = static_cast<RooCmdArg const*>(cmdList.FindObject("FormatArgs")) ;
2738
2739 const char* label = pc.getString("label") ;
2740 double xmin = pc.getDouble("xmin") ;
2741 double xmax = pc.getDouble("xmax") ;
2742 double ymax = pc.getInt("ymaxi") / 10000. ;
2743 int showc = pc.getInt("showc") ;
2744
2745 // Decode command line arguments
2746 std::unique_ptr<RooArgSet> params{getParameters(frame->getNormVars())} ;
2747 if(RooArgSet* requestedParams = pc.getSet("params")) {
2748 params = std::unique_ptr<RooArgSet>{static_cast<RooArgSet*>(params->selectCommon(*requestedParams))};
2749 }
2750 paramOn(frame,*params,showc,label,xmin,xmax,ymax,formatCmd);
2751
2752 return frame ;
2753}
2754
2755
2756////////////////////////////////////////////////////////////////////////////////
2757/// Add a text box with the current parameter values and their errors to the frame.
2758/// Observables of this PDF appearing in the 'data' dataset will be omitted.
2759///
2760/// An optional label will be inserted if passed. Multi-line labels can be generated
2761/// by adding `\n` to the label string. Use 'sigDigits'
2762/// to modify the default number of significant digits printed. The 'xmin,xmax,ymax'
2763/// values specify the initial relative position of the text box in the plot frame.
2764
2765RooPlot* RooAbsPdf::paramOn(RooPlot* frame, const RooArgSet& params, bool showConstants, const char *label,
2766 double xmin, double xmax ,double ymax, const RooCmdArg* formatCmd)
2767{
2768
2769 // parse the options
2770 bool showLabel= (label != 0 && strlen(label) > 0);
2771
2772 // calculate the box's size, adjusting for constant parameters
2773
2774 double ymin(ymax), dy(0.06);
2775 for (const auto param : params) {
2776 auto var = static_cast<RooRealVar*>(param);
2777 if(showConstants || !var->isConstant()) ymin-= dy;
2778 }
2779
2780 std::string labelString = label;
2781 unsigned int numLines = std::count(labelString.begin(), labelString.end(), '\n') + 1;
2782 if (showLabel) ymin -= numLines * dy;
2783
2784 // create the box and set its options
2785 TPaveText *box= new TPaveText(xmin,ymax,xmax,ymin,"BRNDC");
2786 if(!box) return 0;
2787 box->SetName((std::string(GetName()) + "_paramBox").c_str());
2788 box->SetFillColor(0);
2789 box->SetBorderSize(0);
2790 box->SetTextAlign(12);
2791 box->SetTextSize(0.04F);
2792 box->SetFillStyle(0);
2793
2794 for (const auto param : params) {
2795 auto var = static_cast<const RooRealVar*>(param);
2796 if(var->isConstant() && !showConstants) continue;
2797
2798 std::unique_ptr<TString> formatted{formatCmd ? var->format(*formatCmd) : var->format(2, "NELU")};
2799 box->AddText(formatted->Data());
2800 }
2801
2802 // add the optional label if specified
2803 if (showLabel) {
2804 for (const auto& line : ROOT::Split(label, "\n")) {
2805 box->AddText(line.c_str());
2806 }
2807 }
2808
2809 // Add box to frame
2810 frame->addObject(box) ;
2811
2812 return frame ;
2813}
2814
2815
2816
2817
2818////////////////////////////////////////////////////////////////////////////////
2819/// Return expected number of events from this p.d.f for use in extended
2820/// likelihood calculations. This default implementation returns zero
2821
2823{
2824 return 0 ;
2825}
2826
2827
2828
2829////////////////////////////////////////////////////////////////////////////////
2830/// Change global level of verbosity for p.d.f. evaluations
2831
2833{
2834 _verboseEval = stat ;
2835}
2836
2837
2838
2839////////////////////////////////////////////////////////////////////////////////
2840/// Return global level of verbosity for p.d.f. evaluations
2841
2843{
2844 return _verboseEval ;
2845}
2846
2847
2848
2849////////////////////////////////////////////////////////////////////////////////
2850/// Destructor of normalization cache element. If this element
2851/// provides the 'current' normalization stored in RooAbsPdf::_norm
2852/// zero _norm pointer here before object pointed to is deleted here
2853
2855{
2856 // Zero _norm pointer in RooAbsPdf if it is points to our cache payload
2857 if (_owner) {
2858 RooAbsPdf* pdfOwner = static_cast<RooAbsPdf*>(_owner) ;
2859 if (pdfOwner->_norm == _norm) {
2860 pdfOwner->_norm = 0 ;
2861 }
2862 }
2863
2864 delete _norm ;
2865}
2866
2867
2868
2869////////////////////////////////////////////////////////////////////////////////
2870/// Return a p.d.f that represent a projection of this p.d.f integrated over given observables
2871
2873{
2874 // Construct name for new object
2875 std::string name(GetName()) ;
2876 name.append("_Proj[") ;
2877 if (iset.getSize()>0) {
2878 bool first = true;
2879 for(auto const& arg : iset) {
2880 if (first) {
2881 first = false ;
2882 } else {
2883 name.append(",") ;
2884 }
2885 name.append(arg->GetName()) ;
2886 }
2887 }
2888 name.append("]") ;
2889
2890 // Return projected p.d.f.
2891 return new RooProjectedPdf(name.c_str(),name.c_str(),*this,iset) ;
2892}
2893
2894
2895
2896////////////////////////////////////////////////////////////////////////////////
2897/// Create a cumulative distribution function of this p.d.f in terms
2898/// of the observables listed in iset. If no nset argument is given
2899/// the c.d.f normalization is constructed over the integrated
2900/// observables, so that its maximum value is precisely 1. It is also
2901/// possible to choose a different normalization for
2902/// multi-dimensional p.d.f.s: eg. for a pdf f(x,y,z) one can
2903/// construct a partial cdf c(x,y) that only when integrated itself
2904/// over z results in a maximum value of 1. To construct such a cdf pass
2905/// z as argument to the optional nset argument
2906
2908{
2909 return createCdf(iset,RooFit::SupNormSet(nset)) ;
2910}
2911
2912
2913
2914////////////////////////////////////////////////////////////////////////////////
2915/// Create an object that represents the integral of the function over one or more observables listed in `iset`.
2916/// The actual integration calculation is only performed when the return object is evaluated. The name
2917/// of the integral object is automatically constructed from the name of the input function, the variables
2918/// it integrates and the range integrates over
2919///
2920/// The following named arguments are accepted
2921/// | Type of CmdArg | Effect on CDF
2922/// | ---------------------|-------------------
2923/// | SupNormSet(const RooArgSet&) | Observables over which should be normalized _in addition_ to the integration observables
2924/// | ScanNumCdf() | Apply scanning technique if cdf integral involves numeric integration [ default ]
2925/// | ScanAllCdf() | Always apply scanning technique
2926/// | ScanNoCdf() | Never apply scanning technique
2927/// | ScanParameters(Int_t nbins, Int_t intOrder) | Parameters for scanning technique of making CDF: number of sampled bins and order of interpolation applied on numeric cdf
2928
2930 const RooCmdArg& arg3, const RooCmdArg& arg4, const RooCmdArg& arg5,
2931 const RooCmdArg& arg6, const RooCmdArg& arg7, const RooCmdArg& arg8)
2932{
2933 // Define configuration for this method
2934 RooCmdConfig pc("RooAbsReal::createCdf(" + std::string(GetName()) + ")");
2935 pc.defineSet("supNormSet","SupNormSet",0,0) ;
2936 pc.defineInt("numScanBins","ScanParameters",0,1000) ;
2937 pc.defineInt("intOrder","ScanParameters",1,2) ;
2938 pc.defineInt("doScanNum","ScanNumCdf",0,1) ;
2939 pc.defineInt("doScanAll","ScanAllCdf",0,0) ;
2940 pc.defineInt("doScanNon","ScanNoCdf",0,0) ;
2941 pc.defineMutex("ScanNumCdf","ScanAllCdf","ScanNoCdf") ;
2942
2943 // Process & check varargs
2944 pc.process(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ;
2945 if (!pc.ok(true)) {
2946 return 0 ;
2947 }
2948
2949 // Extract values from named arguments
2950 const RooArgSet* snset = pc.getSet("supNormSet",0);
2951 RooArgSet nset ;
2952 if (snset) {
2953 nset.add(*snset) ;
2954 }
2955 Int_t numScanBins = pc.getInt("numScanBins") ;
2956 Int_t intOrder = pc.getInt("intOrder") ;
2957 Int_t doScanNum = pc.getInt("doScanNum") ;
2958 Int_t doScanAll = pc.getInt("doScanAll") ;
2959 Int_t doScanNon = pc.getInt("doScanNon") ;
2960
2961 // If scanning technique is not requested make integral-based cdf and return
2962 if (doScanNon) {
2963 return createIntRI(iset,nset) ;
2964 }
2965 if (doScanAll) {
2966 return createScanCdf(iset,nset,numScanBins,intOrder) ;
2967 }
2968 if (doScanNum) {
2969 std::unique_ptr<RooAbsReal> tmp{createIntegral(iset)} ;
2970 Int_t isNum= !static_cast<RooRealIntegral&>(*tmp).numIntRealVars().empty();
2971
2972 if (isNum) {
2973 coutI(NumIntegration) << "RooAbsPdf::createCdf(" << GetName() << ") integration over observable(s) " << iset << " involves numeric integration," << endl
2974 << " constructing cdf though numeric integration of sampled pdf in " << numScanBins << " bins and applying order "
2975 << intOrder << " interpolation on integrated histogram." << endl
2976 << " To override this choice of technique use argument ScanNone(), to change scan parameters use ScanParameters(nbins,order) argument" << endl ;
2977 }
2978
2979 return isNum ? createScanCdf(iset,nset,numScanBins,intOrder) : createIntRI(iset,nset) ;
2980 }
2981 return 0 ;
2982}
2983
2985{
2986 string name = string(GetName()) + "_NUMCDF_" + integralNameSuffix(iset,&nset).Data() ;
2987 RooRealVar* ivar = (RooRealVar*) iset.first() ;
2988 ivar->setBins(numScanBins,"numcdf") ;
2989 auto ret = std::make_unique<RooNumCdf>(name.c_str(),name.c_str(),*this,*ivar,"numcdf");
2990 ret->setInterpolationOrder(intOrder) ;
2991 return RooFit::Detail::owningPtr(std::move(ret));
2992}
2993
2994
2995
2996
2997////////////////////////////////////////////////////////////////////////////////
2998/// This helper function finds and collects all constraints terms of all component p.d.f.s
2999/// and returns a RooArgSet with all those terms.
3000
3001RooArgSet* RooAbsPdf::getAllConstraints(const RooArgSet& observables, RooArgSet& constrainedParams,
3002 bool stripDisconnected, bool removeConstraintsFromPdf) const
3003{
3004 RooArgSet* ret = new RooArgSet("AllConstraints") ;
3005
3006 std::unique_ptr<RooArgSet> comps(getComponents());
3007 for (const auto arg : *comps) {
3008 auto pdf = dynamic_cast<const RooAbsPdf*>(arg) ;
3009 if (pdf && !ret->find(pdf->GetName())) {
3010 std::unique_ptr<RooArgSet> compRet(
3011 pdf->getConstraints(observables,constrainedParams,stripDisconnected,removeConstraintsFromPdf));
3012 if (compRet) {
3013 ret->add(*compRet,false) ;
3014 }
3015 }
3016 }
3017
3018 return ret ;
3019}
3020
3021
3022////////////////////////////////////////////////////////////////////////////////
3023/// Returns the default numeric MC generator configuration for all RooAbsReals
3024
3026{
3028}
3029
3030
3031////////////////////////////////////////////////////////////////////////////////
3032/// Returns the specialized integrator configuration for _this_ RooAbsReal.
3033/// If this object has no specialized configuration, a null pointer is returned
3034
3036{
3037 return _specGeneratorConfig.get();
3038}
3039
3040
3041
3042////////////////////////////////////////////////////////////////////////////////
3043/// Returns the specialized integrator configuration for _this_ RooAbsReal.
3044/// If this object has no specialized configuration, a null pointer is returned,
3045/// unless createOnTheFly is true in which case a clone of the default integrator
3046/// configuration is created, installed as specialized configuration, and returned
3047
3049{
3050 if (!_specGeneratorConfig && createOnTheFly) {
3051 _specGeneratorConfig = std::make_unique<RooNumGenConfig>(*defaultGeneratorConfig()) ;
3052 }
3053 return _specGeneratorConfig.get();
3054}
3055
3056
3057
3058////////////////////////////////////////////////////////////////////////////////
3059/// Return the numeric MC generator configuration used for this object. If
3060/// a specialized configuration was associated with this object, that configuration
3061/// is returned, otherwise the default configuration for all RooAbsReals is returned
3062
3064{
3065 const RooNumGenConfig* config = specialGeneratorConfig() ;
3066 if (config) return config ;
3067 return defaultGeneratorConfig() ;
3068}
3069
3070
3071
3072////////////////////////////////////////////////////////////////////////////////
3073/// Set the given configuration as default numeric MC generator
3074/// configuration for this object
3075
3077{
3078 _specGeneratorConfig = std::make_unique<RooNumGenConfig>(config);
3079}
3080
3081
3082
3083////////////////////////////////////////////////////////////////////////////////
3084/// Remove the specialized numeric MC generator configuration associated
3085/// with this object
3086
3088{
3089 _specGeneratorConfig.reset();
3090}
3091
3092
3093
3094////////////////////////////////////////////////////////////////////////////////
3095
3097{
3098 delete _genContext ;
3099}
3100
3101
3102////////////////////////////////////////////////////////////////////////////////
3103
3104RooAbsPdf::GenSpec::GenSpec(RooAbsGenContext* context, const RooArgSet& whatVars, RooDataSet* protoData, Int_t nGen,
3105 bool extended, bool randProto, bool resampleProto, TString dsetName, bool init) :
3106 _genContext(context), _whatVars(whatVars), _protoData(protoData), _nGen(nGen), _extended(extended),
3107 _randProto(randProto), _resampleProto(resampleProto), _dsetName(dsetName), _init(init)
3108{
3109}
3110
3111
3112namespace {
3113
3114void sterilizeClientCaches(RooAbsArg & arg) {
3115 auto const& clients = arg.clients();
3116 for(std::size_t iClient = 0; iClient < clients.size(); ++iClient) {
3117
3118 const std::size_t oldClientsSize = clients.size();
3119 RooAbsArg* client = clients[iClient];
3120
3121 for(int iCache = 0; iCache < client->numCaches(); ++iCache) {
3122 if(auto cacheMgr = dynamic_cast<RooObjCacheManager*>(client->getCache(iCache))) {
3123 cacheMgr->sterilize();
3124 }
3125 }
3126
3127 // It can happen that the objects cached by the client are also clients of
3128 // the arg itself! In that case, the position of the client in the client
3129 // list might have changed, and we need to find the new index.
3130 if(clients.size() != oldClientsSize) {
3131 auto clientIter = std::find(clients.begin(), clients.end(), client);
3132 if(clientIter == clients.end()) {
3133 throw std::runtime_error("After a clients caches were cleared, the client was gone! This should not happen.");
3134 }
3135 iClient = std::distance(clients.begin(), clientIter);
3136 }
3137 }
3138}
3139
3140} // namespace
3141
3142
3143////////////////////////////////////////////////////////////////////////////////
3144
3145void RooAbsPdf::setNormRange(const char* rangeName)
3146{
3147 if (rangeName) {
3148 _normRange = rangeName ;
3149 } else {
3150 _normRange.Clear() ;
3151 }
3152
3153 // the stuff that the clients have cached may depend on the normalization range
3154 sterilizeClientCaches(*this);
3155
3156 if (_norm) {
3158 _norm = 0 ;
3159 }
3160}
3161
3162
3163////////////////////////////////////////////////////////////////////////////////
3164
3165void RooAbsPdf::setNormRangeOverride(const char* rangeName)
3166{
3167 if (rangeName) {
3168 _normRangeOverride = rangeName ;
3169 } else {
3171 }
3172
3173 // the stuff that the clients have cached may depend on the normalization range
3174 sterilizeClientCaches(*this);
3175
3176 if (_norm) {
3178 _norm = 0 ;
3179 }
3180}
3181
3182
3183////////////////////////////////////////////////////////////////////////////////
3184/// Hook function intercepting redirectServer calls. Discard current
3185/// normalization object if any server is redirected
3186
3187bool RooAbsPdf::redirectServersHook(const RooAbsCollection & newServerList, bool mustReplaceAll,
3188 bool nameChange, bool isRecursiveStep)
3189{
3190 // If servers are redirected, the cached normalization integrals and
3191 // normalization sets are most likely invalid.
3193
3194 // Object is own by _normCacheManager that will delete object as soon as cache
3195 // is sterilized by server redirect
3196 _norm = nullptr ;
3197
3198 // Similar to the situation with the normalization integral above: if a
3199 // server is redirected, the cached normalization set might not point to
3200 // the right observables anymore. We need to reset it.
3201 setActiveNormSet(nullptr);
3202 return RooAbsReal::redirectServersHook(newServerList, mustReplaceAll, nameChange, isRecursiveStep);
3203}
3204
3205
3206std::unique_ptr<RooAbsArg>
3208{
3209 if (normSet.empty() || selfNormalized()) {
3210 return RooAbsReal::compileForNormSet(normSet, ctx);
3211 }
3212 std::unique_ptr<RooAbsPdf> pdfClone(static_cast<RooAbsPdf *>(this->Clone()));
3213 ctx.compileServers(*pdfClone, normSet);
3214
3215 auto newArg = std::make_unique<RooNormalizedPdf>(*pdfClone, normSet);
3216
3217 // The direct servers are this pdf and the normalization integral, which
3218 // don't need to be compiled further.
3219 for (RooAbsArg *server : newArg->servers()) {
3220 ctx.markAsCompiled(*server);
3221 }
3222 ctx.markAsCompiled(*newArg);
3223 newArg->addOwnedComponents(std::move(pdfClone));
3224 return newArg;
3225}
3226
3227/// Returns an object that represents the expected number of events for a given
3228/// normalization set, similar to how createIntegral() returns an object that
3229/// returns the integral. This is used to build the computation graph for the
3230/// final likelihood.
3231std::unique_ptr<RooAbsReal> RooAbsPdf::createExpectedEventsFunc(const RooArgSet * /*nset*/) const
3232{
3233 std::stringstream errMsg;
3234 errMsg << "The pdf \"" << GetName() << "\" of type " << ClassName()
3235 << " did not overload RooAbsPdf::createExpectedEventsFunc()!";
3236 coutE(InputArguments) << errMsg.str() << std::endl;
3237 return nullptr;
3238}
std::unique_ptr< RooAbsReal > createConstraintTerm(std::string const &name, RooAbsPdf const &pdf, RooAbsData const &data, RooArgSet const *constrainedParameters, RooArgSet const *externalConstraints, RooArgSet const *globalObservables, const char *globalObservablesTag, bool takeGlobalObservablesFromData, bool removeConstraintsFromPdf)
Create the parameter constraint sum to add to the negative log-likelihood.
#define e(i)
Definition RSha256.hxx:103
#define coutI(a)
#define cxcoutI(a)
#define cxcoutD(a)
#define coutP(a)
#define oocoutW(o, a)
#define coutW(a)
#define coutE(a)
#define ccoutI(a)
#define ccoutD(a)
int Int_t
Definition RtypesCore.h:45
#define ClassImp(name)
Definition Rtypes.h:377
static void indent(ostringstream &buf, int indent_level)
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 input
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:110
float xmin
float ymin
float xmax
float ymax
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2468
RooAbsArg is the common abstract base class for objects that represent a value and a "shape" in RooFi...
Definition RooAbsArg.h:80
void clearValueAndShapeDirty() const
Definition RooAbsArg.h:600
void Print(Option_t *options=nullptr) const override
Print the object to the defaultPrintStream().
Definition RooAbsArg.h:323
bool dependsOn(const RooAbsCollection &serverList, const RooAbsArg *ignoreArg=nullptr, bool valueOnly=false) const
Test whether we depend on (ie, are served by) any object in the specified collection.
void setOperMode(OperMode mode, bool recurseADirty=true)
Set the operation mode of this node.
void setStringAttribute(const Text_t *key, const Text_t *value)
Associate string 'value' to this object under key 'key'.
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.
bool addOwnedComponents(const RooAbsCollection &comps)
Take ownership of the contents of 'comps'.
const Text_t * getStringAttribute(const Text_t *key) const
Get string attribute mapped under key 'key'.
virtual std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const
RooFit::OwningPtr< RooArgSet > getComponents() const
Create a RooArgSet with all components (branch nodes) of the expression tree headed by this object.
void removeStringAttribute(const Text_t *key)
Delete a string attribute with a given key.
bool getAttribute(const Text_t *name) const
Check if a named attribute is set. By default, all attributes are unset.
RooFit::OwningPtr< RooArgSet > getVariables(bool stripDisconnected=true) const
Return RooArgSet with all variables (tree leaf nodes of expression tree)
RooAbsCache * getCache(Int_t index) const
Return registered cache object by index.
const RefCountList_t & clients() const
List of all clients of this object.
Definition RooAbsArg.h:195
bool isValueDirty() const
Definition RooAbsArg.h:422
void setAttribute(const Text_t *name, bool value=true)
Set (default) or clear a named boolean attribute of this object.
void setProxyNormSet(const RooArgSet *nset)
Forward a change in the cached normalization argset to all the registered proxies.
void branchNodeServerList(RooAbsCollection *list, const RooAbsArg *arg=nullptr, bool recurseNonDerived=false) const
Fill supplied list with all branch nodes of the arg tree starting with ourself as top node.
TObject * Clone(const char *newname=nullptr) const override
Make a clone of an object using the Streamer facility.
Definition RooAbsArg.h:92
RefCountList_t _serverList
Definition RooAbsArg.h:635
Int_t numCaches() const
Return number of registered caches.
RooAbsArg * findServer(const char *name) const
Return server of this with name name. Returns nullptr if not found.
Definition RooAbsArg.h:213
OperMode operMode() const
Query the operation mode of this node.
Definition RooAbsArg.h:485
RooAbsArg * _owner
! Pointer to owning RooAbsArg
void setInterpolationOrder(Int_t order)
Set interpolation order of RooHistFunct representing cache histogram.
RooAbsCategoryLValue is the common abstract base class for objects that represent a discrete value th...
RooAbsCollection is an abstract container object that can hold multiple RooAbsArg objects.
virtual bool remove(const RooAbsArg &var, bool silent=false, bool matchByNameOnly=false)
Remove the specified argument from our list.
Int_t getSize() const
Return the number of elements in the collection.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
RooAbsArg * first() const
RooAbsCollection * selectByName(const char *nameList, bool verbose=false) const
Create a subset of the current collection, consisting only of those elements with names matching the ...
bool selectCommon(const RooAbsCollection &refColl, RooAbsCollection &outColl) const
Create a subset of the current collection, consisting only of those elements that are contained as we...
std::string contentsString() const
Return comma separated list of contained object names as STL string.
RooAbsArg * find(const char *name) const
Find object with given name in list.
void Print(Option_t *options=nullptr) const override
This method must be overridden when a class wants to print itself.
RooAbsData is the common abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:57
virtual Int_t numEntries() const
Return number of entries in dataset, i.e., count unweighted entries.
RooAbsGenContext is the abstract base class for generator contexts of RooAbsPdf objects.
virtual void setExpectedData(bool)
virtual RooDataSet * generate(double nEvents=0, bool skipInit=false, bool extendedMode=false)
Generate the specified number of events with nEvents>0 and and return a dataset containing the genera...
bool isValid() const
virtual void setProtoDataOrder(Int_t *lut)
Set the traversal order of prototype data to that in the lookup tables passed as argument.
Normalization set with for above integral.
Definition RooAbsPdf.h:322
~CacheElem() override
Destructor of normalization cache element.
RooAbsReal * _norm
Definition RooAbsPdf.h:327
RooArgSet _whatVars
Definition RooAbsPdf.h:83
RooAbsGenContext * _genContext
Definition RooAbsPdf.h:82
RooDataSet * _protoData
Definition RooAbsPdf.h:84
virtual bool syncNormalization(const RooArgSet *dset, bool adjustProxies=true) const
Verify that the normalization integral cached with this PDF is valid for given set of normalization o...
double getNorm(const RooArgSet &nset) const
Get normalisation term needed to normalise the raw values returned by getVal().
Definition RooAbsPdf.h:195
std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const override
RooObjCacheManager _normMgr
Definition RooAbsPdf.h:329
std::unique_ptr< RooNumGenConfig > _specGeneratorConfig
! MC generator configuration specific for this object
Definition RooAbsPdf.h:341
bool interpretExtendedCmdArg(int extendedCmdArg) const
RooFit::OwningPtr< RooAbsReal > createNLL(RooAbsData &data, CmdArgs_t const &... cmdArgs)
Construct representation of -log(L) of PDF with given dataset.
Definition RooAbsPdf.h:162
double getValV(const RooArgSet *set=nullptr) const override
Return current value, normalized by integrating over the observables in nset.
virtual std::unique_ptr< RooFitResult > fitToImpl(RooAbsData &data, const RooLinkedList &cmdList)
Protected implementation of the likelihood fitting routine.
bool _selectComp
Component selection flag for RooAbsPdf::plotCompOn.
Definition RooAbsPdf.h:339
virtual void generateEvent(Int_t code)
Interface for generation of an event using the algorithm corresponding to the specified code.
RooFit::OwningPtr< RooAbsReal > createScanCdf(const RooArgSet &iset, const RooArgSet &nset, Int_t numScanBins, Int_t intOrder)
void setGeneratorConfig()
Remove the specialized numeric MC generator configuration associated with this object.
virtual void resetErrorCounters(Int_t resetValue=10)
Reset error counter to given value, limiting the number of future error messages for this pdf to 'res...
static int verboseEval()
Return global level of verbosity for p.d.f. evaluations.
RooFit::OwningPtr< RooAbsReal > createCdf(const RooArgSet &iset, const RooArgSet &nset=RooArgSet())
Create a cumulative distribution function of this p.d.f in terms of the observables listed in iset.
bool isActiveNormSet(RooArgSet const *normSet) const
Checks if normSet is the currently active normalization set of this PDF, meaning is exactly the same ...
Definition RooAbsPdf.h:299
virtual double expectedEvents(const RooArgSet *nset) const
Return expected number of events to be used in calculation of extended likelihood.
virtual RooAbsGenContext * binnedGenContext(const RooArgSet &vars, bool verbose=false) const
Return a binned generator context.
TString _normRange
Normalization range.
Definition RooAbsPdf.h:343
virtual bool isDirectGenSafe(const RooAbsArg &arg) const
Check if given observable can be safely generated using the pdfs internal generator mechanism (if tha...
Int_t * randomizeProtoOrder(Int_t nProto, Int_t nGen, bool resample=false) const
Return lookup table with randomized order for nProto prototype events.
void setNormRange(const char *rangeName)
~RooAbsPdf() override
Destructor.
RooArgSet const * _normSet
Normalization integral (owned by _normMgr)
Definition RooAbsPdf.h:320
RooPlot * plotOn(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 RooCmdArg &arg9={}, const RooCmdArg &arg10={}) const override
Helper calling plotOn(RooPlot*, RooLinkedList&) const.
Definition RooAbsPdf.h:123
RooNumGenConfig * specialGeneratorConfig() const
Returns the specialized integrator configuration for this RooAbsReal.
virtual bool selfNormalized() const
Shows if a PDF is self-normalized, which means that no attempt is made to add a normalization term.
Definition RooAbsPdf.h:207
void printMultiline(std::ostream &os, Int_t contents, bool verbose=false, TString indent="") const override
Print multi line detailed information of this RooAbsPdf.
Int_t _traceCount
Number of traces remaining to print.
Definition RooAbsPdf.h:336
bool canBeExtended() const
If true, PDF can provide extended likelihood term.
Definition RooAbsPdf.h:218
RooAbsReal * _norm
Definition RooAbsPdf.h:319
void setTraceCounter(Int_t value, bool allNodes=false)
Reset trace counter to given value, limiting the number of future trace messages for this pdf to 'val...
GenSpec * prepareMultiGen(const RooArgSet &whatVars, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={})
Prepare GenSpec configuration object for efficient generation of multiple datasets from identical spe...
Int_t _errorCount
Number of errors remaining to print.
Definition RooAbsPdf.h:335
@ CanBeExtended
Definition RooAbsPdf.h:212
@ MustBeExtended
Definition RooAbsPdf.h:212
@ CanNotBeExtended
Definition RooAbsPdf.h:212
double _rawValue
Definition RooAbsPdf.h:318
virtual std::unique_ptr< RooAbsReal > createExpectedEventsFunc(const RooArgSet *nset) const
Returns an object that represents the expected number of events for a given normalization set,...
virtual RooPlot * paramOn(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={})
Add a box with parameter values (and errors) to the specified frame.
RooFit::OwningPtr< RooFitResult > fitTo(RooAbsData &data, CmdArgs_t const &... cmdArgs)
Fit PDF to given dataset.
Definition RooAbsPdf.h:156
Int_t _negCount
Number of negative probabilities remaining to print.
Definition RooAbsPdf.h:337
RooFit::OwningPtr< RooDataSet > generate(const RooArgSet &whatVars, Int_t nEvents, const RooCmdArg &arg1, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={})
See RooAbsPdf::generate(const RooArgSet&,const RooCmdArg&,const RooCmdArg&,const RooCmdArg&,...
Definition RooAbsPdf.h:57
virtual const RooAbsReal * getNormObj(const RooArgSet *set, const RooArgSet *iset, const TNamed *rangeName=nullptr) const
Return pointer to RooAbsReal object that implements calculation of integral over observables iset in ...
void setActiveNormSet(RooArgSet const *normSet) const
Setter for the _normSet member, which should never be set directly.
Definition RooAbsPdf.h:284
double analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Analytical integral with normalization (see RooAbsReal::analyticalIntegralWN() for further informatio...
void setNormRangeOverride(const char *rangeName)
virtual RooFit::OwningPtr< RooDataSet > generateSimGlobal(const RooArgSet &whatVars, Int_t nEvents)
Special generator interface for generation of 'global observables' – for RooStats tools.
double normalizeWithNaNPacking(double rawVal, double normVal) const
virtual RooAbsGenContext * autoGenContext(const RooArgSet &vars, const RooDataSet *prototype=nullptr, const RooArgSet *auxProto=nullptr, bool verbose=false, bool autoBinned=true, const char *binnedTag="") const
RooArgSet * getAllConstraints(const RooArgSet &observables, RooArgSet &constrainedParams, bool stripDisconnected=true, bool removeConstraintsFromPdf=false) const
This helper function finds and collects all constraints terms of all component p.d....
const RooNumGenConfig * getGeneratorConfig() const
Return the numeric MC generator configuration used for this object.
virtual void initGenerator(Int_t code)
Interface for one-time initialization to setup the generator for the specified code.
virtual ExtendMode extendMode() const
Returns ability of PDF to provide extended likelihood terms.
Definition RooAbsPdf.h:216
RooAbsPdf()
Default constructor.
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:109
bool traceEvalPdf(double value) const
Check that passed value is positive and not 'not-a-number'.
static RooNumGenConfig * defaultGeneratorConfig()
Returns the default numeric MC generator configuration for all RooAbsReals.
bool redirectServersHook(const RooAbsCollection &newServerList, bool mustReplaceAll, bool nameChange, bool isRecursiveStep) override
The cache manager.
void printValue(std::ostream &os) const override
Print value of p.d.f, also print normalization integral that was last used, if any.
virtual std::unique_ptr< RooAbsReal > createNLLImpl(RooAbsData &data, const RooLinkedList &cmdList)
Protected implementation of the NLL creation routine.
void logBatchComputationErrors(std::span< const double > &outputs, std::size_t begin) const
Scan through outputs and fix+log all nans and negative values.
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.
void getLogProbabilities(std::span< const double > pdfValues, double *output) const
static TString _normRangeOverride
Definition RooAbsPdf.h:344
static Int_t _verboseEval
Definition RooAbsPdf.h:314
double extendedTerm(double sumEntries, double expected, double sumEntriesW2=0.0, bool doOffset=false) const
virtual Int_t getGenerator(const RooArgSet &directVars, RooArgSet &generateVars, bool staticInitOK=true) const
Load generatedVars with the subset of directVars that we can generate events for, and return a code t...
virtual RooAbsPdf * createProjection(const RooArgSet &iset)
Return a p.d.f that represent a projection of this p.d.f integrated over given observables.
virtual double getLogVal(const RooArgSet *set=nullptr) const
Return the log of the current value with given normalization An error message is printed if the argum...
bool hasRange(const char *name) const override
Check if variable has a binning with given name.
std::pair< double, double > getRange(const char *name=nullptr) const
Get low and high bound of the variable.
RooAbsReal is the common abstract base class for objects that represent a real value and implements f...
Definition RooAbsReal.h:59
RooDataHist * fillDataHist(RooDataHist *hist, const RooArgSet *nset, double scaleFactor, bool correctForBinVolume=false, bool showProgress=false) const
Fill a RooDataHist with values sampled from this function at the bin centers.
void plotOnCompSelect(RooArgSet *selNodes) const
Helper function for plotting of composite p.d.fs.
RooFit::OwningPtr< RooAbsReal > createIntegral(const RooArgSet &iset, 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 an object that represents the integral of the function over one or more observables listed in ...
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:103
bool plotSanityChecks(RooPlot *frame) const
Utility function for plotOn(), perform general sanity check on frame to ensure safe plotting operatio...
void printMultiline(std::ostream &os, Int_t contents, bool verbose=false, TString indent="") const override
Structure printing.
bool redirectServersHook(const RooAbsCollection &newServerList, bool mustReplaceAll, bool nameChange, bool isRecursiveStep) override
Function that is called at the end of redirectServers().
double _value
Cache for current value of object.
Definition RooAbsReal.h:543
virtual double analyticalIntegral(Int_t code, const char *rangeName=nullptr) const
Implements the actual analytical integral(s) advertised by getAnalyticalIntegral.
static void setEvalErrorLoggingMode(ErrorLoggingMode m)
Set evaluation error logging mode.
TString integralNameSuffix(const RooArgSet &iset, const RooArgSet *nset=nullptr, const char *rangeName=nullptr, bool omitEmpty=false) const
Construct string with unique suffix name to give to integral object that encodes integrated observabl...
virtual double evaluate() const =0
Evaluate this PDF / function / constant. Needs to be overridden by all derived classes.
void logEvalError(const char *message, const char *serverValueString=nullptr) const
Log evaluation error message.
const RooNumIntConfig * getIntegratorConfig() const
Return the numeric integration configuration used for this object.
virtual bool isBinnedDistribution(const RooArgSet &) const
Tests if the distribution is binned. Unless overridden by derived classes, this always returns false.
Definition RooAbsReal.h:353
RooFit::OwningPtr< RooAbsReal > createIntRI(const RooArgSet &iset, const RooArgSet &nset={})
Utility function for createRunningIntegral.
virtual RooPlot * plotOn(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 RooCmdArg &arg9={}, const RooCmdArg &arg10={}) const
Plot (project) PDF on specified frame.
virtual double offset() const
Definition RooAbsReal.h:378
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:55
RooBinnedGenContext is an efficient implementation of the generator context specific for binned pdfs.
Int_t setObj(const RooArgSet *nset, T *obj, const TNamed *isetRangeName=nullptr)
Setter function without integration set.
T * getObj(const RooArgSet *nset, Int_t *sterileIndex=nullptr, const TNamed *isetRangeName=nullptr)
Getter function without integration set.
RooCachedReal is an implementation of RooAbsCachedReal that can cache any external RooAbsReal input f...
void setCacheSource(bool flag)
RooCmdArg is a named container for two doubles, two integers two object points and three string point...
Definition RooCmdArg.h:26
void setInt(Int_t idx, Int_t value)
Definition RooCmdArg.h:72
Int_t getInt(Int_t idx) const
Definition RooCmdArg.h:86
void setString(Int_t idx, const char *value)
Definition RooCmdArg.h:78
Class RooCmdConfig is a 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 ...
const char * getString(const char *name, const char *defaultValue="", bool convEmptyToNull=false) const
Return string property registered with name 'name'.
bool defineString(const char *name, const char *argName, int stringNum, const char *defValue="", bool appendMode=false)
Define double property name 'name' mapped to double in slot 'stringNum' in RooCmdArg with name argNam...
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'.
RooLinkedList filterCmdList(RooLinkedList &cmdInList, const char *cmdNameList, bool removeFromInList=true) const
Utility function to filter commands listed in cmdNameList from cmdInList.
TObject * getObject(const char *name, TObject *obj=nullptr) const
Return TObject property registered with name 'name'.
RooDataSet is a container class to hold unbinned data.
Definition RooDataSet.h:57
void markAsCompiled(RooAbsArg &arg) const
void compileServers(RooAbsArg &arg, RooArgSet const &normSet)
static Value & defaultValue()
Class RooGenContext implement a universal generator context for all RooAbsPdf classes that do not hav...
Switches the message service to a different level while the instance is alive.
Definition RooHelpers.h:42
RooLinkedList is an collection class for internal use, storing a collection of RooAbsArg pointers in ...
virtual void Add(TObject *arg)
TObject * FindObject(const char *name) const override
Return pointer to object with given name.
static const char * str(const TNamed *ptr)
Return C++ string corresponding to given TNamed pointer.
Definition RooNameReg.h:37
RooNumGenConfig holds the configuration parameters of the various numeric integrators used by RooReal...
static RooNumGenConfig & defaultConfig()
Return reference to instance of default numeric integrator configuration object.
Class RooObjCacheManager is an implementation of class RooCacheManager<RooAbsCacheElement> and specia...
void sterilize() override
Clear the cache payload but retain slot mapping w.r.t to normalization and integration sets.
A RooPlot is a plot frame and a container for graphics objects within that frame.
Definition RooPlot.h:43
void addObject(TObject *obj, Option_t *drawOptions="", bool invisible=false)
Add a generic object to this plot.
Definition RooPlot.cxx:383
double getFitRangeNEvt() const
Return the number of events in the fit range.
Definition RooPlot.h:139
const RooArgSet * getNormVars() const
Definition RooPlot.h:146
RooAbsRealLValue * getPlotVar() const
Definition RooPlot.h:137
void updateNormVars(const RooArgSet &vars)
Install the given set of observables are reference normalization variables for this frame.
Definition RooPlot.cxx:368
double getFitRangeBinW() const
Return the bin width that is being used to normalise the PDF.
Definition RooPlot.h:142
virtual void printStream(std::ostream &os, Int_t contents, StyleOption style, TString indent="") const
Print description of object on ostream, printing contents set by contents integer,...
Class RooProjectedPdf is a RooAbsPdf implementation that represent a projection of a given input p....
static UInt_t integer(UInt_t max, TRandom *generator=randomGenerator())
Return an integer uniformly distributed from [0,n-1].
Definition RooRandom.cxx:99
static TRandom * randomGenerator()
Return a pointer to a singleton random-number generator implementation.
Definition RooRandom.cxx:51
RooRealIntegral performs hybrid numerical/analytical integrals of RooAbsReal objects.
const RooArgSet & numIntRealVars() const
RooRealVar represents a variable that can be changed from the outside.
Definition RooRealVar.h:37
void setRange(const char *name, double min, double max)
Set a fit or plotting range.
void setBins(Int_t nBins, const char *name=nullptr)
Create a uniform binning under name 'name' for this variable.
RooSimultaneous facilitates simultaneous fitting of multiple PDFs to subsets of a given dataset.
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:47
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:48
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:207
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:525
A Pave (see TPave) with text, lines or/and boxes inside.
Definition TPaveText.h:21
virtual Int_t Poisson(Double_t mean)
Generates a random integer N according to a Poisson law.
Definition TRandom.cxx:402
virtual Double_t Uniform(Double_t x1=1)
Returns a uniform deviate on the interval (0, x1).
Definition TRandom.cxx:672
virtual UInt_t Integer(UInt_t imax)
Returns a random integer uniformly distributed on the interval [ 0, imax-1 ].
Definition TRandom.cxx:360
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:421
void Clear()
Clear string without changing its capacity.
Definition TString.cxx:1222
const char * Data() const
Definition TString.h:380
TLine * line
void box(Int_t pat, Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Definition fillpatterns.C:1
RooCmdArg SupNormSet(const RooArgSet &nset)
RooCmdArg WeightVar(const char *name="weight", bool reinterpretAsWeight=false)
RooCmdArg Hesse(bool flag=true)
RooCmdArg ModularL(bool flag=false)
RooCmdArg PrintLevel(Int_t code)
RooCmdArg NormRange(const char *rangeNameList)
RooCmdArg Range(const char *rangeName, bool adjustNorm=true)
RooCmdArg Normalization(double scaleFactor)
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
std::unique_ptr< RooAbsReal > createNLL(RooAbsPdf &pdf, RooAbsData &data, std::unique_ptr< RooAbsReal > &&constraints, std::string const &rangeName, RooArgSet const &projDeps, bool isExtended, double integrateOverBinsPrecision, RooFit::OffsetMode offset)
OwningPtr< T > owningPtr(std::unique_ptr< T > &&ptr)
Internal helper to turn a std::unique_ptr<T> into an OwningPtr.
Definition Config.h:50
std::unique_ptr< T > compileForNormSet(T const &arg, RooArgSet const &normSet)
void defineMinimizationOptions(RooCmdConfig &pc)
std::unique_ptr< RooFitResult > minimize(RooAbsReal &model, RooAbsReal &nll, RooAbsData const &data, RooCmdConfig const &pc)
constexpr int extendedFitDefault
Definition FitHelpers.h:37
OffsetMode
For setting the offset mode with the Offset() command argument to RooAbsPdf::fitTo()
T * OwningPtr
An alias for raw pointers for indicating that the return type of a RooFit function is an owning point...
Definition Config.h:43
std::string getColonSeparatedNameString(RooArgSet const &argSet, char delim=':')
Create a string with all sorted names of RooArgSet elements separated by delimiters.
std::unique_ptr< T > cloneTreeWithSameParameters(T const &arg, RooArgSet const *observables=nullptr)
Clone RooAbsArg object and reattach to original parameters.
Definition RooHelpers.h:149
RooArgSet selectFromArgSet(RooArgSet const &, std::string const &names)
Construct a RooArgSet of objects in a RooArgSet whose names match to those in the names string.
BinnedLOutput getBinnedL(RooAbsPdf const &pdf)
Bool_t IsNaN(Double_t x)
Definition TMath.h:892
Double_t QuietNaN()
Returns a quiet NaN as defined by IEEE 754.
Definition TMath.h:902
Definition first.py:1
std::string rangeName
Stores the configuration parameters for RooAbsTestStatistic.
__roodevice__ static __roohost__ double packFloatIntoNaN(float payload)
Pack float into mantissa of a NaN.
static void output()