Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooTruthModel.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooFitCore *
4 * @(#)root/roofitcore:$Id$
5 * Authors: *
6 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7 * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8 * *
9 * Copyright (c) 2000-2005, Regents of the University of California *
10 * and Stanford University. All rights reserved. *
11 * *
12 * Redistribution and use in source and binary forms, *
13 * with or without modification, are permitted according to the terms *
14 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15 *****************************************************************************/
16
17/**
18\file RooTruthModel.cxx
19\class RooTruthModel
20\ingroup Roofitcore
21
22Implements a RooResolution model that corresponds to a delta function.
23The truth model supports <i>all</i> basis functions because it evaluates each basis function as
24as a RooFormulaVar. The 6 basis functions used in B mixing and decay and 2 basis
25functions used in D mixing have been hand coded for increased execution speed.
26**/
27
28#include <RooTruthModel.h>
29
30#include <RooAbsAnaConvPdf.h>
31#include <RooBatchCompute.h>
32#include <RooGenContext.h>
33
35
36#include <TError.h>
37
38#include <algorithm>
39#include <array>
40#include <cmath>
41#include <limits>
42
43namespace {
44
45enum RooTruthBasis {
46 noBasis = 0,
47 expBasisMinus = 1,
48 expBasisSum = 2,
49 expBasisPlus = 3,
50 sinBasisMinus = 11,
51 sinBasisSum = 12,
52 sinBasisPlus = 13,
53 cosBasisMinus = 21,
54 cosBasisSum = 22,
55 cosBasisPlus = 23,
56 linBasisPlus = 33,
57 quadBasisPlus = 43,
58 coshBasisMinus = 51,
59 coshBasisSum = 52,
60 coshBasisPlus = 53,
61 sinhBasisMinus = 61,
62 sinhBasisSum = 62,
63 sinhBasisPlus = 63,
64 genericBasis = 100
65};
66
67enum BasisType {
68 none = 0,
69 expBasis = 1,
70 sinBasis = 2,
71 cosBasis = 3,
72 linBasis = 4,
73 quadBasis = 5,
74 coshBasis = 6,
75 sinhBasis = 7
76};
77
78enum BasisSign { Both = 0, Plus = +1, Minus = -1 };
79
80} // namespace
81
82
83////////////////////////////////////////////////////////////////////////////////
84/// Constructor of a truth resolution model, i.e. a delta function in observable 'xIn'
85
86RooTruthModel::RooTruthModel(const char *name, const char *title, RooAbsRealLValue& xIn) :
88{
89}
90
91////////////////////////////////////////////////////////////////////////////////
92/// Return basis code for given basis definition string. Return special
93/// codes for 'known' bases for which compiled definition exists. Return
94/// generic bases code if implementation relies on TFormula interpretation
95/// of basis name
96
98{
99 std::string str = name;
100
101 // Remove whitespaces from the input string
102 str.erase(remove(str.begin(),str.end(),' '),str.end());
103
104 // Check for optimized basis functions
105 if (str == "exp(-@0/@1)") return expBasisPlus ;
106 if (str == "exp(@0/@1)") return expBasisMinus ;
107 if (str == "exp(-abs(@0)/@1)") return expBasisSum ;
108 if (str == "exp(-@0/@1)*sin(@0*@2)") return sinBasisPlus ;
109 if (str == "exp(@0/@1)*sin(@0*@2)") return sinBasisMinus ;
110 if (str == "exp(-abs(@0)/@1)*sin(@0*@2)") return sinBasisSum ;
111 if (str == "exp(-@0/@1)*cos(@0*@2)") return cosBasisPlus ;
112 if (str == "exp(@0/@1)*cos(@0*@2)") return cosBasisMinus ;
113 if (str == "exp(-abs(@0)/@1)*cos(@0*@2)") return cosBasisSum ;
114 if (str == "(@0/@1)*exp(-@0/@1)") return linBasisPlus ;
115 if (str == "(@0/@1)*(@0/@1)*exp(-@0/@1)") return quadBasisPlus ;
116 if (str == "exp(-@0/@1)*cosh(@0*@2/2)") return coshBasisPlus;
117 if (str == "exp(@0/@1)*cosh(@0*@2/2)") return coshBasisMinus;
118 if (str == "exp(-abs(@0)/@1)*cosh(@0*@2/2)") return coshBasisSum;
119 if (str == "exp(-@0/@1)*sinh(@0*@2/2)") return sinhBasisPlus;
120 if (str == "exp(@0/@1)*sinh(@0*@2/2)") return sinhBasisMinus;
121 if (str == "exp(-abs(@0)/@1)*sinh(@0*@2/2)") return sinhBasisSum;
122
123 // Truth model is delta function, i.e. convolution integral is basis
124 // function, therefore we can handle any basis function
125 return genericBasis ;
126}
127
128
129
130////////////////////////////////////////////////////////////////////////////////
131/// Changes associated bases function to 'inBasis'
132
134{
135 // Remove client-server link to old basis
136 if (_basis) {
137 if (_basisCode == genericBasis) {
138 // In the case of a generic basis, we evaluate it directly, so the
139 // basis was a direct server.
141 } else {
142 for (RooAbsArg *basisServer : _basis->servers()) {
144 }
145 }
146
147 if (_ownBasis) {
148 delete _basis;
149 }
150 }
151 _ownBasis = false;
152
153 _basisCode = inBasis ? basisCode(inBasis->GetTitle()) : 0;
154
155 // Change basis pointer and update client-server link
156 _basis = inBasis;
157 if (_basis) {
158 if (_basisCode == genericBasis) {
159 // Since we actually evaluate the basis function object, we need to
160 // adjust our client-server links to the basis function here
161 addServer(*_basis, true, false);
162 } else {
163 for (RooAbsArg *basisServer : _basis->servers()) {
164 addServer(*basisServer, true, false);
165 }
166 }
167 }
168}
169
170
171
172////////////////////////////////////////////////////////////////////////////////
173/// Evaluate the truth model: a delta function when used as PDF,
174/// the basis function itself, when convoluted with a basis function.
175
177{
178 // No basis: delta function
179 if (_basisCode == noBasis) {
180 if (x==0) return 1 ;
181 return 0 ;
182 }
183
184 // Generic basis: evaluate basis function object
185 if (_basisCode == genericBasis) {
186 return basis().getVal() ;
187 }
188
189 // Precompiled basis functions
190 BasisType basisType = (BasisType)( (_basisCode == 0) ? 0 : (_basisCode/10) + 1 );
191 BasisSign basisSign = (BasisSign)( _basisCode - 10*(basisType-1) - 2 ) ;
192
193 // Enforce sign compatibility
194 if ((basisSign==Minus && x>0) ||
195 (basisSign==Plus && x<0)) return 0 ;
196
197
198 double tau = (static_cast<RooAbsReal*>(basis().getParameter(1)))->getVal() ;
199 // Return desired basis function
200 switch(basisType) {
201 case expBasis: {
202 return std::exp(-std::abs((double)x)/tau) ;
203 }
204 case sinBasis: {
205 double dm = (static_cast<RooAbsReal*>(basis().getParameter(2)))->getVal() ;
206 return std::exp(-std::abs((double)x)/tau)*std::sin(x*dm) ;
207 }
208 case cosBasis: {
209 double dm = (static_cast<RooAbsReal*>(basis().getParameter(2)))->getVal() ;
210 return std::exp(-std::abs((double)x)/tau)*std::cos(x*dm) ;
211 }
212 case linBasis: {
213 double tscaled = std::abs((double)x)/tau;
214 return std::exp(-tscaled)*tscaled ;
215 }
216 case quadBasis: {
217 double tscaled = std::abs((double)x)/tau;
218 return std::exp(-tscaled)*tscaled*tscaled;
219 }
220 case sinhBasis: {
221 double dg = (static_cast<RooAbsReal*>(basis().getParameter(2)))->getVal() ;
222 return std::exp(-std::abs((double)x)/tau)*std::sinh(x*dg/2) ;
223 }
224 case coshBasis: {
225 double dg = (static_cast<RooAbsReal*>(basis().getParameter(2)))->getVal() ;
226 return std::exp(-std::abs((double)x)/tau)*std::cosh(x*dg/2) ;
227 }
228 default:
229 R__ASSERT(0) ;
230 }
231
232 return 0 ;
233}
234
235
237{
238 auto config = ctx.config(this);
239 auto xVals = ctx.at(x);
240
241 // No basis: delta function
242 if (_basisCode == noBasis) {
244 return;
245 }
246
247 // Generic basis: evaluate basis function object
248 if (_basisCode == genericBasis) {
249 RooBatchCompute::compute(config, RooBatchCompute::Identity, ctx.output(), {ctx.at(&basis())});
250 return;
251 }
252
253 // Precompiled basis functions
254 const BasisType basisType = static_cast<BasisType>((_basisCode == 0) ? 0 : (_basisCode / 10) + 1);
255
256 // Cast the int from the enum to double because we can only pass doubles to
257 // RooBatchCompute at this point.
258 const double basisSign = static_cast<double>((BasisSign)(_basisCode - 10 * (basisType - 1) - 2));
259
260 auto param1 = static_cast<RooAbsReal const *>(basis().getParameter(1));
261 auto param2 = static_cast<RooAbsReal const *>(basis().getParameter(2));
262 auto param1Vals = param1 ? ctx.at(param1) : std::span<const double>{};
263 auto param2Vals = param2 ? ctx.at(param2) : std::span<const double>{};
264
265 // Return desired basis function
266 std::array<double, 1> extraArgs{basisSign};
267 switch (basisType) {
268 case expBasis: {
269 RooBatchCompute::compute(config, RooBatchCompute::TruthModelExpBasis, ctx.output(), {xVals, param1Vals},
270 extraArgs);
271 break;
272 }
273 case sinBasis: {
275 {xVals, param1Vals, param2Vals}, extraArgs);
276 break;
277 }
278 case cosBasis: {
280 {xVals, param1Vals, param2Vals}, extraArgs);
281 break;
282 }
283 case linBasis: {
284 RooBatchCompute::compute(config, RooBatchCompute::TruthModelLinBasis, ctx.output(), {xVals, param1Vals},
285 extraArgs);
286 break;
287 }
288 case quadBasis: {
289 RooBatchCompute::compute(config, RooBatchCompute::TruthModelQuadBasis, ctx.output(), {xVals, param1Vals},
290 extraArgs);
291 break;
292 }
293 case sinhBasis: {
295 {xVals, param1Vals, param2Vals}, extraArgs);
296 break;
297 }
298 case coshBasis: {
300 {xVals, param1Vals, param2Vals}, extraArgs);
301 break;
302 }
303 default: R__ASSERT(0);
304 }
305}
306
307
308////////////////////////////////////////////////////////////////////////////////
309/// Advertise analytical integrals for compiled basis functions and when used
310/// as p.d.f without basis function.
311
312Int_t RooTruthModel::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* /*rangeName*/) const
313{
314 switch(_basisCode) {
315
316 // Analytical integration capability of raw PDF
317 case noBasis:
318 if (matchArgs(allVars,analVars,convVar())) return 1 ;
319 break ;
320
321 // Analytical integration capability of convoluted PDF
322 case expBasisPlus:
323 case expBasisMinus:
324 case expBasisSum:
325 case sinBasisPlus:
326 case sinBasisMinus:
327 case sinBasisSum:
328 case cosBasisPlus:
329 case cosBasisMinus:
330 case cosBasisSum:
331 case linBasisPlus:
332 case quadBasisPlus:
333 case sinhBasisPlus:
334 case sinhBasisMinus:
335 case sinhBasisSum:
336 case coshBasisPlus:
337 case coshBasisMinus:
338 case coshBasisSum:
339 if (matchArgs(allVars,analVars,convVar())) return 1 ;
340 break ;
341 }
342
343 return 0 ;
344}
345
346
347namespace {
348
349// From asking WolframAlpha: integrate exp(-x/tau) over x.
350inline double indefiniteIntegralExpBasisPlus(double x, double tau, double /*dm*/)
351{
352 // Restrict to positive x
353 x = std::max(x, 0.0);
354 return -tau * std::exp(-x / tau);
355}
356
357// From asking WolframAlpha: integrate exp(-x/tau)* x / tau over x.
358inline double indefiniteIntegralLinBasisPlus(double x, double tau, double /*dm*/)
359{
360 // Restrict to positive x
361 x = std::max(x, 0.0);
362 return -(tau + x) * std::exp(-x / tau);
363}
364
365// From asking WolframAlpha: integrate exp(-x/tau) * (x / tau)^2 over x.
366inline double indefiniteIntegralQuadBasisPlus(double x, double tau, double /*dm*/)
367{
368 // Restrict to positive x
369 x = std::max(x, 0.0);
370 return -(std::exp(-x / tau) * (2 * tau * tau + x * x + 2 * tau * x)) / tau;
371}
372
373// A common factor that appears in the integrals of the trigonometric
374// function bases (sin and cos).
375inline double commonFactorPlus(double x, double tau, double dm)
376{
377 const double num = tau * std::exp(-x / tau);
378 const double den = dm * dm * tau * tau + 1.0;
379 return num / den;
380}
381
382// A common factor that appears in the integrals of the hyperbolic
383// trigonometric function bases (sinh and cosh).
384inline double commonFactorHyperbolicPlus(double x, double tau, double dm)
385{
386 const double num = 2 * tau * std::exp(-x / tau);
387 const double den = dm * dm * tau * tau - 4.0;
388 return num / den;
389}
390
391// From asking WolframAlpha: integrate exp(-x/tau)*sin(x*m) over x.
392inline double indefiniteIntegralSinBasisPlus(double x, double tau, double dm)
393{
394 // Restrict to positive x
395 x = std::max(x, 0.0);
396 const double fac = commonFactorPlus(x, tau, dm);
397 // Only multiply with the sine term if the coefficient is non zero,
398 // i.e. if x was not infinity. Otherwise, we are evaluating the
399 // sine of infinity, which is NAN!
400 return fac != 0.0 ? fac * (-tau * dm * std::cos(dm * x) - std::sin(dm * x)) : 0.0;
401}
402
403// From asking WolframAlpha: integrate exp(-x/tau)*cos(x*m) over x.
404inline double indefiniteIntegralCosBasisPlus(double x, double tau, double dm)
405{
406 // Restrict to positive x
407 x = std::max(x, 0.0);
408 const double fac = commonFactorPlus(x, tau, dm);
409 return fac != 0.0 ? fac * (tau * dm * std::sin(dm * x) - std::cos(dm * x)) : 0.0;
410}
411
412// From asking WolframAlpha: integrate exp(-x/tau)*sinh(x*m/2) over x.
413inline double indefiniteIntegralSinhBasisPlus(double x, double tau, double dm)
414{
415 // Restrict to positive x
416 x = std::max(x, 0.0);
417 const double fac = commonFactorHyperbolicPlus(x, tau, dm);
418 const double arg = 0.5 * dm * x;
419 return fac != 0.0 ? fac * (tau * dm * std::cosh(arg) - 2. * std::sinh(arg)) : 0.0;
420}
421
422// From asking WolframAlpha: integrate exp(-x/tau)*cosh(x*m/2) over x.
423inline double indefiniteIntegralCoshBasisPlus(double x, double tau, double dm)
424{
425 // Restrict to positive x
426 x = std::max(x, 0.0);
427 const double fac = commonFactorHyperbolicPlus(x, tau, dm);
428 const double arg = 0.5 * dm * x;
429 return fac != 0.0 ? fac * (tau * dm * std::sinh(arg) + 2. * std::cosh(arg)) : 0.0;
430}
431
432// Integrate one of the basis functions. Takes a function that represents the
433// indefinite integral, some parameters, and a flag that indicates whether the
434// basis function is symmetric or antisymmetric. This information is used to
435// evaluate the integrals for the "Minus" and "Sum" cases.
436template <class Function>
437double definiteIntegral(Function indefiniteIntegral, double xmin, double xmax, double tau, double dm,
438 BasisSign basisSign, bool isSymmetric)
439{
440 // Note: isSymmetric == false implies antisymmetric
441 if (tau == 0.0)
442 return isSymmetric ? 1.0 : 0.0;
443 double result = 0.0;
444 if (basisSign != Minus) {
445 result += indefiniteIntegral(xmax, tau, dm) - indefiniteIntegral(xmin, tau, dm);
446 }
447 if (basisSign != Plus) {
448 const double resultMinus = indefiniteIntegral(-xmax, tau, dm) - indefiniteIntegral(-xmin, tau, dm);
450 }
451 return result;
452}
453
454} // namespace
455
456////////////////////////////////////////////////////////////////////////////////
457/// Implement analytical integrals when used as p.d.f and for compiled
458/// basis functions.
459
460double RooTruthModel::analyticalIntegral(Int_t code, const char *rangeName) const
461{
462 // Code must be 1
463 R__ASSERT(code == 1);
464
465 // Unconvoluted PDF
466 if (_basisCode == noBasis)
467 return 1;
468
469 // Precompiled basis functions
470 BasisType basisType = (BasisType)((_basisCode == 0) ? 0 : (_basisCode / 10) + 1);
471 BasisSign basisSign = (BasisSign)(_basisCode - 10 * (basisType - 1) - 2);
472
473 const bool needsDm =
475
476 const double tau = (static_cast<RooAbsReal *>(basis().getParameter(1)))->getVal();
477 const double dm =
478 needsDm ? (static_cast<RooAbsReal *>(basis().getParameter(2)))->getVal() : std::numeric_limits<Double_t>::quiet_NaN();
479
480 const double xmin = x.min(rangeName);
481 const double xmax = x.max(rangeName);
482
483 auto integrate = [&](auto indefiniteIntegral, bool isSymmetric) {
485 };
486
487 switch (basisType) {
488 case expBasis: return integrate(indefiniteIntegralExpBasisPlus, /*isSymmetric=*/true);
489 case sinBasis: return integrate(indefiniteIntegralSinBasisPlus, /*isSymmetric=*/false);
490 case cosBasis: return integrate(indefiniteIntegralCosBasisPlus, /*isSymmetric=*/true);
491 case linBasis: return integrate(indefiniteIntegralLinBasisPlus, /*isSymmetric=*/false);
492 case quadBasis: return integrate(indefiniteIntegralQuadBasisPlus, /*isSymmetric=*/true);
493 case sinhBasis: return integrate(indefiniteIntegralSinhBasisPlus, /*isSymmetric=*/false);
494 case coshBasis: return integrate(indefiniteIntegralCoshBasisPlus, /*isSymmetric=*/true);
495 default: R__ASSERT(0);
496 }
497
498 R__ASSERT(0);
499 return 0;
500}
501
502
503////////////////////////////////////////////////////////////////////////////////
504
506(const RooAbsAnaConvPdf& convPdf, const RooArgSet &vars, const RooDataSet *prototype,
507 const RooArgSet* auxProto, bool verbose) const
508{
510 return new RooGenContext(convPdf, vars, prototype, auxProto, verbose, &forceDirect);
511}
512
513
514
515////////////////////////////////////////////////////////////////////////////////
516/// Advertise internal generator for observable x
517
519{
520 if (matchArgs(directVars,generateVars,x)) return 1 ;
521 return 0 ;
522}
523
524
525
526////////////////////////////////////////////////////////////////////////////////
527/// Implement internal generator for observable x,
528/// x=0 for all events following definition
529/// of delta function
530
532{
533 R__ASSERT(code==1) ;
534 double zero(0.) ;
535 x = zero ;
536 return;
537}
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:130
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
char name[80]
Definition TGX11.cxx:142
float xmin
float xmax
Base class for PDFs that represent a physics model that can be analytically convolved with a resoluti...
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
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...
const RefCountList_t & servers() const
List of all servers of this object.
Definition RooAbsArg.h:145
void addServer(RooAbsArg &server, bool valueProp=true, bool shapeProp=false, std::size_t refCount=1)
Register another RooAbsArg as a server to us, ie, declare that we depend on it.
Abstract base class for generator contexts of RooAbsPdf objects.
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
bool matchArgs(const RooArgSet &allDeps, RooArgSet &analDeps, const RooArgProxy &a, const Proxies &... proxies) const
Definition RooAbsReal.h:425
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
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...
RooResolutionModel is the base class for PDFs that represent a resolution model that can be convolute...
bool _ownBasis
Flag indicating ownership of _basis.
Int_t _basisCode
Identifier code for selected basis function.
RooAbsRealLValue & convVar() const
Return the convolution variable of the resolution model.
RooFormulaVar * _basis
Basis function convolved with this resolution model.
const RooFormulaVar & basis() const
RooTemplateProxy< RooAbsRealLValue > x
Dependent/convolution variable.
double max(const char *rname=nullptr) const
Query upper limit of range. This requires the payload to be RooAbsRealLValue or derived.
double min(const char *rname=nullptr) const
Query lower limit of range. This requires the payload to be RooAbsRealLValue or derived.
void doEval(RooFit::EvalContext &) const override
Base function for computing multiple values of a RooAbsReal.
void generateEvent(Int_t code) override
Implement internal generator for observable x, x=0 for all events following definition of delta funct...
double evaluate() const override
Evaluate the truth model: a delta function when used as PDF, the basis function itself,...
Int_t getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &analVars, const char *rangeName=nullptr) const override
Advertise analytical integrals for compiled basis functions and when used as p.d.f without basis func...
Int_t getGenerator(const RooArgSet &directVars, RooArgSet &generateVars, bool staticInitOK=true) const override
Advertise internal generator for observable x.
RooAbsGenContext * modelGenContext(const RooAbsAnaConvPdf &convPdf, const RooArgSet &vars, const RooDataSet *prototype=nullptr, const RooArgSet *auxProto=nullptr, bool verbose=false) const override
double analyticalIntegral(Int_t code, const char *rangeName=nullptr) const override
Implement analytical integrals when used as p.d.f and for compiled basis functions.
Int_t basisCode(const char *name) const override
Return basis code for given basis definition string.
RooTruthModel()=default
void changeBasis(RooFormulaVar *basis) override
Changes associated bases function to 'inBasis'.
Double_t x[n]
Definition legend1.C:17
void compute(Config cfg, Computer comp, std::span< double > output, VarSpan vars, ArgSpan extraArgs={})