MINT2
RooEffResModel.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  * Project: RooFit *
3  * Package: RooFitModels *
4  * @(#)root/roofit:$Id: RooEffResModel.cxx 44982 2012-07-10 08:36:13Z moneta $
5  * Authors: *
6  * *
7  * Redistribution and use in source and binary forms, *
8  * with or without modification, are permitted according to the terms *
9  * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
10  *
11  * 2012-08-24 imported from G. Raven's p2vv git repository - M. Schiller *
12  * 2012-09-08 re-import from upstream, with some substantial modifications *
13  * to ensure that the code does not leak memory (Manuel Schiller) *
14  * 2012-10-04 re-import from upstream, with some experimental changes, which *
15  * which are disabled by default for now... *
16  * 2017-04-11 another merge with the P2VV sources, preserving B2DXFitters *
17  * improvements *
18  *****************************************************************************/
19 
21 //
22 // BEGIN_HTML
23 // Class RooEffResModel implements a RooResolutionModel that models a EffResian
24 // distribution. Object of class RooEffResModel can be used
25 // for analytical convolutions with classes inheriting from RooAbsAnaConvPdf
26 // END_HTML
27 //
28 
29 #include <string>
30 #include <memory>
31 #include <cstdio>
32 #include <limits>
33 #include <sstream>
34 #include <cstring>
35 #include <cassert>
36 #include <cmath>
37 
38 #include <RooCustomizer.h>
39 #include <RooStringVar.h>
40 class RooAbsAnaConvPdf;
42 #include "Mint/RooEffResModel.h"
43 
44 using std::endl;
45 
46 #if __cplusplus < 201102L
47 #define myunique_ptr std::auto_ptr
48 #else
49 template <typename T>
50 using myunique_ptr = std::unique_ptr<T>;
51 #endif
52 
53 //_____________________________________________________________________________
54 #if __cplusplus < 201102L
55 #define myunique_ptr std::auto_ptr
56 #else
57 template <typename T>
58 using myunique_ptr = std::unique_ptr<T>;
59 #endif
60 
61 //_____________________________________________________________________________
63 {
64  delete _eff;
65  delete _int; // _int owns _x, _xmin, _xmax, so no need to free them
66 }
67 
68 //_____________________________________________________________________________
70 {
71  // Return list of all RooAbsArgs in cache element
72  if (_eff) return RooArgList(*_int, *_eff, *_x, *_xmin, *_xmax);
73  else return RooArgList(*_int);
74 }
75 
76 //_____________________________________________________________________________
77 
78 RooEffResModel::CacheElem::CacheElem(const RooEffResModel& parent, const RooArgSet& iset,
79  const TNamed* rangeName) :
80  _x(0), _eff(0), _xmin(0), _xmax(0), _int(0),
81  _val(std::numeric_limits<Double_t>::quiet_NaN())
82 {
83  RooRealVar& x = parent.convVar(); // binboundaries not const...
84  RooAbsReal& eff = *parent.efficiency();
85  RooAbsReal& model = parent.model();
86  // the subset of iset on which the efficiency depends
87  myunique_ptr<const RooArgSet> effInt( eff.getObservables(iset) );
88 
89  if (effInt->getSize()>1) {
90  std::cout << " got efficiency iset with more than 1 AbsArg -- not yet supported" << std::endl;
91  effInt->Print("V");
92  }
93  assert(effInt->getSize() < 2); // for now, we only do 1D efficiency histograms...
94  //TODO: instead of the above, verify whether things factorize, i.e.
95  // allow the case where the overlap of effInt and model is 1D, and
96  // all 'other' dependencies are from the efficiency only...
97  // That works because we can then ingrate the 'ceff' coefficient below
98  // over the remaining dependencies...
99  if (0 == effInt->getSize()) {
100  _int = parent.model().createIntegral(iset, RooNameReg::str(rangeName));
101  return;
102  }
103 
104  const char* rn = (rangeName ? RooNameReg::str(rangeName) : "");
105  // get bin bounds
106  const double rxmin = x.getMin(rn);
107  const double rxmax = x.getMax(rn);
108 
109  myunique_ptr<std::list<Double_t> > bounds(
110  eff.binBoundaries(x, x.getMin(), x.getMax()));
111  assert(bounds->size() > 1);
112  _bounds.reserve(bounds->size());
113  for (std::list<Double_t>::const_iterator
114  lo = bounds->begin(), hi = ++(bounds->begin());
115  hi != bounds->end(); ++hi, ++lo) {
116  if (*hi < rxmin) continue; // not there yet...
117  if (*lo > rxmax) break; // past the requested interval...
118  const double xmin = std::max(*lo, rxmin);
119  const double xmax = std::min(*hi, rxmax);
120  if (_bounds.empty())
121  _bounds.push_back(xmin);
122  _bounds.push_back(xmax);
123  }
124  assert(_bounds.size() > 1);
125  // build integral ingredients
126  _x = dynamic_cast<RooRealVar*>(x.clone((std::string(x.GetName()) + "_" +
127  rn).c_str()));
128  assert(_x);
129  RooCustomizer customizer2(model, (std::string(rn) + "_customizer2").c_str());
130  customizer2.replaceArg(x, *_x);
131  RooAbsReal* m = dynamic_cast<RooAbsReal*>(customizer2.build(false));
132  assert(m);
133  // build "customised" version of iset
134  RooArgSet custiset(iset);
135  custiset.replace(x, *_x);
136  // working range
137  _xmin = dynamic_cast<RooRealVar*>(_x->clone(
138  (std::string(_x->GetName()) + "_xmin").c_str()));
139  assert(_xmin);
140  _xmin->setVal(_bounds.front());
141  _xmax = dynamic_cast<RooRealVar*>(_x->clone(
142  (std::string(_x->GetName()) + "_xmax").c_str()));
143  assert(_xmax);
144  _xmax->setVal(_bounds.back());
145  std::string wrn(parent.GetName());
146  wrn += "_"; wrn += x.GetName(); wrn += "_"; wrn += model.GetName();
147  wrn += "_"; wrn += eff.GetName(); wrn += "_"; wrn += rn;
148  wrn += "_workRange";
149  assert(!_x->hasRange(wrn.c_str()));
150  _x->setRange(wrn.c_str(), *_xmin, *_xmax);
151  // build integral
152  _int = m->createIntegral(custiset, wrn.c_str());
153  assert(_int);
154  _int->addOwnedComponents(*m);
155  _int->addOwnedComponents(*_x);
156  _int->addOwnedComponents(*_xmin);
157  _int->addOwnedComponents(*_xmax);
158  // build efficiency in bin middle
159  RooCustomizer customizer(eff, (std::string(rn) + "_customizer").c_str());
160  customizer.replaceArg(x, *_x);
161  _eff = static_cast<RooAbsReal*>(customizer.build(false));
162  assert(_eff);
163 }
164 
165 Double_t RooEffResModel::CacheElem::getVal(const RooArgSet* nset) const
166 {
167  if (0 == _x) {
168  // handle trivial case
169  return _int->getVal(nset);
170  }
171  // see if our cached value needs recalculating
172  if (_val != _val || _eff->isValueOrShapeDirtyAndClear() ||
173  _int->isValueOrShapeDirtyAndClear()) {
174  // yes, so iterate over subranges, and sum up integral contributions
175  _val = 0.;
176  for (unsigned i = 1; i < _bounds.size(); ++i) {
177  _xmin->setVal(_bounds[i - 1]);
178  _xmax->setVal(_bounds[i]);
179  _x->setVal(0.5 * (_bounds[i - 1] + _bounds[i]));
180  _val += _int->getVal() * _eff->getVal();
181  }
182  }
183 
184  return _val;
185 }
186 
187 //_____________________________________________________________________________
188 RooEffResModel::RooEffResModel(const char *name, const char *title,
189  RooResolutionModel& __model, RooAbsReal& eff) :
190  RooResolutionModel(name,title,__model.convVar())
191  , _observables("observables", "observables", this)
192  , _model("!model","Original resolution model",this,__model)
193  , _eff("!efficiency","efficiency of convvar", this,eff)
194  , _cacheMgr(this)
195 {
196  // FIXME: assert that efficiency is a function of convVar, and there are no overlaps...
197  _observables.add(__model.convVar());
198 }
199 
200 //_____________________________________________________________________________
201 RooEffResModel::RooEffResModel(const RooEffResModel& other, const char* name) :
202  RooResolutionModel(other,name)
203  , _observables("observables", this, other._observables)
204  , _model("!model", this, other._model)
205  , _eff("!efficiency", this, other._eff)
206  , _cacheMgr(other._cacheMgr, this)
207 {
208  // copy constructor
209 }
210 
211 RooEffResModel* RooEffResModel::clone(const char* newname) const
212 { return new RooEffResModel(*this,newname); }
213 
214 //_____________________________________________________________________________
216 {
217  // Destructor
218 }
219 
220 RooArgSet* RooEffResModel::observables() const
221 { return new RooArgSet(_observables); }
222 
223 RooAbsReal* RooEffResModel::efficiency() const
224 { return static_cast<RooAbsReal*>(_eff.absArg()); }
225 
226 std::vector<RooAbsReal*> RooEffResModel::efficiencies() const
227 { return std::vector<RooAbsReal*>(1, efficiency()); }
228 
229 RooResolutionModel& RooEffResModel::model() const
230 { return dynamic_cast<RooResolutionModel&>(*_model.absArg()); }
231 
232 //_____________________________________________________________________________
234  RooFormulaVar* inBasis, RooAbsArg* owner) const
235 {
236  // Instantiate a clone of this resolution model representing a convolution with given
237  // basis function. The owners object name is incorporated in the clones name
238  // to avoid multiple convolution objects with the same name in complex PDF structures.
239  //
240  // Note: The 'inBasis' formula expression must be a RooFormulaVar that encodes the formula
241  // in the title of the object and this expression must be an exact match against the
242  // implemented basis function strings (see derived class implementation of method basisCode()
243  // for those strings
244 
245  // Check that primary variable of basis functions is our convolution variable
246  if (inBasis->getParameter(0) != x.absArg()) {
247  coutE(InputArguments) << "RooEffResModel::convolution(" << GetName() << "," << this
248  << ") convolution parameter of basis function and PDF don't match" << endl
249  << "basis->findServer(0) = " << inBasis->findServer(0) << endl
250  << "x.absArg() = " << x.absArg() << endl;
251  return 0;
252  }
253 
254  if (basisCode(inBasis->GetTitle())==0) {
255  coutE(InputArguments) << "RooEffResModel::convolution(" << GetName() << "," << this
256  << ") basis function '" << inBasis->GetTitle() << "' is not supported." << endl;
257  return 0;
258  }
259 
260  std::string newName(GetName());
261  newName += "_conv_";
262  newName += inBasis->GetName();
263  newName += "_[";
264  newName += owner->GetName();
265  newName += "]";
266 
267  RooResolutionModel *conv = model().convolution(inBasis, owner);
268 
269  std::string newTitle(conv->GetTitle());
270  newTitle += " convoluted with basis function ";
271  newTitle += inBasis->GetName();
272  conv->SetTitle(newTitle.c_str());
273 
274  RooAbsReal* eff = efficiency();
275  RooEffResModel *effConv = new RooEffResModel(newName.c_str(), newTitle.c_str(), *conv, *eff);
276  effConv->addOwnedComponents(*conv);
277  effConv->changeBasis(inBasis);
278 
279  const char* cacheParamsStr = getStringAttribute("CACHEPARAMINT");
280  if (cacheParamsStr && strlen(cacheParamsStr)) {
281  //cout << "prior has CACHEPARAMINT : " << cacheParamsStr << endl;
282  //const char* ecCacheParamsStr = effConv->getStringAttribute("CACHEPARAMINT");
283  //if (ecCacheParamsStr && strlen(ecCacheParamsStr)) cout << "bound version has CACHEPARAMINT : " << ecCacheParamsStr << endl;
284  effConv->setStringAttribute("CACHEPARAMINT",cacheParamsStr);
285  //cout << "2nd time: bound version has CACHEPARAMINT : " << effConv->getStringAttribute("CACHEPARAMINT") << endl;
286  //cout << endl << endl << endl;
287  }
288 
289  return effConv;
290 }
291 
292 //_____________________________________________________________________________
293 Int_t RooEffResModel::basisCode(const char* name) const
294 {
295  return model().basisCode(name);
296 }
297 
298 //_____________________________________________________________________________
299 Double_t RooEffResModel::evaluate() const
300 {
301  Double_t mod = model().getVal();
302  // TODO: replace this by the discretized version, i.e. replace convVar by
303  // customized middle of bin... this in order to ensure evaluate &
304  // analyticalIntegral are consistent (in case eff is not discretized!!!)
305  Double_t eps = efficiency()->getVal();
306  return eps * mod;
307 }
308 
309 //_____________________________________________________________________________
310 Bool_t RooEffResModel::forceAnalyticalInt(const RooAbsArg& /*dep*/) const
311 {
312  // Force RooRealIntegral to offer all observables for internal integration
313  return kTRUE;
314 }
315 
316 //_____________________________________________________________________________
318  RooArgSet& allVars, RooArgSet& analVars, const char* rangeName) const
319 {
320  if (_forceNumInt) return 0;
321  analVars.add(allVars);
322  getCache(&analVars, RooNameReg::ptr(rangeName));
323  return 1 + _cacheMgr.lastIndex();
324 }
325 
326 //_____________________________________________________________________________
328  Int_t code, const char* rangeName) const
329 {
330  assert(code > 0);
331  CacheElem* cache = static_cast<CacheElem*>(_cacheMgr.getObjByIndex(code - 1));
332  if (!cache) {
333  myunique_ptr<RooArgSet> vars(getParameters(RooArgSet()));
334  myunique_ptr<RooArgSet> iset(
335  _cacheMgr.nameSet1ByIndex(code - 1)->select(*vars));
336  cache = getCache(iset.get(), RooNameReg::ptr(rangeName));
337  assert(cache!=0);
338  }
339  return cache->getVal();
340 }
341 
342 //_____________________________________________________________________________
344  const RooAbsAnaConvPdf& convPdf, const RooArgSet &vars,
345  const RooDataSet *prototype, const RooArgSet* auxProto,
346  Bool_t verbose) const
347 {
348  return new RooEffConvGenContext(convPdf, vars, prototype, auxProto, verbose);
349 }
350 
351 //_____________________________________________________________________________
353  const RooArgSet& directVars, RooArgSet &generateVars,
354  Bool_t staticInitOK) const
355 {
356  return model().getGenerator(directVars, generateVars, staticInitOK);
357 }
358 
359 //_____________________________________________________________________________
361 {
362  model().initGenerator(code);
363 }
364 
365 //_____________________________________________________________________________
367 {
368  // The hit-miss on the efficiency is done at the level of the GenContext.
369  model().generateEvent(code);
370 }
371 
372 //_____________________________________________________________________________
373 const RooArgList& RooEffResModel::getIntegralRanges(const RooArgSet& iset,
374  const char* rangeName) const
375 {
376  rangeName = rangeName ? rangeName : "default";
377  RangeMap::const_iterator it = _ranges.find(rangeName);
378  if (it != _ranges.end()) return *it->second;
379 
380  RooRealVar& x = static_cast<RooRealVar&>(convVar());
381  const Double_t xmin = x.getMin(rangeName);
382  const Double_t xmax = x.getMax(rangeName);
383 
384  RooArgList* ranges = new RooArgList;
385  myunique_ptr<std::list<Double_t> > bounds(efficiency()->binBoundaries(x, x.getMin(), x.getMax()));
386  if (!bounds.get()) {
387  std::string s;
388  s += "RooEffResModel("; s += GetName(); s += "): specified efficiency ";
389  s += efficiency()->GetName(); s += " does not provide binBoundaries...";
390  std::cout << s << std::endl;
391  throw s;
392  }
393  std::list<Double_t>::const_iterator lo, hi = bounds->begin();
394  std::stringstream strange;
395  for (unsigned int i = 0; i + 1 < bounds->size();++i) {
396  lo = hi++;
397  if (*hi < xmin) continue; // not there yet...
398  if (*lo > xmax) break; // past the requested interval...
399  const Double_t thisxmin = std::max(*lo, xmin);
400  const Double_t thisxmax = std::min(*hi, xmax);
401 
402  // add eff name, as it specifies the boundaries...
403  strange.str("R");
404  strange << i << "_" << x.GetName() << "_" << efficiency()->GetName();
405 
406  // Add original rangeName if there is one
407  if (rangeName) strange << "_" << rangeName;
408  strange << "_I_" << RooNameSet(iset).content();
409  const std::string trange = strange.str();
410  const char* range = trange.c_str();
411 
412  // Create a new name for the range
413  // check if already exists and matches..
414  if (!x.hasRange(range)) {
415  x.setRange(range, thisxmin, thisxmax);
416  }
417  assert(x.getMin(range)==thisxmin);
418  assert(x.getMax(range)==thisxmax);
419  ranges->addOwned(*new RooStringVar(range, range, range));
420  }
421  std::pair<RangeMap::iterator, bool> r = _ranges.insert(
422  std::make_pair(std::string(rangeName), ranges));
423  assert(r.second);
424  return *r.first->second;
425 }
426 
427 //_____________________________________________________________________________
429  const RooArgSet *iset, const TNamed *rangeName) const
430 {
431  Int_t sterileIndex(-1);
432  CacheElem* cache = (CacheElem*) _cacheMgr.getObj(iset, &sterileIndex, rangeName);
433  if (cache) return cache;
434  _cacheMgr.setObj(iset, new CacheElem( *this, *iset, rangeName), rangeName);
435  return getCache(iset, rangeName);
436 }
virtual void generateEvent(Int_t code)
#define myunique_ptr
virtual Int_t getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &analVars, const char *rangeName=0) const
std::vector< double > _bounds
static const double s
virtual RooArgSet * observables() const
Return pointer to pdf in product.
virtual RooResolutionModel & model() const
const RooArgList & getIntegralRanges(const RooArgSet &iset, const char *rangeName=0) const
virtual Double_t evaluate() const
virtual RooEffResModel * convolution(RooFormulaVar *inBasis, RooAbsArg *owner) const
virtual Bool_t forceAnalyticalInt(const RooAbsArg &dep) const
virtual std::vector< RooAbsReal * > efficiencies() const
Return pointer to pdf in product.
virtual Int_t basisCode(const char *name) const
virtual RooEffResModel * clone(const char *newname) const
virtual void initGenerator(Int_t code)
virtual Double_t analyticalIntegral(Int_t code, const char *rangeName) const
static const double m
Double_t getVal(const RooArgSet *nset=0) const
RooRealProxy _model
virtual ~RooEffResModel()
CacheElem(const RooEffResModel &parent, const RooArgSet &iset, const TNamed *rangeName)
virtual RooAbsReal * efficiency() const
Return pointer to pdf in product.
virtual RooArgList containedArgs(Action)
RooSetProxy _observables
virtual RooAbsGenContext * modelGenContext(const RooAbsAnaConvPdf &convPdf, const RooArgSet &vars, const RooDataSet *prototype=0, const RooArgSet *auxProto=0, Bool_t verbose=kFALSE) const
CacheElem * getCache(const RooArgSet *iset, const TNamed *rangeName=0) const
RooRealProxy _eff
RooObjCacheManager _cacheMgr
virtual Int_t getGenerator(const RooArgSet &directVars, RooArgSet &generateVars, Bool_t staticInitOK=kTRUE) const