MINT2
RooGaussEfficiencyModel.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  * Project: RooFit *
3  * Package: RooFitModels *
4  * @(#)root/roofit:$Id: RooGaussModel.cxx 44982 2012-07-10 08:36:13Z moneta $
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 
18 //
19 // BEGIN_HTML
20 // Class RooGaussModel implements a RooResolutionModel that models a Gaussian
21 // distribution. Object of class RooGaussModel can be used
22 // for analytical convolutions with classes inheriting from RooAbsAnaConvPdf
23 // After the convolution is applied, the result is multiplied with an
24 // efficiency, which can be any implementation of the RooAbsGaussModelEfficiency
25 // interface
26 // END_HTML
27 //
28 #include <memory>
29 
30 #include "RVersion.h"
31 
32 #include "RooMath.h"
33 #include "RooRealConstant.h"
34 #include "RooRandom.h"
35 
39 
40 #if __cplusplus < 201102L
41 #define myunique_ptr std::auto_ptr
42 #else
43 template <typename T>
44 using myunique_ptr = std::unique_ptr<T>;
45 #endif
46 
47 using namespace std;
48 
49 namespace {
50  enum basisType { noBasis=0 , expBasis= 3
51  , sinBasis=13, cosBasis=23
52  , sinhBasis=63, coshBasis=53 };
53  static const Double_t rootpi(sqrt(TMath::Pi())) ;
54 
55  std::complex<double> evalApprox(Double_t x, const std::complex<double>& z) {
56  // compute exp(-x^2)cwerf(-i(z-x)), cwerf(z) = exp(-z^2)erfc(-iz)
57  // use the approximation: erfc(z) = exp(-z*z)/(sqrt(pi)*z)
58  // to explicitly cancel the divergent exp(y*y) behaviour of
59  // CWERF for z = x + i y with large negative y
60  static const std::complex<double> mi(0,-1);
61  std::complex<double> zp = mi*(z-x);
62  std::complex<double> zsq = zp*zp;
63  std::complex<double> v = -zsq - x*x;
64  std::complex<double> iz(z.imag()+x,z.real()-x); // ???
65  return exp(v)*(exp(zsq)/(iz*rootpi) + 1.)*2. ;
66  }
67 
68  // Calculate Re[exp(-x^2) cwerf(i (z-x) )], taking care of numerical instabilities
69  Double_t evalRe(Double_t x, const std::complex<double>& z) {
70  Double_t re = z.real()-x;
71 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,34,8)
72  return (re>-5.0) ? RooMath::faddeeva_fast(std::complex<double>(-z.imag(),re)).real()*exp(-x*x)
73  : evalApprox(x,z).real() ;
74 #else
75  return (re>-5.0) ? RooMath::FastComplexErrFunc(RooComplex(-z.imag(),re)).re()*exp(-x*x)
76  : evalApprox(x,z).real() ;
77 #endif
78  }
79 
80  // Calculate Im[exp(-x^2) cwerf(i(z-x))], taking care of numerical instabilities
81  Double_t evalIm(Double_t x, const std::complex<double>& z) {
82  Double_t re = z.real()-x;
83 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,34,8)
84  return (re>-5.0) ? RooMath::faddeeva_fast(std::complex<double>(-z.imag(),re)).imag()*exp(-x*x)
85  : evalApprox(x,z).imag() ;
86 #else
87  return (re>-5.0) ? RooMath::FastComplexErrFunc(RooComplex(-z.imag(),re)).im()*exp(-x*x)
88  : evalApprox(x,z).imag() ;
89 #endif
90  }
91 
92 }
93 
94 
95 //_____________________________________________________________________________
96 RooGaussEfficiencyModel::RooGaussEfficiencyModel(const char *name, const char *title
97  , RooRealVar& x, RooAbsGaussModelEfficiency& _eff
98  , RooAbsReal& _mean, RooAbsReal& _sigma )
99  : RooResolutionModel(name, title, x),
101  _flatSFInt(kFALSE),
102  eff("eff","Spline describing efficiency",this,_eff),
103  mean("mean","Mean",this,_mean),
104  sigma("sigma","Width",this,_sigma),
105  msf("msf","Mean Scale Factor",this,RooRealConstant::value(1.0)),
106  ssf("ssf","Sigma Scale Factor",this,RooRealConstant::value(1.0))
107 {
108  // make sure 'x' matches the eff argument!
109  myunique_ptr<RooArgSet> svar( eff.arg().getVariables() );
110  assert( svar->contains( convVar() ) );
111 }
112 
113 //_____________________________________________________________________________
114 RooGaussEfficiencyModel::RooGaussEfficiencyModel(const char *name, const char *title
115  , RooRealVar& x, RooAbsGaussModelEfficiency& _eff
116  , RooAbsReal& _mean, RooAbsReal& _sigma
117  , RooAbsReal& _meanSF, RooAbsReal& _sigmaSF)
118  : RooResolutionModel(name,title,x),
120  _flatSFInt(kFALSE),
121  eff("eff","Spline describing efficiency",this,_eff),
122  mean("mean","Mean",this,_mean),
123  sigma("sigma","Width",this,_sigma),
124  msf("msf","Mean Scale Factor",this,_meanSF),
125  ssf("ssf","Sigma Scale Factor",this,_sigmaSF)
126 {
127  // make sure 'x' matches the spline argument!
128  myunique_ptr<RooArgSet> svar( eff.arg().getVariables() );
129  assert( svar->contains( convVar() ) );
130 }
131 
132 //_____________________________________________________________________________
134  const char* name)
135  : RooResolutionModel(other,name),
137  _flatSFInt(other._flatSFInt),
138  eff("eff",this,other.eff),
139  mean("mean",this,other.mean),
140  sigma("sigma",this,other.sigma),
141  msf("msf",this,other.msf),
142  ssf("ssf",this,other.ssf)
143 {
144 }
145 
146 //_____________________________________________________________________________
148 {
149  // Destructor
150 }
151 
152 //_____________________________________________________________________________
153 Int_t RooGaussEfficiencyModel::basisCode(const char* name) const
154 {
155  if (!TString("exp(-@0/@1)" ).CompareTo(name)) return expBasis;
156  if (!TString("exp(-@0/@1)*sin(@0*@2)" ).CompareTo(name)) return sinBasis;
157  if (!TString("exp(-@0/@1)*cos(@0*@2)" ).CompareTo(name)) return cosBasis;
158  if (!TString("exp(-@0/@1)*cosh(@0*@2/2)").CompareTo(name)) return coshBasis;
159  if (!TString("exp(-@0/@1)*sinh(@0*@2/2)").CompareTo(name)) return sinhBasis;
160  return 0 ;
161 }
162 
163 //_____________________________________________________________________________
164 const RooAbsReal* RooGaussEfficiencyModel::efficiency() const
165 {
166  return &eff.arg();
167 }
168 
169 //_____________________________________________________________________________
171  // Return pointer to pdf in product
172  // verify whether efficiency depends on additional observables!!!
173  return new RooArgSet(convVar());
174 }
175 
176 //_____________________________________________________________________________
177 std::complex<double> RooGaussEfficiencyModel::evalInt(Double_t umin, Double_t umax,
178  Double_t scale, Double_t offset,
179  const std::complex<double>& z) const
180 {
181  const RooAbsGaussModelEfficiency &sp = dynamic_cast<const RooAbsGaussModelEfficiency&>( eff.arg() );
182  return sp.productAnalyticalIntegral( umin, umax, scale, offset, z) ;
183 }
184 
185 //_____________________________________________________________________________
187 {
188  basisType basisCode = (basisType) _basisCode ;
189  Double_t tau = (basisCode!=noBasis) ? ((RooAbsReal*)basis().getParameter(1))->getVal() : 0 ;
190  Double_t omega = (basisCode==sinBasis || basisCode==cosBasis) ? ((RooAbsReal*)basis().getParameter(2))->getVal() : 0 ;
191  Double_t dGamma = (basisCode==sinhBasis || basisCode==coshBasis) ? ((RooAbsReal*)basis().getParameter(2))->getVal() : 0 ;
192  if (basisCode == coshBasis && basisCode!=noBasis && dGamma==0 ) basisCode = expBasis;
193 
194  Double_t scale = sigma*ssf*TMath::Sqrt2();
195  Double_t u = (x-mean*msf)/scale;
196  // *** 1st form: Straight Gaussian, used for unconvoluted PDF or expBasis with 0 lifetime ***
197  if (basisCode==noBasis || ((basisCode==expBasis || basisCode==cosBasis) && tau==0)) {
198  if (verboseEval()>2) cout << "RooGaussEfficiencyModel::evaluate(" << GetName() << ") 1st form" << endl ;
199  Double_t eff=efficiency()->getVal();
200  if (TMath::IsNaN(eff))
201  cxcoutE(Tracing) << "RooGaussEfficiencyModel::evaluate(" << GetName()
202  << ") got nan during efficiency " << endl;
203  return eff * exp(-u*u)/(scale*rootpi) ; // ???
204  }
205 
206  // *** 2nd form: 0, used for sinBasis, linBasis, and quadBasis with tau=0 ***
207  if (tau==0) {
208  if (verboseEval()>2) cout << "RooGaussEfficiencyModel::evaluate(" << GetName() << ") 2nd form" << endl ;
209  return 0. ;
210  }
211  std::complex<double> z( double(1)/tau, -omega ); z*=0.5*scale;
212 
213  Double_t val(0);
214  if (verboseEval()>2) cout << "RooGaussEfficiencyModel::evaluate(" << GetName() << ") basisCode = " << basisCode << " z = " << z << ", u = " << u << endl ;
215 
216  switch (basisCode) {
217  case expBasis:
218  case cosBasis:
219  val += evalRe(u,z);
220  break;
221  case sinBasis:
222  val += z.imag()!=0 ? evalIm(u,z) : 0;
223  break;
224  case coshBasis:
225  case sinhBasis: {
226  std::complex<double> y( scale * dGamma / 4 , 0 );
227  val += ( evalRe(u,z-y)
228  + ( basisCode == coshBasis ? +1 : -1 )*evalRe(u,z+y) )/2;
229  break;
230  }
231  default:
232  assert(0);
233  }
234  if (TMath::IsNaN(val))
235  cxcoutE(Tracing) << "RooGaussEfficiencyModel::evaluate(" << GetName()
236  << ") got nan during basisCode = " << basisCode << endl;
237  Double_t _eff=eff;
238  if (TMath::IsNaN(_eff))
239  cxcoutE(Tracing) << "RooGaussEfficiencyModel::evaluate(" << GetName()
240  << ") got nan during efficiency " << endl;
241  return _eff*val;
242 }
243 
244 
245 Double_t RooGaussEfficiencyModel::evaluate(Int_t basisCodeInt, Double_t tau, Double_t omega, Double_t dGamma ) const
246 {
247  basisType basisCode = (basisType) basisCodeInt ;
248  tau = (basisCode!=noBasis) ? tau : 0 ;
249  omega = (basisCode==sinBasis || basisCode==cosBasis) ? omega : 0 ;
250  dGamma = (basisCode==sinhBasis || basisCode==coshBasis) ? dGamma : 0 ;
251  if (basisCode == coshBasis && basisCode!=noBasis && dGamma==0 ) basisCode = expBasis;
252 
253  Double_t scale = sigma*ssf*TMath::Sqrt2();
254  Double_t u = (x-mean*msf)/scale;
255  // *** 1st form: Straight Gaussian, used for unconvoluted PDF or expBasis with 0 lifetime ***
256  if (basisCode==noBasis || ((basisCode==expBasis || basisCode==cosBasis) && tau==0)) {
257  if (verboseEval()>2) cout << "RooGaussEfficiencyModel::evaluate(" << GetName() << ") 1st form" << endl ;
258  Double_t eff=efficiency()->getVal();
259  if (TMath::IsNaN(eff))
260  cxcoutE(Tracing) << "RooGaussEfficiencyModel::evaluate(" << GetName()
261  << ") got nan during efficiency " << endl;
262  return eff * exp(-u*u)/(scale*rootpi) ; // ???
263  }
264 
265  // *** 2nd form: 0, used for sinBasis, linBasis, and quadBasis with tau=0 ***
266  if (tau==0) {
267  if (verboseEval()>2) cout << "RooGaussEfficiencyModel::evaluate(" << GetName() << ") 2nd form" << endl ;
268  return 0. ;
269  }
270  std::complex<double> z( double(1)/tau, -omega ); z*=0.5*scale;
271 
272  Double_t val(0);
273  if (verboseEval()>2) cout << "RooGaussEfficiencyModel::evaluate(" << GetName() << ") basisCode = " << basisCode << " z = " << z << ", u = " << u << endl ;
274 
275  switch (basisCode) {
276  case expBasis:
277  case cosBasis:
278  val += evalRe(u,z);
279  break;
280  case sinBasis:
281  val += z.imag()!=0 ? evalIm(u,z) : 0;
282  break;
283  case coshBasis:
284  case sinhBasis: {
285  std::complex<double> y( scale * dGamma / 4 , 0 );
286  val += ( evalRe(u,z-y)
287  + ( basisCode == coshBasis ? +1 : -1 )*evalRe(u,z+y) )/2;
288  break;
289  }
290  default:
291  assert(0);
292  }
293  if (TMath::IsNaN(val))
294  cxcoutE(Tracing) << "RooGaussEfficiencyModel::evaluate(" << GetName()
295  << ") got nan during basisCode = " << basisCode << endl;
296  Double_t _eff=eff;
297  if (TMath::IsNaN(_eff))
298  cxcoutE(Tracing) << "RooGaussEfficiencyModel::evaluate(" << GetName()
299  << ") got nan during efficiency " << endl;
300  //return val;
301  return _eff*val;
302 }
303 
304 
305 //_____________________________________________________________________________
306 Int_t RooGaussEfficiencyModel::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* /*rangeName*/) const
307 {
308  switch(_basisCode) {
309  // Analytical integration capability of raw PDF
310  case noBasis:
311  // Optionally advertise flat integral over sigma scale factor
312  if (_flatSFInt && matchArgs(allVars,analVars,RooArgSet(convVar(),ssf.arg()))) return 2 ;
313  if (matchArgs(allVars,analVars,convVar())) return 1 ;
314  break ;
315 
316  // Analytical integration capability of convoluted PDF
317  case expBasis:
318  case sinBasis:
319  case cosBasis:
320  case coshBasis:
321  case sinhBasis:
322  // Optionally advertise flat integral over sigma scale factor
323  if (_flatSFInt && matchArgs(allVars,analVars,RooArgSet(convVar(),ssf.arg()))) return 2 ;
324  if (matchArgs(allVars,analVars,convVar())) return 1 ;
325  break ;
326  }
327  return 0 ;
328 }
329 
330 //_____________________________________________________________________________
331 Double_t RooGaussEfficiencyModel::analyticalIntegral(Int_t code, const char* rangeName) const
332 {
333  // Code must be 1 or 2
334  assert(code==1||code==2) ;
335  Double_t ssfInt( code==2 ? (ssf.max(rangeName)-ssf.min(rangeName)) : 1.0 );
336 
337  basisType basisCode = (basisType) _basisCode ;
338  Double_t tau = (basisCode!=noBasis) ? ((RooAbsReal*)basis().getParameter(1))->getVal() : 0 ;
339  Double_t omega = (basisCode==sinBasis || basisCode==cosBasis) ? ((RooAbsReal*)basis().getParameter(2))->getVal() : 0 ;
340  Double_t dGamma = (basisCode==sinhBasis || basisCode==coshBasis) ? ((RooAbsReal*)basis().getParameter(2))->getVal() : 0 ;
341  if (basisCode == coshBasis && basisCode!=noBasis && dGamma==0 ) basisCode = expBasis;
342 
343  Double_t scale = sigma*ssf*TMath::Sqrt2();
344  Double_t offset = mean*msf;
345  Double_t umin = (x.min(rangeName)-offset)/scale;
346  Double_t umax = (x.max(rangeName)-offset)/scale;
347 
348  if (basisCode==noBasis || ((basisCode==expBasis || basisCode==cosBasis) && tau==0)) {
349  if (verboseEval()>0) cout << "RooGaussEfficiencyModel::analyticalIntegral(" << GetName() << ") 1st form" << endl ;
350  Double_t result = 0.5*(RooMath::erf( umax )-RooMath::erf( umin )) ;
351  if (TMath::IsNaN(result)) { cxcoutE(Tracing) << "RooGaussEfficiencyModel::analyticalIntegral(" << GetName() << ") got nan during case 1 " << endl; }
352  return result*ssfInt ; // ???
353  }
354  if (tau==0) {
355  if (verboseEval()>0) cout << "RooGaussEfficiencyModel::analyticalIntegral(" << GetName() << ") 2nd form" << endl ;
356  return 0. ;
357  }
358 
359  std::complex<double> z( double(1)/tau, -omega ); z=0.5*z*scale;
360 
361  if (verboseEval()>0) cout << "RooGaussEfficiencyModel::analyticalIntegral(" << GetName() << ") basisCode = " << basisCode << " z = " << z << endl ;
362 
363  Double_t result(0);
364  switch (basisCode) {
365  case expBasis:
366  case cosBasis:
367  result += evalInt(umin,umax,scale,offset,z).real();
368  break;
369  case sinBasis:
370  result += z.imag()!=0 ? evalInt(umin,umax,scale,offset,z).imag() : 0 ;
371  break;
372  case coshBasis:
373  case sinhBasis: {
374  std::complex<double> y( scale * dGamma / 4 , 0 );
375  result += 0.5 * ( evalInt(umin,umax,scale,offset,z-y).real()
376  + ( basisCode == coshBasis ? +1 : -1 )*evalInt(umin,umax,scale,offset,z+y).real() );
377  break;
378  }
379  default:
380  assert(0) ;
381  }
382  if (TMath::IsNaN(result)) { cxcoutE(Tracing) << "RooGaussEfficiencyModel::analyticalIntegral("
383  << GetName() << ") got nan for basisCode = "
384  << basisCode << endl;
385  }
386  return scale*result*ssfInt;
387 }
388 
389 
390 Double_t RooGaussEfficiencyModel::analyticalIntegral(Int_t basisCodeInt, Double_t tau, Double_t omega, Double_t dGamma, Int_t code, const char* rangeName) const
391 {
392  // Code must be 1 or 2
393  assert(code==1||code==2) ;
394  Double_t ssfInt( code==2 ? (ssf.max(rangeName)-ssf.min(rangeName)) : 1.0 );
395 
396  basisType basisCode = (basisType) basisCodeInt ;
397  tau = (basisCode!=noBasis) ? tau : 0 ;
398  omega = (basisCode==sinBasis || basisCode==cosBasis) ? omega : 0 ;
399  dGamma = (basisCode==sinhBasis || basisCode==coshBasis) ? dGamma : 0 ;
400  if (basisCode == coshBasis && basisCode!=noBasis && dGamma==0 ) basisCode = expBasis;
401 
402  Double_t scale = sigma*ssf*TMath::Sqrt2();
403  Double_t offset = mean*msf;
404  Double_t umin = (x.min(rangeName)-offset)/scale;
405  Double_t umax = (x.max(rangeName)-offset)/scale;
406 
407  if (basisCode==noBasis || ((basisCode==expBasis || basisCode==cosBasis) && tau==0)) {
408  if (verboseEval()>0) cout << "RooGaussEfficiencyModel::analyticalIntegral(" << GetName() << ") 1st form" << endl ;
409  Double_t result = 0.5*(RooMath::erf( umax )-RooMath::erf( umin )) ;
410  if (TMath::IsNaN(result)) { cxcoutE(Tracing) << "RooGaussEfficiencyModel::analyticalIntegral(" << GetName() << ") got nan during case 1 " << endl; }
411  return result*ssfInt ; // ???
412  }
413  if (tau==0) {
414  if (verboseEval()>0) cout << "RooGaussEfficiencyModel::analyticalIntegral(" << GetName() << ") 2nd form" << endl ;
415  return 0. ;
416  }
417 
418  std::complex<double> z( double(1)/tau, -omega ); z=0.5*z*scale;
419 
420  if (verboseEval()>0) cout << "RooGaussEfficiencyModel::analyticalIntegral(" << GetName() << ") basisCode = " << basisCode << " z = " << z << endl ;
421 
422  Double_t result(0);
423  switch (basisCode) {
424  case expBasis:
425  case cosBasis:
426  result += evalInt(umin,umax,scale,offset,z).real();
427  break;
428  case sinBasis:
429  result += z.imag()!=0 ? evalInt(umin,umax,scale,offset,z).imag() : 0 ;
430  break;
431  case coshBasis:
432  case sinhBasis: {
433  std::complex<double> y( scale * dGamma / 4 , 0 );
434  result += 0.5 * ( evalInt(umin,umax,scale,offset,z-y).real()
435  + ( basisCode == coshBasis ? +1 : -1 )*evalInt(umin,umax,scale,offset,z+y).real() );
436  break;
437  }
438  default:
439  assert(0) ;
440  }
441  if (TMath::IsNaN(result)) { cxcoutE(Tracing) << "RooGaussEfficiencyModel::analyticalIntegral("
442  << GetName() << ") got nan for basisCode = "
443  << basisCode << endl;
444  }
445  return scale*result*ssfInt;
446 }
447 
448 
449 //_____________________________________________________________________________
451 (const RooAbsAnaConvPdf& convPdf, const RooArgSet &vars, const RooDataSet *prototype,
452  const RooArgSet* auxProto, Bool_t verbose) const
453 {
454  return new RooEffConvGenContext(convPdf, vars, prototype, auxProto, verbose);
455 }
456 
457 //_____________________________________________________________________________
458 Bool_t RooGaussEfficiencyModel::isDirectGenSafe(const RooAbsArg& arg) const
459 {
460  return (!TString(convVar().GetName()).CompareTo(arg.GetName()))
461  || RooResolutionModel::isDirectGenSafe(arg);
462 }
463 
464 //_____________________________________________________________________________
465 Int_t RooGaussEfficiencyModel::getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, Bool_t /*staticInitOK*/) const
466 {
467  if (matchArgs(directVars,generateVars,x)) { return 1 ; }
468  return 0 ;
469 }
470 
471 //_____________________________________________________________________________
473 {
474  if (code != 1) {
475  coutE(InputArguments) << "RooGaussEfficiencyModel::generateEvent("
476  << GetName()<< "): argument \"code\" can only have value 1"
477  << std::endl;
478  assert(code==1);
479  }
480 
481  Double_t xmin = x.min();
482  Double_t xmax = x.max();
483  Double_t m = mean*msf;
484  Double_t s = sigma*ssf;
485  TRandom *generator = RooRandom::randomGenerator();
486  while(true) {
487  Double_t xgen = generator->Gaus(m,s);
488  if (xgen<xmax && xgen>xmin) {
489  x = xgen ; return ;
490  }
491  }
492 }
virtual RooAbsGenContext * modelGenContext(const RooAbsAnaConvPdf &convPdf, const RooArgSet &vars, const RooDataSet *prototype=0, const RooArgSet *auxProto=0, Bool_t verbose=kFALSE) const
virtual RooArgSet * observables() const
virtual Double_t evaluate() const
static const double s
std::complex< double > evalInt(Double_t xmin, Double_t xmax, Double_t scale, Double_t offset, const std::complex< double > &z) const
Bool_t isDirectGenSafe(const RooAbsArg &arg) const
basisType
Definition: TimePdfMaster.h:43
virtual Double_t analyticalIntegral(Int_t code, const char *rangeName) const
static const double m
Int_t getGenerator(const RooArgSet &directVars, RooArgSet &generateVars, Bool_t staticInitOK) const
virtual std::complex< double > productAnalyticalIntegral(Double_t umin, Double_t umax, Double_t scale, Double_t offset, const std::complex< double > &z) const =0
virtual const RooAbsReal * efficiency() const
virtual Int_t getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &analVars, const char *rangeName=0) const
#define myunique_ptr
virtual Int_t basisCode(const char *name) const