Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooAbsAnaConvPdf.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 RooAbsAnaConvPdf
19/// \ingroup Roofitcore
20///
21/// Base class for PDFs that represent a
22/// physics model that can be analytically convolved with a resolution model.
23///
24/// To achieve factorization between the physics model and the resolution
25/// model, each physics model must be able to be written in the form
26/// \f[
27/// \mathrm{Phys}(x, \bar{a}, \bar{b}) = \sum_k \mathrm{coef}_k(\bar{a}) * \mathrm{basis}_k(x,\bar{b})
28/// \f]
29///
30/// where \f$ \mathrm{basis}_k \f$ are a limited number of functions in terms of the variable
31/// to be convoluted, and \f$ \mathrm{coef}_k \f$ are coefficients independent of the convolution
32/// variable.
33///
34/// Classes derived from RooResolutionModel implement
35/// \f[
36/// R_k(x,\bar{b},\bar{c}) = \int \mathrm{basis}_k(x', \bar{b}) \cdot \mathrm{resModel}(x-x',\bar{c}) \;
37/// \mathrm{d}x',
38/// \f]
39///
40/// which RooAbsAnaConvPdf uses to construct the pdf for [ Phys (x) R ] :
41/// \f[
42/// \mathrm{PDF}(x,\bar{a},\bar{b},\bar{c}) = \sum_k \mathrm{coef}_k(\bar{a}) * R_k(x,\bar{b},\bar{c})
43/// \f]
44///
45/// A minimal implementation of a RooAbsAnaConvPdf physics model consists of
46///
47/// - A constructor that declares the required basis functions using the declareBasis() method.
48/// The declareBasis() function assigns a unique identifier code to each declare basis
49///
50/// - An implementation of `coefficient(Int_t code)` returning the coefficient value for each
51/// declared basis function
52///
53/// Optionally, analytical integrals can be provided for the coefficient functions. The
54/// interface for this is quite similar to that for integrals of regular PDFs. Two functions,
55/// \code{.cpp}
56/// Int_t getCoefAnalyticalIntegral(Int_t coef, RooArgSet& allVars, RooArgSet& analVars, const char* rangeName) const
57/// double coefAnalyticalIntegral(Int_t coef, Int_t code, const char* rangeName) const
58/// \endcode
59///
60/// advertise the coefficient integration capabilities and implement them respectively.
61/// Please see RooAbsPdf for additional details. Advertised analytical integrals must be
62/// valid for all coefficients.
63///
64/// ### The resolution model is a configuration object, not a graph node
65///
66/// The resolution model passed to the constructor is **not** a node of the
67/// computation graph of the RooAbsAnaConvPdf. It is never evaluated directly;
68/// it only serves as a *configuration* object that specifies which resolution
69/// model should be convolved with the basis functions. From it, the
70/// RooAbsAnaConvPdf builds its own internal \f$ \mathrm{basis}_k \otimes
71/// \mathrm{resModel} \f$ convolution objects (one per declared basis function),
72/// and it is *those* convolutions that are the actual value servers of the pdf
73/// and that get evaluated.
74///
75/// Consequently, the resolution model itself is not a server of the
76/// RooAbsAnaConvPdf. It remains accessible via getModel() (for example for
77/// serialization), but it does not appear in the pdf's `servers()` list, in
78/// `getParameters()` / `getVariables()`, or in the printed computation graph.
79///
80/// \note **Behavior change in ROOT 6.42:** in earlier releases the resolution
81/// model was kept as a (non-value, non-shape) server of the RooAbsAnaConvPdf.
82/// As a side effect, importing a RooAbsAnaConvPdf into a RooWorkspace also
83/// dragged the original resolution model into the workspace (and into HS3/JSON
84/// exports), even though it played no role in the computation. As of ROOT 6.42
85/// this is no longer the case: a resolution model that is only used as the
86/// configuration of a RooAbsAnaConvPdf is not imported into the workspace on
87/// its own anymore.
88///
89/// Objects written with older ROOT versions are read back correctly via schema
90/// evolution: the resolution model is dropped as a server, so the *pdf's*
91/// computation graph is the same as for a freshly constructed one. Note,
92/// however, that if such an old file already stored the resolution model as a
93/// standalone RooWorkspace member (which used to happen on import), that member
94/// is *not* retroactively removed from the workspace on read-back -- it simply
95/// is no longer wired into the RooAbsAnaConvPdf. Only newly created workspaces
96/// are guaranteed to be free of the standalone resolution model.
97
98#include "RooAbsAnaConvPdf.h"
99
101#include "RooMsgService.h"
102#include "RooResolutionModel.h"
103#include "RooRealVar.h"
104#include "RooFormulaVar.h"
105#include "RooConvGenContext.h"
106#include "RooGenContext.h"
107#include "RooTruthModel.h"
108#include "RooConvCoefVar.h"
109#include "RooNameReg.h"
110
111using std::endl, std::string, std::ostream;
112
113
114
115////////////////////////////////////////////////////////////////////////////////
116/// Default constructor, required for persistence
117
119 _isCopy(false),
120 _coefNormMgr(this,10)
121{
122}
123
124
125
126////////////////////////////////////////////////////////////////////////////////
127/// Constructor. The supplied resolution model must be constructed with the same
128/// convoluted variable as this physics model ('convVar')
129
130RooAbsAnaConvPdf::RooAbsAnaConvPdf(const char *name, const char *title, const RooResolutionModel &model,
132 : RooAbsPdf(name, title),
133 _isCopy(false),
134 _model{static_cast<RooResolutionModel *>(model.clone(model.GetName()))},
135 _ownModel{true},
136 _convVar("!convVar", "Convolution variable", this, cVar, false, false),
137 _convSet("!convSet", "Set of resModel X basisFunc convolutions", this),
138 _coefNormMgr(this, 10),
139 _codeReg(10)
140{
141}
142
143
144
145////////////////////////////////////////////////////////////////////////////////
146
148 : RooAbsPdf(other, name),
149 _isCopy(true),
150 _model{other._model ? static_cast<RooResolutionModel *>(other._model->clone(other._model->GetName())) : nullptr},
151 _ownModel{true},
152 _convVar("!convVar", this, other._convVar),
153 _convSet("!convSet", this, other._convSet),
154 _coefNormMgr(other._coefNormMgr, this),
155 _codeReg(other._codeReg)
156{
157 // Copy constructor
158 if (_model) {
159 }
160 other._basisList.snapshot(_basisList);
161}
162
163
164
165////////////////////////////////////////////////////////////////////////////////
166/// Destructor
167
169{
170 if (!_isCopy) {
171 std::vector<RooAbsArg*> tmp(_convSet.begin(), _convSet.end());
172
173 for (auto arg : tmp) {
174 _convSet.remove(*arg) ;
175 delete arg ;
176 }
177 }
178
179 if (_ownModel) {
180 delete _model;
181 }
182}
183
184////////////////////////////////////////////////////////////////////////////////
185/// Forward server redirection to the original resolution model. The resolution
186/// model is not a server of this pdf (it is only used to build the convolutions
187/// and for generation), so it is not redirected by the standard machinery. We
188/// keep its servers in sync here, analogous to RooResolutionModel forwarding
189/// the redirection to its basis function.
190
192 bool isRecursive)
193{
194 if (_model) {
195 // Pass mustReplaceAll=false: the model may legitimately reference servers
196 // that are not part of this particular redirection, and it is never
197 // evaluated as part of the computation graph anyway.
199 }
200
202}
203
204////////////////////////////////////////////////////////////////////////////////
205/// Second-pass schema evolution, called by the RooWorkspace after reading.
206///
207/// In class version <= 3, the original resolution model was held in a
208/// RooRealProxy and was therefore a (non-value, non-shape) server of this pdf.
209/// The schema evolution read rule (see LinkDef.h) already recovered the model
210/// pointer into _model, but the stale server link is also restored from the
211/// file via the RooAbsArg server list. We remove it here, once the full graph
212/// is live, so that an object read from an old file has the same clean server
213/// structure as a freshly constructed one. This is safe because there is no
214/// longer a proxy that could resurrect the server link on copy.
215
217{
219
220 // Force removal (the link may have been added with a reference count > 1):
221 // the model must be completely severed from the server list.
222 if (_model && findServer(*_model)) {
223 removeServer(*_model, true);
224 }
225}
226
227////////////////////////////////////////////////////////////////////////////////
228/// Declare a basis function for use in this physics model. The string expression
229/// must be a valid RooFormulVar expression representing the basis function, referring
230/// to the convolution variable as '@0', and any additional parameters (supplied in
231/// 'params' as '@1','@2' etc.
232///
233/// The return value is a unique identifier code, that will be passed to coefficient()
234/// to identify the basis function for which the coefficient is requested. If the
235/// resolution model used does not support the declared basis function, code -1 is
236/// returned.
237///
238
239Int_t RooAbsAnaConvPdf::declareBasis(const char* expression, const RooArgList& params)
240{
241 // Sanity check
242 if (_isCopy) {
243 coutE(InputArguments) << "RooAbsAnaConvPdf::declareBasis(" << GetName() << "): ERROR attempt to "
244 << " declare basis functions in a copied RooAbsAnaConvPdf" << std::endl ;
245 return -1 ;
246 }
247
248 // Resolution model must support declared basis
249 if (!_model->isBasisSupported(expression)) {
250 coutE(InputArguments) << "RooAbsAnaConvPdf::declareBasis(" << GetName() << "): resolution model "
251 << _model->GetName() << " doesn't support basis function " << expression << std::endl;
252 return -1;
253 }
254
255 // Instantiate basis function
257 basisArgs.add(params) ;
258
259 TString basisName(expression) ;
260 for (const auto arg : basisArgs) {
261 basisName.Append("_") ;
262 basisName.Append(arg->GetName()) ;
263 }
264
265 auto basisFunc = std::make_unique<RooFormulaVar>(basisName, expression, basisArgs);
266 basisFunc->setAttribute("RooWorkspace::Recycle") ;
267 basisFunc->setOperMode(operMode()) ;
268
269 // Instantiate resModel x basisFunc convolution
270 RooAbsReal *conv = _model->convolution(basisFunc.get(), this);
271 _basisList.addOwned(std::move(basisFunc));
272 if (!conv) {
273 coutE(InputArguments) << "RooAbsAnaConvPdf::declareBasis(" << GetName() << "): unable to construct convolution with basis function '"
274 << expression << "'" << std::endl ;
275 return -1 ;
276 }
277 _convSet.add(*conv) ;
278
279 return _convSet.index(conv) ;
280}
281
282
283
284////////////////////////////////////////////////////////////////////////////////
285/// Change the current resolution model to newModel
286
288{
290 bool allOK(true) ;
292
293 // Build new resolution model
294 std::unique_ptr<RooResolutionModel> newConv{newModel.convolution(const_cast<RooFormulaVar*>(&conv->basis()),this)};
295 if (!newConvSet.addOwned(std::move(newConv))) {
296 allOK = false ;
297 break ;
298 }
299 }
300
301 // Check if all convolutions were successfully built
302 if (!allOK) {
303 return true ;
304 }
305
306 // Replace old convolutions with new set
308 _convSet.addOwned(std::move(newConvSet));
309
310 // Replace the stored original resolution model. Since it is not a server of
311 // this pdf, it cannot (and need not) be redirected via redirectServers(): we
312 // simply own a fresh clone of the new model.
313 if (_ownModel) {
314 delete _model;
315 }
316 _model = static_cast<RooResolutionModel *>(newModel.clone(newModel.GetName()));
317 _ownModel = true;
318
319 return false ;
320}
321
322
323
324
325////////////////////////////////////////////////////////////////////////////////
326/// Create a generator context for this p.d.f. If both the p.d.f and the resolution model
327/// support internal generation of the convolution observable on an infinite domain,
328/// deploy a specialized convolution generator context, which generates the physics distribution
329/// and the smearing separately, adding them a posteriori. If this is not possible return
330/// a (slower) generic generation context that uses accept/reject sampling
331
333 const RooArgSet* auxProto, bool verbose) const
334{
335 // Check if the resolution model specifies a special context to be used.
337 assert(conv);
338
339 std::unique_ptr<RooArgSet> modelDep {_model->getObservables(&vars)};
340 modelDep->remove(*convVar(),true,true) ;
341 Int_t numAddDep = modelDep->size() ;
342
343 // Check if physics PDF and resolution model can both directly generate the convolution variable
344 RooArgSet dummy ;
345 bool pdfCanDir = (getGenerator(*convVar(),dummy) != 0) ;
346 bool resCanDir = conv && (conv->getGenerator(*convVar(),dummy)!=0) && conv->isDirectGenSafe(*convVar()) ;
347
348 if (numAddDep>0 || !pdfCanDir || !resCanDir) {
349 // Any resolution model with more dependents than the convolution variable
350 // or pdf or resmodel do not support direct generation
351 string reason ;
352 if (numAddDep>0) reason += "Resolution model has more observables than the convolution variable. " ;
353 if (!pdfCanDir) reason += "PDF does not support internal generation of convolution observable. " ;
354 if (!resCanDir) reason += "Resolution model does not support internal generation of convolution observable. " ;
355
356 coutI(Generation) << "RooAbsAnaConvPdf::genContext(" << GetName() << ") Using regular accept/reject generator for convolution p.d.f because: " << reason.c_str() << std::endl ;
357 return new RooGenContext(*this,vars,prototype,auxProto,verbose) ;
358 }
359
360 RooAbsGenContext* context = conv->modelGenContext(*this, vars, prototype, auxProto, verbose);
361 if (context) return context;
362
363 // Any other resolution model: use specialized generator context
364 return new RooConvGenContext(*this,vars,prototype,auxProto,verbose) ;
365}
366
367
368
369////////////////////////////////////////////////////////////////////////////////
370/// Return true if it is safe to generate the convolution observable
371/// from the internal generator (this is the case if the chosen resolution
372/// model is the truth model)
373
375{
376
377 // All direct generation of convolution arg if model is truth model
378 if (!TString(_convVar.absArg()->GetName()).CompareTo(arg.GetName()) && dynamic_cast<RooTruthModel *>(_model)) {
379 return true;
380 }
381
382 return RooAbsPdf::isDirectGenSafe(arg) ;
383}
384
385
386
387////////////////////////////////////////////////////////////////////////////////
388/// Return a pointer to the convolution variable instance used in the resolution model
389
391{
392 auto* conv = static_cast<RooResolutionModel*>(_convSet.at(0));
393 if (!conv) return nullptr;
394 return &conv->convVar() ;
395}
396
397
398
399////////////////////////////////////////////////////////////////////////////////
400/// Calculate the current unnormalized value of the PDF
401///
402/// PDF = sum_k coef_k * [ basis_k (x) ResModel ]
403///
404
406{
407 double result(0) ;
408
409 Int_t index(0) ;
410 for (auto *conv : static_range_cast<RooAbsPdf*>(_convSet)) {
411 double coef = coefficient(index++) ;
412 if (coef!=0.) {
413 const double c = conv->getVal(nullptr);
414 cxcoutD(Eval) << "RooAbsAnaConvPdf::evaluate(" << GetName() << ") val += coef*conv [" << index-1 << "/"
415 << _convSet.size() << "] coef = " << coef << " conv = " << c << std::endl ;
416 result += c * coef;
417 } else {
418 cxcoutD(Eval) << "RooAbsAnaConvPdf::evaluate(" << GetName() << ") [" << index-1 << "/" << _convSet.size() << "] coef = 0" << std::endl ;
419 }
420 }
421
422 return result ;
423}
424
425
426
427////////////////////////////////////////////////////////////////////////////////
428/// Advertise capability to perform (analytical) integrals
429/// internally. For a given integration request over allVars while
430/// normalized over normSet2 and in range 'rangeName', returns
431/// largest subset that can be performed internally in analVars
432/// Return code is unique integer code identifying integration scenario
433/// to be passed to analyticalIntegralWN() to calculate requeste integral
434///
435/// Class RooAbsAnaConv defers analytical integration request to
436/// resolution model and/or coefficient implementations and
437/// aggregates results into composite configuration with a unique
438/// code assigned by RooAICRegistry
439
441 RooArgSet& analVars, const RooArgSet* normSet2, const char* /*rangeName*/) const
442{
443 // Handle trivial no-integration scenario
444 if (allVars.empty()) return 0 ;
445
446 if (_forceNumInt) return 0 ;
447
448 // Select subset of allVars that are actual dependents
450 getObservables(&allVars, allDeps);
451 std::unique_ptr<RooArgSet> normSet{normSet2 ? getObservables(normSet2) : nullptr};
452
453 RooArgSet intSetAll{allDeps,"intSetAll"};
454
455 // Split intSetAll in coef/conv parts
456 auto intCoefSet = std::make_unique<RooArgSet>("intCoefSet");
457 auto intConvSet = std::make_unique<RooArgSet>("intConvSet");
458
459 for (RooAbsArg * arg : intSetAll) {
460 bool ok(true) ;
461 for (RooAbsArg * conv : _convSet) {
462 if (conv->dependsOn(*arg)) ok=false ;
463 }
464
465 if (ok) {
466 intCoefSet->add(*arg) ;
467 } else {
468 intConvSet->add(*arg) ;
469 }
470
471 }
472
473 // Split normSetAll in coef/conv parts
474 auto normCoefSet = std::make_unique<RooArgSet>("normCoefSet");
475 auto normConvSet = std::make_unique<RooArgSet>("normConvSet");
476 if (normSet) {
477 for (RooAbsArg * arg : *normSet) {
478 bool ok(true) ;
479 for (RooAbsArg * conv : _convSet) {
480 if (conv->dependsOn(*arg)) ok=false ;
481 }
482
483 if (ok) {
484 normCoefSet->add(*arg) ;
485 } else {
486 normConvSet->add(*arg) ;
487 }
488
489 }
490 }
491
492 if (intCoefSet->empty()) intCoefSet.reset();
493 if (intConvSet->empty()) intConvSet.reset();
494 if (normCoefSet->empty()) normCoefSet.reset();
495 if (normConvSet->empty()) normConvSet.reset();
496
497
498 // Store integration configuration in registry
499 Int_t masterCode(0) ;
500 std::vector<Int_t> tmp(1, 0) ;
501
502 // takes ownership of all sets
504 intCoefSet.get(),
505 intConvSet.get(),
506 normCoefSet.get(),
507 normConvSet.get()) + 1;
508
509 analVars.add(allDeps) ;
510
511 return masterCode ;
512}
513
514
515
516
517////////////////////////////////////////////////////////////////////////////////
518/// Return analytical integral defined by given code, which is returned
519/// by getAnalyticalIntegralWN()
520///
521/// For unnormalized integrals the returned value is
522/// \f[
523/// \mathrm{PDF} = \sum_k \int \mathrm{coef}_k \; \mathrm{d}\bar{x}
524/// \cdot \int \mathrm{basis}_k (x) \mathrm{ResModel} \; \mathrm{d}\bar{y},
525/// \f]
526/// where \f$ \bar{x} \f$ is the set of coefficient dependents to be integrated,
527/// and \f$ \bar{y} \f$ the set of basis function dependents to be integrated.
528///
529/// For normalized integrals this becomes
530/// \f[
531/// \mathrm{PDF} = \frac{\sum_k \int \mathrm{coef}_k \; \mathrm{d}x
532/// \cdot \int \mathrm{basis}_k (x) \mathrm{ResModel} \; \mathrm{d}y}
533/// {\sum_k \int \mathrm{coef}_k \; \mathrm{d}v
534/// \cdot \int \mathrm{basis}_k (x) \mathrm{ResModel} \; \mathrm{d}w},
535/// \f]
536/// where
537/// * \f$ x \f$ is the set of coefficient dependents to be integrated,
538/// * \f$ y \f$ the set of basis function dependents to be integrated,
539/// * \f$ v \f$ is the set of coefficient dependents over which is normalized and
540/// * \f$ w \f$ is the set of basis function dependents over which is normalized.
541///
542/// Set \f$ x \f$ must be contained in \f$ v \f$ and set \f$ y \f$ must be contained in \f$ w \f$.
543///
544
546{
547 // WVE needs adaptation to handle new rangeName feature
548
549 // Handle trivial passthrough scenario
550 if (code == 0)
551 return getVal(normSet);
552
553 // Unpack master code
554 auto retrieved = _codeReg.retrieve(code - 1);
555 RooArgSet *intCoefSet = retrieved.sets[0];
556 RooArgSet *intConvSet = retrieved.sets[1];
559
560 Int_t index(0);
561
562 if (normCoefSet == nullptr && normConvSet == nullptr) {
563 // Integral over unnormalized function
564 double integral(0);
566 for (auto *conv : static_range_cast<RooAbsPdf *>(_convSet)) {
567 double coef = getCoefNorm(index++, intCoefSet, rangeNamePtr);
568 if (coef != 0) {
569 const double term = coef * conv->getNormObj(nullptr, intConvSet, rangeNamePtr)->getVal();
570 integral += term;
571 cxcoutD(Eval) << "RooAbsAnaConv::aiWN(" << GetName() << ") [" << index - 1 << "] integral += " << term
572 << std::endl;
573 }
574 }
575 return integral;
576 }
577
578 // Integral over normalized function
579 double integral(0);
580 double norm(0);
582 for (auto *conv : static_range_cast<RooAbsPdf *>(_convSet)) {
583
585 if (coefInt != 0) {
586 double term = conv->getNormObj(nullptr, intConvSet, rangeNamePtr)->getVal();
587 integral += coefInt * term;
588 }
589
591 if (coefNorm != 0) {
592 double term = conv->getNormObj(nullptr, normConvSet)->getVal();
593 norm += coefNorm * term;
594 }
595
596 index++;
597 }
598 return integral / norm;
599}
600
601
602
603////////////////////////////////////////////////////////////////////////////////
604/// Default implementation of function advertising integration capabilities. The interface is
605/// similar to that of getAnalyticalIntegral except that an integer code is added that
606/// designates the coefficient number for which the integration capabilities are requested
607///
608/// This default implementation advertises that no internal integrals are supported.
609
610Int_t RooAbsAnaConvPdf::getCoefAnalyticalIntegral(Int_t /* coef*/, RooArgSet& /*allVars*/, RooArgSet& /*analVars*/, const char* /*rangeName*/) const
611{
612 return 0 ;
613}
614
615
616
617////////////////////////////////////////////////////////////////////////////////
618/// Default implementation of function implementing advertised integrals. Only
619/// the pass-through scenario (no integration) is implemented.
620
621double RooAbsAnaConvPdf::coefAnalyticalIntegral(Int_t coef, Int_t code, const char* /*rangeName*/) const
622{
623 if (code==0) return coefficient(coef) ;
624 coutE(InputArguments) << "RooAbsAnaConvPdf::coefAnalyticalIntegral(" << GetName() << ") ERROR: unrecognized integration code: " << code << std::endl ;
625 assert(0) ;
626 return 1 ;
627}
628
629
630
631////////////////////////////////////////////////////////////////////////////////
632/// This function forces RooRealIntegral to offer all integration dependents
633/// to RooAbsAnaConvPdf::getAnalyticalIntegralWN() for consideration for
634/// internal integration, if RooRealIntegral considers this to be unsafe (e.g. due
635/// to hidden Jacobian terms).
636///
637/// RooAbsAnaConvPdf will not attempt to actually integrate all these dependents
638/// but feed them to the resolution models integration interface, which will
639/// make the final determination on how to integrate these dependents.
640
642{
643 return true ;
644}
645
646
647
648////////////////////////////////////////////////////////////////////////////////
649/// Returns the normalization integral value of the coefficient with number coefIdx over normalization
650/// set nset in range rangeName
651
653{
654 if (nset==nullptr) return coefficient(coefIdx) ;
655
656 CacheElem* cache = static_cast<CacheElem*>(_coefNormMgr.getObj(nset,nullptr,nullptr,rangeName)) ;
657 if (!cache) {
658
659 cache = new CacheElem ;
660
661 // Make list of coefficient normalizations
663
664 for (std::size_t i=0 ; i<cache->_coefVarList.size() ; i++) {
665 cache->_normList.addOwned(std::unique_ptr<RooAbsReal>{static_cast<RooAbsReal&>(*cache->_coefVarList.at(i)).createIntegral(*nset,RooNameReg::str(rangeName))});
666 }
667
668 _coefNormMgr.setObj(nset,nullptr,cache,rangeName) ;
669 }
670
671 return (static_cast<RooAbsReal*>(cache->_normList.at(coefIdx)))->getVal() ;
672}
673
674
675
676////////////////////////////////////////////////////////////////////////////////
677/// Build complete list of coefficient variables
678
680{
681 // Instantiate a coefficient variables
682 for (std::size_t i=0 ; i<_convSet.size() ; i++) {
683 auto cvars = coefVars(i);
684 std::string name = std::string{GetName()} + "_coefVar_" + std::to_string(i);
685 varList.addOwned(std::make_unique<RooConvCoefVar>(name.c_str(),"coefVar",*this,i,&*cvars));
686 }
687
688}
689
690
691////////////////////////////////////////////////////////////////////////////////
692/// Return set of parameters with are used exclusively by the coefficient functions
693
695{
696 std::unique_ptr<RooArgSet> cVars{getParameters(static_cast<RooArgSet*>(nullptr))};
697 std::vector<RooAbsArg*> tmp;
698 for (auto arg : *cVars) {
699 for (auto convSetArg : _convSet) {
700 if (convSetArg->dependsOn(*arg)) {
701 tmp.push_back(arg);
702 }
703 }
704 }
705
706 cVars->remove(tmp.begin(), tmp.end(), true, true);
707
708 return RooFit::makeOwningPtr(std::move(cVars));
709}
710
711
712
713
714////////////////////////////////////////////////////////////////////////////////
715/// Print info about this object to the specified stream. In addition to the info
716/// from RooAbsPdf::printStream() we add:
717///
718/// Verbose : detailed information on convolution integrals
719
720void RooAbsAnaConvPdf::printMultiline(ostream& os, Int_t contents, bool verbose, TString indent) const
721{
722 RooAbsPdf::printMultiline(os,contents,verbose,indent);
723
724 os << indent << "--- RooAbsAnaConvPdf ---" << std::endl;
725 for (RooAbsArg * conv : _convSet) {
726 conv->printMultiline(os,contents,verbose,indent) ;
727 }
728}
729
730
731std::unique_ptr<RooAbsArg>
733{
734 // If there is only one component in the linear sum of convolutions, we can
735 // just return that one, normalized.
736 if(_convSet.size() == 1) {
737 if (normSet.empty()) {
738 return _convSet[0].compileForNormSet(normSet, ctx);
739 }
740 std::unique_ptr<RooAbsPdf> pdfClone(static_cast<RooAbsPdf *>(_convSet[0].Clone()));
741 ctx.compileServers(*pdfClone, normSet);
742
743 auto newArg = std::make_unique<RooFit::Detail::RooNormalizedPdf>(*pdfClone, normSet);
744
745 // The direct servers are this pdf and the normalization integral, which
746 // don't need to be compiled further.
747 for (RooAbsArg *server : newArg->servers()) {
748 server->setAttribute("_COMPILED");
749 }
750 newArg->setAttribute("_COMPILED");
751 newArg->addOwnedComponents(std::move(pdfClone));
752 return newArg;
753 }
754
755 // Here, we can't use directly the function from the RooAbsPdf base class,
756 // because the convolution argument servers need to be evaluated
757 // unnormalized, even if they are pdfs.
758
759 if (normSet.empty()) {
761 }
762 std::unique_ptr<RooAbsAnaConvPdf> pdfClone(static_cast<RooAbsAnaConvPdf *>(this->Clone()));
763
764 // The other servers will be compiled with the original normSet, but the
765 // _convSet has to be evaluated unnormalized.
767 for (RooAbsArg *convArg : _convSet) {
768 if (auto convArgClone = ctx.compile(*convArg, *pdfClone, {})) {
770 }
771 }
772 pdfClone->redirectServers(convArgClones, false, true);
773
774 // Compile remaining servers that are evaluated normalized
775 ctx.compileServers(*pdfClone, normSet);
776
777 // Finally, this RooAbsAnaConvPdf needs to be normalized
778 auto newArg = std::make_unique<RooFit::Detail::RooNormalizedPdf>(*pdfClone, normSet);
779
780 // The direct servers are this pdf and the normalization integral, which
781 // don't need to be compiled further.
782 for (RooAbsArg *server : newArg->servers()) {
783 server->setAttribute("_COMPILED");
784 }
785 newArg->setAttribute("_COMPILED");
786 newArg->addOwnedComponents(std::move(pdfClone));
787 return newArg;
788}
#define c(i)
Definition RSha256.hxx:101
#define coutI(a)
#define cxcoutD(a)
#define coutE(a)
static void indent(ostringstream &buf, int indent_level)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
char name[80]
Definition TGX11.cxx:142
const_iterator begin() const
const_iterator end() const
int store(const std::vector< int > &codeList, RooArgSet *set1=nullptr, RooArgSet *set2=nullptr, RooArgSet *set3=nullptr, RooArgSet *set4=nullptr)
Store given arrays of integer codes, and up to four RooArgSets in the registry (each setX pointer may...
Output retrieve(int masterCode)
Retrieve the array of integer codes associated with the given master code, together with the (up to f...
Base class for PDFs that represent a physics model that can be analytically convolved with a resoluti...
friend class RooConvGenContext
Int_t getAnalyticalIntegralWN(RooArgSet &allVars, RooArgSet &analVars, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Advertise capability to perform (analytical) integrals internally.
double analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Return analytical integral defined by given code, which is returned by getAnalyticalIntegralWN()
virtual double coefAnalyticalIntegral(Int_t coef, Int_t code, const char *rangeName=nullptr) const
Default implementation of function implementing advertised integrals.
virtual bool changeModel(const RooResolutionModel &newModel)
Change the current resolution model to newModel.
double getCoefNorm(Int_t coefIdx, const RooArgSet &nset, const char *rangeName) const
bool forceAnalyticalInt(const RooAbsArg &dep) const override
This function forces RooRealIntegral to offer all integration dependents to RooAbsAnaConvPdf::getAnal...
RooAbsGenContext * genContext(const RooArgSet &vars, const RooDataSet *prototype=nullptr, const RooArgSet *auxProto=nullptr, bool verbose=false) const override
Create a generator context for this p.d.f.
RooResolutionModel * _model
Original resolution model (not a server)
virtual double coefficient(Int_t basisIndex) const =0
void ioStreamerPass2() override
Second-pass schema evolution, called by the RooWorkspace after reading.
RooArgList _basisList
! List of created basis functions
RooObjCacheManager _coefNormMgr
! Coefficient normalization manager
void makeCoefVarList(RooArgList &) const
Build complete list of coefficient variables.
RooAICRegistry _codeReg
! Registry of analytical integration codes
virtual Int_t getCoefAnalyticalIntegral(Int_t coef, RooArgSet &allVars, RooArgSet &analVars, const char *rangeName=nullptr) const
Default implementation of function advertising integration capabilities.
bool _ownModel
Flag indicating ownership of _model.
~RooAbsAnaConvPdf() override
Destructor.
bool isDirectGenSafe(const RooAbsArg &arg) const override
Return true if it is safe to generate the convolution observable from the internal generator (this is...
RooAbsRealLValue * convVar()
Retrieve the convolution variable.
double evaluate() const override
Calculate the current unnormalized value of the PDF.
void printMultiline(std::ostream &stream, Int_t contents, bool verbose=false, TString indent="") const override
Print info about this object to the specified stream.
RooRealProxy _convVar
Convolution variable.
bool redirectServersHook(const RooAbsCollection &newServerList, bool mustReplaceAll, bool nameChange, bool isRecursive) override
Forward server redirection to the original resolution model.
RooAbsAnaConvPdf()
Default constructor, required for persistence.
Int_t declareBasis(const char *expression, const RooArgList &params)
Declare a basis function for use in this physics model.
RooListProxy _convSet
Set of (resModel (x) basisFunc) convolution objects.
virtual RooFit::OwningPtr< RooArgSet > coefVars(Int_t coefIdx) const
Return set of parameters with are used exclusively by the coefficient functions.
std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const override
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
RooFit::OwningPtr< RooArgSet > getParameters(const RooAbsData *data, bool stripDisconnected=true) const
Create a list of leaf nodes in the arg tree starting with ourself as top node that don't match any of...
void removeServer(RooAbsArg &server, bool force=false)
Unregister another RooAbsArg as a server to us, ie, declare that we no longer depend on its value and...
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 redirectServers(const RooAbsCollection &newServerList, bool mustReplaceAll=false, bool nameChange=false, bool isRecursionStep=false)
Replace all direct servers of this object with the new servers in newServerList.
virtual void ioStreamerPass2()
Method called by workspace container to finalize schema evolution issues that cannot be handled in a ...
TObject * Clone(const char *newname=nullptr) const override
Make a clone of an object using the Streamer facility.
Definition RooAbsArg.h:88
RooAbsArg * findServer(const char *name) const
Return server of this with name name. Returns nullptr if not found.
Definition RooAbsArg.h:147
OperMode operMode() const
Query the operation mode of this node.
Definition RooAbsArg.h:398
Abstract container object that can hold multiple RooAbsArg objects.
Int_t index(const RooAbsArg *arg) const
Returns index of given arg, or -1 if arg is not in the collection.
const_iterator end() const
Storage_t::size_type size() const
virtual bool addOwned(RooAbsArg &var, bool silent=false)
Add an argument and transfer the ownership to the collection.
const_iterator begin() const
Abstract base class for generator contexts of RooAbsPdf objects.
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const override
virtual bool isDirectGenSafe(const RooAbsArg &arg) const
Check if given observable can be safely generated using the pdfs internal generator mechanism (if tha...
void printMultiline(std::ostream &os, Int_t contents, bool verbose=false, TString indent="") const override
Print multi line detailed information of this RooAbsPdf.
bool redirectServersHook(const RooAbsCollection &newServerList, bool mustReplaceAll, bool nameChange, bool isRecursiveStep) override
Hook function intercepting redirectServer calls.
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...
Abstract base class for objects that represent a real value that may appear on the left hand side of ...
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:107
bool _forceNumInt
Force numerical integration if flag set.
Definition RooAbsReal.h:544
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 ...
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooAbsArg * at(Int_t idx) const
Return object at given index, or nullptr if index is out of range.
Definition RooArgList.h:110
RooAbsArg * absArg() const
Return pointer to contained argument.
Definition RooArgProxy.h:46
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
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.
void removeAll() override
Remove all argument inset using remove(const RooAbsArg&).
bool addOwned(RooAbsArg &var, bool silent=false) override
Overloaded RooCollection_t::addOwned() method insert object into owning set and registers object as s...
bool add(const RooAbsArg &var, bool valueServer, bool shapeServer, bool silent)
Overloaded RooCollection_t::add() method insert object into set and registers object as server to own...
bool remove(const RooAbsArg &var, bool silent=false, bool matchByNameOnly=false) override
Remove object 'var' from set and deregister 'var' as server to owner.
Container class to hold unbinned data.
Definition RooDataSet.h:32
A RooFormulaVar is a generic implementation of a real-valued object, which takes a RooArgList of serv...
Implements a universal generator context for all RooAbsPdf classes that do not have or need a special...
static const char * str(const TNamed *ptr)
Return C++ string corresponding to given TNamed pointer.
Definition RooNameReg.h:39
static const TNamed * ptr(const char *stringPtr)
Return a unique TNamed pointer for given C++ string.
Variable that can be changed from the outside.
Definition RooRealVar.h:37
RooResolutionModel is the base class for PDFs that represent a resolution model that can be convolute...
virtual RooResolutionModel * convolution(RooFormulaVar *basis, RooAbsArg *owner) const
Instantiate a clone of this resolution model representing a convolution with given basis function.
bool isBasisSupported(const char *name) const
virtual RooAbsGenContext * modelGenContext(const RooAbsAnaConvPdf &, const RooArgSet &, const RooDataSet *, const RooArgSet *, bool) const
RooAbsRealLValue & convVar() const
Return the convolution variable of the resolution model.
const T & arg() const
Return reference to object held in proxy.
Implements a RooResolution model that corresponds to a delta function.
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
Basic string class.
Definition TString.h:138
int CompareTo(const char *cs, ECaseCompare cmp=kExact) const
Compare a string to char *cs2.
Definition TString.cxx:464
T * OwningPtr
An alias for raw pointers for indicating that the return type of a RooFit function is an owning point...
Definition Config.h:35
OwningPtr< T > makeOwningPtr(std::unique_ptr< T > &&ptr)
Internal helper to turn a std::unique_ptr<T> into an OwningPtr.
Definition Config.h:40