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
34#include <Riostream.h>
35
36#include <TError.h>
37
38#include <algorithm>
39#include <limits>
40
41using namespace std ;
42
44
45
46////////////////////////////////////////////////////////////////////////////////
47/// Constructor of a truth resolution model, i.e. a delta function in observable 'xIn'
48
49RooTruthModel::RooTruthModel(const char *name, const char *title, RooAbsRealLValue& xIn) :
50 RooResolutionModel(name,title,xIn)
51{
52}
53
54
55
56////////////////////////////////////////////////////////////////////////////////
57/// Copy constructor
58
61{
62}
63
64
65
66////////////////////////////////////////////////////////////////////////////////
67/// Return basis code for given basis definition string. Return special
68/// codes for 'known' bases for which compiled definition exists. Return
69/// generic bases code if implementation relies on TFormula interpretation
70/// of basis name
71
73{
74 std::string str = name;
75
76 // Remove whitespaces from the input string
77 str.erase(remove(str.begin(),str.end(),' '),str.end());
78
79 // Check for optimized basis functions
80 if (str == "exp(-@0/@1)") return expBasisPlus ;
81 if (str == "exp(@0/@1)") return expBasisMinus ;
82 if (str == "exp(-abs(@0)/@1)") return expBasisSum ;
83 if (str == "exp(-@0/@1)*sin(@0*@2)") return sinBasisPlus ;
84 if (str == "exp(@0/@1)*sin(@0*@2)") return sinBasisMinus ;
85 if (str == "exp(-abs(@0)/@1)*sin(@0*@2)") return sinBasisSum ;
86 if (str == "exp(-@0/@1)*cos(@0*@2)") return cosBasisPlus ;
87 if (str == "exp(@0/@1)*cos(@0*@2)") return cosBasisMinus ;
88 if (str == "exp(-abs(@0)/@1)*cos(@0*@2)") return cosBasisSum ;
89 if (str == "(@0/@1)*exp(-@0/@1)") return linBasisPlus ;
90 if (str == "(@0/@1)*(@0/@1)*exp(-@0/@1)") return quadBasisPlus ;
91 if (str == "exp(-@0/@1)*cosh(@0*@2/2)") return coshBasisPlus;
92 if (str == "exp(@0/@1)*cosh(@0*@2/2)") return coshBasisMinus;
93 if (str == "exp(-abs(@0)/@1)*cosh(@0*@2/2)") return coshBasisSum;
94 if (str == "exp(-@0/@1)*sinh(@0*@2/2)") return sinhBasisPlus;
95 if (str == "exp(@0/@1)*sinh(@0*@2/2)") return sinhBasisMinus;
96 if (str == "exp(-abs(@0)/@1)*sinh(@0*@2/2)") return sinhBasisSum;
97
98 // Truth model is delta function, i.e. convolution integral is basis
99 // function, therefore we can handle any basis function
100 return genericBasis ;
101}
102
103
104
105////////////////////////////////////////////////////////////////////////////////
106/// Changes associated bases function to 'inBasis'
107
109{
110 // Remove client-server link to old basis
111 if (_basis) {
112 if (_basisCode == genericBasis) {
113 // In the case of a generic basis, we evaluate it directly, so the
114 // basis was a direct server.
116 } else {
117 for (RooAbsArg *basisServer : _basis->servers()) {
118 removeServer(*basisServer);
119 }
120 }
121
122 if (_ownBasis) {
123 delete _basis;
124 }
125 }
126 _ownBasis = false;
127
128 _basisCode = inBasis ? basisCode(inBasis->GetTitle()) : 0;
129
130 // Change basis pointer and update client-server link
131 _basis = inBasis;
132 if (_basis) {
133 if (_basisCode == genericBasis) {
134 // Since we actually evaluate the basis function object, we need to
135 // adjust our client-server links to the basis function here
136 addServer(*_basis, true, false);
137 } else {
138 for (RooAbsArg *basisServer : _basis->servers()) {
139 addServer(*basisServer, true, false);
140 }
141 }
142 }
143}
144
145
146
147////////////////////////////////////////////////////////////////////////////////
148/// Evaluate the truth model: a delta function when used as PDF,
149/// the basis function itself, when convoluted with a basis function.
150
152{
153 // No basis: delta function
154 if (_basisCode == noBasis) {
155 if (x==0) return 1 ;
156 return 0 ;
157 }
158
159 // Generic basis: evaluate basis function object
160 if (_basisCode == genericBasis) {
161 return basis().getVal() ;
162 }
163
164 // Precompiled basis functions
165 BasisType basisType = (BasisType)( (_basisCode == 0) ? 0 : (_basisCode/10) + 1 );
166 BasisSign basisSign = (BasisSign)( _basisCode - 10*(basisType-1) - 2 ) ;
167
168 // Enforce sign compatibility
169 if ((basisSign==Minus && x>0) ||
170 (basisSign==Plus && x<0)) return 0 ;
171
172
173 double tau = ((RooAbsReal*)basis().getParameter(1))->getVal() ;
174 // Return desired basis function
175 switch(basisType) {
176 case expBasis: {
177 //cout << " RooTruthModel::eval(" << GetName() << ") expBasis mode ret = " << exp(-std::abs((double)x)/tau) << " tau = " << tau << endl ;
178 return exp(-std::abs((double)x)/tau) ;
179 }
180 case sinBasis: {
181 double dm = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
182 return exp(-std::abs((double)x)/tau)*sin(x*dm) ;
183 }
184 case cosBasis: {
185 double dm = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
186 return exp(-std::abs((double)x)/tau)*cos(x*dm) ;
187 }
188 case linBasis: {
189 double tscaled = std::abs((double)x)/tau;
190 return exp(-tscaled)*tscaled ;
191 }
192 case quadBasis: {
193 double tscaled = std::abs((double)x)/tau;
194 return exp(-tscaled)*tscaled*tscaled;
195 }
196 case sinhBasis: {
197 double dg = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
198 return exp(-std::abs((double)x)/tau)*sinh(x*dg/2) ;
199 }
200 case coshBasis: {
201 double dg = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
202 return exp(-std::abs((double)x)/tau)*cosh(x*dg/2) ;
203 }
204 default:
205 R__ASSERT(0) ;
206 }
207
208 return 0 ;
209}
210
211
212void RooTruthModel::computeBatch(double *output, size_t nEvents, RooFit::Detail::DataMap const &dataMap) const
213{
214 auto config = dataMap.config(this);
215 auto xVals = dataMap.at(x);
216
217 // No basis: delta function
218 if (_basisCode == noBasis) {
220 return;
221 }
222
223 // Generic basis: evaluate basis function object
224 if (_basisCode == genericBasis) {
225 RooBatchCompute::compute(config, RooBatchCompute::Identity, output, nEvents, {dataMap.at(&basis())});
226 return;
227 }
228
229 // Precompiled basis functions
230 const BasisType basisType = static_cast<BasisType>((_basisCode == 0) ? 0 : (_basisCode / 10) + 1);
231
232 // Cast the int from the enum to double because we can only pass doubles to
233 // RooBatchCompute at this point.
234 const double basisSign = static_cast<double>((BasisSign)(_basisCode - 10 * (basisType - 1) - 2));
235
236 auto param1 = static_cast<RooAbsReal const *>(basis().getParameter(1));
237 auto param2 = static_cast<RooAbsReal const *>(basis().getParameter(2));
238 auto param1Vals = param1 ? dataMap.at(param1) : std::span<const double>{};
239 auto param2Vals = param2 ? dataMap.at(param2) : std::span<const double>{};
240
241 // Return desired basis function
242 RooBatchCompute::ArgVector extraArgs{basisSign};
243 switch (basisType) {
244 case expBasis: {
245 RooBatchCompute::compute(config, RooBatchCompute::TruthModelExpBasis, output, nEvents, {xVals, param1Vals},
246 extraArgs);
247 break;
248 }
249 case sinBasis: {
251 {xVals, param1Vals, param2Vals}, extraArgs);
252 break;
253 }
254 case cosBasis: {
256 {xVals, param1Vals, param2Vals}, extraArgs);
257 break;
258 }
259 case linBasis: {
260 RooBatchCompute::compute(config, RooBatchCompute::TruthModelLinBasis, output, nEvents, {xVals, param1Vals},
261 extraArgs);
262 break;
263 }
264 case quadBasis: {
265 RooBatchCompute::compute(config, RooBatchCompute::TruthModelQuadBasis, output, nEvents, {xVals, param1Vals},
266 extraArgs);
267 break;
268 }
269 case sinhBasis: {
271 {xVals, param1Vals, param2Vals}, extraArgs);
272 break;
273 }
274 case coshBasis: {
276 {xVals, param1Vals, param2Vals}, extraArgs);
277 break;
278 }
279 default: R__ASSERT(0);
280 }
281}
282
283
284////////////////////////////////////////////////////////////////////////////////
285/// Advertise analytical integrals for compiled basis functions and when used
286/// as p.d.f without basis function.
287
288Int_t RooTruthModel::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* /*rangeName*/) const
289{
290 switch(_basisCode) {
291
292 // Analytical integration capability of raw PDF
293 case noBasis:
294 if (matchArgs(allVars,analVars,convVar())) return 1 ;
295 break ;
296
297 // Analytical integration capability of convoluted PDF
298 case expBasisPlus:
299 case expBasisMinus:
300 case expBasisSum:
301 case sinBasisPlus:
302 case sinBasisMinus:
303 case sinBasisSum:
304 case cosBasisPlus:
305 case cosBasisMinus:
306 case cosBasisSum:
307 case linBasisPlus:
308 case quadBasisPlus:
309 case sinhBasisPlus:
310 case sinhBasisMinus:
311 case sinhBasisSum:
312 case coshBasisPlus:
313 case coshBasisMinus:
314 case coshBasisSum:
315 if (matchArgs(allVars,analVars,convVar())) return 1 ;
316 break ;
317 }
318
319 return 0 ;
320}
321
322
323namespace {
324
325// From asking WolframAlpha: integrate exp(-x/tau) over x.
326inline double indefiniteIntegralExpBasisPlus(double x, double tau, double /*dm*/)
327{
328 // Restrict to positive x
329 x = std::max(x, 0.0);
330 return -tau * std::exp(-x / tau);
331}
332
333// From asking WolframAlpha: integrate exp(-x/tau)* x / tau over x.
334inline double indefiniteIntegralLinBasisPlus(double x, double tau, double /*dm*/)
335{
336 // Restrict to positive x
337 x = std::max(x, 0.0);
338 return -(tau + x) * std::exp(-x / tau);
339}
340
341// From asking WolframAlpha: integrate exp(-x/tau) * (x / tau)^2 over x.
342inline double indefiniteIntegralQuadBasisPlus(double x, double tau, double /*dm*/)
343{
344 // Restrict to positive x
345 x = std::max(x, 0.0);
346 return -(std::exp(-x / tau) * (2 * tau * tau + x * x + 2 * tau * x)) / tau;
347}
348
349// A common factor that appears in the integrals of the trigonometric
350// function bases (sin and cos).
351inline double commonFactorPlus(double x, double tau, double dm)
352{
353 const double num = tau * std::exp(-x / tau);
354 const double den = dm * dm * tau * tau + 1.0;
355 return num / den;
356}
357
358// A common factor that appears in the integrals of the hyperbolic
359// trigonometric function bases (sinh and cosh).
360inline double commonFactorHyperbolicPlus(double x, double tau, double dm)
361{
362 const double num = 2 * tau * std::exp(-x / tau);
363 const double den = dm * dm * tau * tau - 4.0;
364 return num / den;
365}
366
367// From asking WolframAlpha: integrate exp(-x/tau)*sin(x*m) over x.
368inline double indefiniteIntegralSinBasisPlus(double x, double tau, double dm)
369{
370 // Restrict to positive x
371 x = std::max(x, 0.0);
372 const double fac = commonFactorPlus(x, tau, dm);
373 // Only multiply with the sine term if the coefficient is non zero,
374 // i.e. if x was not infinity. Otherwise, we are evaluating the
375 // sine of infinity, which is NAN!
376 return fac != 0.0 ? fac * (-tau * dm * std::cos(dm * x) - std::sin(dm * x)) : 0.0;
377}
378
379// From asking WolframAlpha: integrate exp(-x/tau)*cos(x*m) over x.
380inline double indefiniteIntegralCosBasisPlus(double x, double tau, double dm)
381{
382 // Restrict to positive x
383 x = std::max(x, 0.0);
384 const double fac = commonFactorPlus(x, tau, dm);
385 return fac != 0.0 ? fac * (tau * dm * std::sin(dm * x) - std::cos(dm * x)) : 0.0;
386}
387
388// From asking WolframAlpha: integrate exp(-x/tau)*sinh(x*m/2) over x.
389inline double indefiniteIntegralSinhBasisPlus(double x, double tau, double dm)
390{
391 // Restrict to positive x
392 x = std::max(x, 0.0);
393 const double fac = commonFactorHyperbolicPlus(x, tau, dm);
394 const double arg = 0.5 * dm * x;
395 return fac != 0.0 ? fac * (tau * dm * std::cosh(arg) - 2. * std::sinh(arg)) : 0.0;
396}
397
398// From asking WolframAlpha: integrate exp(-x/tau)*cosh(x*m/2) over x.
399inline double indefiniteIntegralCoshBasisPlus(double x, double tau, double dm)
400{
401 // Restrict to positive x
402 x = std::max(x, 0.0);
403 const double fac = commonFactorHyperbolicPlus(x, tau, dm);
404 const double arg = 0.5 * dm * x;
405 return fac != 0.0 ? fac * (tau * dm * std::sinh(arg) + 2. * std::cosh(arg)) : 0.0;
406}
407
408// Integrate one of the basis functions. Takes a function that represents the
409// indefinite integral, some parameters, and a flag that indicats whether the
410// basis function is symmetric or antisymmetric. This information is used to
411// evaluate the integrals for the "Minus" and "Sum" cases.
412template <class Function>
413double definiteIntegral(Function indefiniteIntegral, double xmin, double xmax, double tau, double dm,
414 RooTruthModel::BasisSign basisSign, bool isSymmetric)
415{
416 // Note: isSymmetric == false implies antisymmetric
417 if (tau == 0.0)
418 return isSymmetric ? 1.0 : 0.0;
419 double result = 0.0;
420 if (basisSign != RooTruthModel::Minus) {
421 result += indefiniteIntegral(xmax, tau, dm) - indefiniteIntegral(xmin, tau, dm);
422 }
423 if (basisSign != RooTruthModel::Plus) {
424 const double resultMinus = indefiniteIntegral(-xmax, tau, dm) - indefiniteIntegral(-xmin, tau, dm);
425 result += isSymmetric ? -resultMinus : resultMinus;
426 }
427 return result;
428}
429
430} // namespace
431
432////////////////////////////////////////////////////////////////////////////////
433/// Implement analytical integrals when used as p.d.f and for compiled
434/// basis functions.
435
436double RooTruthModel::analyticalIntegral(Int_t code, const char *rangeName) const
437{
438 // Code must be 1
439 R__ASSERT(code == 1);
440
441 // Unconvoluted PDF
442 if (_basisCode == noBasis)
443 return 1;
444
445 // Precompiled basis functions
446 BasisType basisType = (BasisType)((_basisCode == 0) ? 0 : (_basisCode / 10) + 1);
447 BasisSign basisSign = (BasisSign)(_basisCode - 10 * (basisType - 1) - 2);
448
449 const bool needsDm =
450 basisType == sinBasis || basisType == cosBasis || basisType == sinhBasis || basisType == coshBasis;
451
452 const double tau = ((RooAbsReal *)basis().getParameter(1))->getVal();
453 const double dm =
454 needsDm ? ((RooAbsReal *)basis().getParameter(2))->getVal() : std::numeric_limits<Double_t>::quiet_NaN();
455
456 const double xmin = x.min(rangeName);
457 const double xmax = x.max(rangeName);
458
459 auto integrate = [&](auto indefiniteIntegral, bool isSymmetric) {
460 return definiteIntegral(indefiniteIntegral, xmin, xmax, tau, dm, basisSign, isSymmetric);
461 };
462
463 switch (basisType) {
464 case expBasis: return integrate(indefiniteIntegralExpBasisPlus, /*isSymmetric=*/true);
465 case sinBasis: return integrate(indefiniteIntegralSinBasisPlus, /*isSymmetric=*/false);
466 case cosBasis: return integrate(indefiniteIntegralCosBasisPlus, /*isSymmetric=*/true);
467 case linBasis: return integrate(indefiniteIntegralLinBasisPlus, /*isSymmetric=*/false);
468 case quadBasis: return integrate(indefiniteIntegralQuadBasisPlus, /*isSymmetric=*/true);
469 case sinhBasis: return integrate(indefiniteIntegralSinhBasisPlus, /*isSymmetric=*/false);
470 case coshBasis: return integrate(indefiniteIntegralCoshBasisPlus, /*isSymmetric=*/true);
471 default: R__ASSERT(0);
472 }
473
474 R__ASSERT(0);
475 return 0;
476}
477
478
479////////////////////////////////////////////////////////////////////////////////
480
482(const RooAbsAnaConvPdf& convPdf, const RooArgSet &vars, const RooDataSet *prototype,
483 const RooArgSet* auxProto, bool verbose) const
484{
485 RooArgSet forceDirect(convVar()) ;
486 return new RooGenContext(convPdf, vars, prototype, auxProto, verbose, &forceDirect);
487}
488
489
490
491////////////////////////////////////////////////////////////////////////////////
492/// Advertise internal generator for observable x
493
494Int_t RooTruthModel::getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, bool /*staticInitOK*/) const
495{
496 if (matchArgs(directVars,generateVars,x)) return 1 ;
497 return 0 ;
498}
499
500
501
502////////////////////////////////////////////////////////////////////////////////
503/// Implement internal generator for observable x,
504/// x=0 for all events following definition
505/// of delta function
506
508{
509 R__ASSERT(code==1) ;
510 double zero(0.) ;
511 x = zero ;
512 return;
513}
#define ClassImp(name)
Definition Rtypes.h:377
#define R__ASSERT(e)
Definition TError.h:118
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:110
float xmin
float xmax
Double_t(* Function)(Double_t)
Definition Functor.C:4
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:79
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:208
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.
RooAbsRealLValue is the common abstract base class for objects that represent a real value that may a...
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:59
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:103
bool matchArgs(const RooArgSet &allDeps, RooArgSet &numDeps, const RooArgProxy &a) const
Utility function for use in getAnalyticalIntegral().
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:55
RooDataSet is a container class to hold unbinned data.
Definition RooDataSet.h:57
RooBatchCompute::Config config(RooAbsArg const *arg) const
Definition DataMap.cxx:40
std::span< const double > at(RooAbsArg const *arg, RooAbsArg const *caller=nullptr)
Definition DataMap.cxx:22
A RooFormulaVar is a generic implementation of a real-valued object, which takes a RooArgList of serv...
RooAbsArg * getParameter(const char *name) const
Return pointer to parameter with given name.
Class RooGenContext implement a universal generator context for all RooAbsPdf classes that do not hav...
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.
Implements a RooResolution model that corresponds to a delta function.
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.
void computeBatch(double *output, size_t size, RooFit::Detail::DataMap const &) const override
Base function for computing multiple values of a RooAbsReal.
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.
void changeBasis(RooFormulaVar *basis) override
Changes associated bases function to 'inBasis'.
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:48
Double_t x[n]
Definition legend1.C:17
std::vector< double > ArgVector
void compute(Config cfg, Computer comp, RestrictArr output, size_t size, const VarVector &vars, ArgVector &extraArgs)
static void output()