Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooProdPdf.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 RooProdPdf.cxx
19 \class RooProdPdf
20 \ingroup Roofitcore
21 
22 RooProdPdf is an efficient implementation of a product of PDFs of the form
23 \f[ \prod_{i=1}^{N} \mathrm{PDF}_i (x, \ldots) \f]
24 
25 PDFs may share observables. If that is the case any irreducible subset
26 of PDFs that share observables will be normalised with explicit numeric
27 integration as any built-in normalisation will no longer be valid.
28 
29 Alternatively, products using conditional PDFs can be defined, *e.g.*
30 
31 \f[ F(x|y) \cdot G(y), \f]
32 
33 meaning a PDF \f$ F(x) \f$ **given** \f$ y \f$ and a PDF \f$ G(y) \f$.
34 In this construction, \f$ F \f$ is only
35 normalised w.r.t \f$ x\f$, and \f$ G \f$ is normalised w.r.t \f$ y \f$. The product in this construction
36 is properly normalised.
37 
38 If exactly one of the component PDFs supports extended likelihood fits, the
39 product will also be usable in extended mode, returning the number of expected
40 events from the extendable component PDF. The extendable component does not
41 have to appear in any specific place in the list.
42 **/
43 
44 #include "RooProdPdf.h"
45 #include "RooRealProxy.h"
46 #include "RooProdGenContext.h"
47 #include "RooGenProdProj.h"
48 #include "RooProduct.h"
49 #include "RooNameReg.h"
50 #include "RooMsgService.h"
51 #include "RooFormulaVar.h"
52 #include "RooRealVar.h"
53 #include "RooAddition.h"
54 #include "RooGlobalFunc.h"
55 #include "RooConstVar.h"
56 #include "RooWorkspace.h"
57 #include "RooRangeBoolean.h"
58 #include "RooCustomizer.h"
59 #include "RooRealIntegral.h"
60 #include "RooTrace.h"
61 
62 #include <cstring>
63 #include <sstream>
64 #include <algorithm>
65 
66 #ifndef _WIN32
67 #include <strings.h>
68 #endif
69 
70 
71 #include "TSystem.h"
72 
73 using namespace std;
74 
75 ClassImp(RooProdPdf);
76 ;
77 
78 
79 
80 ////////////////////////////////////////////////////////////////////////////////
81 /// Default constructor
82 
83 RooProdPdf::RooProdPdf() :
84  _curNormSet(0),
85  _cutOff(0),
86  _extendedIndex(-1),
87  _useDefaultGen(kFALSE),
88  _refRangeName(0),
89  _selfNorm(kTRUE)
90 {
91  // Default constructor
92  TRACE_CREATE
93 }
94 
95 
96 
97 ////////////////////////////////////////////////////////////////////////////////
98 /// Dummy constructor
99 
100 RooProdPdf::RooProdPdf(const char *name, const char *title, Double_t cutOff) :
101  RooAbsPdf(name,title),
102  _cacheMgr(this,10),
103  _genCode(10),
104  _cutOff(cutOff),
105  _pdfList("!pdfs","List of PDFs",this),
106  _extendedIndex(-1),
107  _useDefaultGen(kFALSE),
108  _refRangeName(0),
109  _selfNorm(kTRUE)
110 {
111  TRACE_CREATE
112 }
113 
114 
115 
116 ////////////////////////////////////////////////////////////////////////////////
117 /// Constructor with 2 PDFs (most frequent use case).
118 ///
119 /// The optional cutOff parameter can be used as a speed optimization if
120 /// one or more of the PDF have sizable regions with very small values,
121 /// which would pull the entire product of PDFs to zero in those regions.
122 ///
123 /// After each PDF multiplication, the running product is compared with
124 /// the cutOff parameter. If the running product is smaller than the
125 /// cutOff value, the product series is terminated and remaining PDFs
126 /// are not evaluated.
127 ///
128 /// There is no magic value of the cutOff, the user should experiment
129 /// to find the appropriate balance between speed and precision.
130 /// If a cutoff is specified, the PDFs most likely to be small should
131 /// be put first in the product. The default cutOff value is zero.
132 ///
133 
134 RooProdPdf::RooProdPdf(const char *name, const char *title,
135  RooAbsPdf& pdf1, RooAbsPdf& pdf2, Double_t cutOff) :
136  RooAbsPdf(name,title),
137  _cacheMgr(this,10),
138  _genCode(10),
139  _cutOff(cutOff),
140  _pdfList("!pdfs","List of PDFs",this),
141  _extendedIndex(-1),
142  _useDefaultGen(kFALSE),
143  _refRangeName(0),
144  _selfNorm(kTRUE)
145 {
146  _pdfList.add(pdf1) ;
147  RooArgSet* nset1 = new RooArgSet("nset") ;
148  _pdfNSetList.Add(nset1) ;
149  if (pdf1.canBeExtended()) {
150  _extendedIndex = _pdfList.index(&pdf1) ;
151  }
152 
153  _pdfList.add(pdf2) ;
154  RooArgSet* nset2 = new RooArgSet("nset") ;
155  _pdfNSetList.Add(nset2) ;
156 
157  if (pdf2.canBeExtended()) {
158  if (_extendedIndex>=0) {
159  // Protect against multiple extended terms
160  coutW(InputArguments) << "RooProdPdf::RooProdPdf(" << GetName()
161  << ") multiple components with extended terms detected,"
162  << " product will not be extendible." << endl ;
163  _extendedIndex=-1 ;
164  } else {
165  _extendedIndex=_pdfList.index(&pdf2) ;
166  }
167  }
168  TRACE_CREATE
169 }
170 
171 
172 
173 ////////////////////////////////////////////////////////////////////////////////
174 /// Constructor from a list of PDFs.
175 ///
176 /// The optional cutOff parameter can be used as a speed optimization if
177 /// one or more of the PDF have sizable regions with very small values,
178 /// which would pull the entire product of PDFs to zero in those regions.
179 ///
180 /// After each PDF multiplication, the running product is compared with
181 /// the cutOff parameter. If the running product is smaller than the
182 /// cutOff value, the product series is terminated and remaining PDFs
183 /// are not evaluated.
184 ///
185 /// There is no magic value of the cutOff, the user should experiment
186 /// to find the appropriate balance between speed and precision.
187 /// If a cutoff is specified, the PDFs most likely to be small should
188 /// be put first in the product. The default cutOff value is zero.
189 
190 RooProdPdf::RooProdPdf(const char* name, const char* title, const RooArgList& inPdfList, Double_t cutOff) :
191  RooAbsPdf(name,title),
192  _cacheMgr(this,10),
193  _genCode(10),
194  _cutOff(cutOff),
195  _pdfList("!pdfs","List of PDFs",this),
196  _extendedIndex(-1),
197  _useDefaultGen(kFALSE),
198  _refRangeName(0),
199  _selfNorm(kTRUE)
200 {
201  RooFIter iter = inPdfList.fwdIterator();
202  RooAbsArg* arg ;
203  Int_t numExtended(0) ;
204  while((arg=(RooAbsArg*)iter.next())) {
205  RooAbsPdf* pdf = dynamic_cast<RooAbsPdf*>(arg) ;
206  if (!pdf) {
207  coutW(InputArguments) << "RooProdPdf::RooProdPdf(" << GetName() << ") list arg "
208  << arg->GetName() << " is not a PDF, ignored" << endl ;
209  continue ;
210  }
211  _pdfList.add(*pdf) ;
212 
213  RooArgSet* nset = new RooArgSet("nset") ;
214  _pdfNSetList.Add(nset) ;
215 
216  if (pdf->canBeExtended()) {
217  _extendedIndex = _pdfList.index(pdf) ;
218  numExtended++ ;
219  }
220  }
221 
222  // Protect against multiple extended terms
223  if (numExtended>1) {
224  coutW(InputArguments) << "RooProdPdf::RooProdPdf(" << GetName()
225  << ") WARNING: multiple components with extended terms detected,"
226  << " product will not be extendible." << endl ;
227  _extendedIndex = -1 ;
228  }
229 
230  TRACE_CREATE
231 }
232 
233 
234 
235 ////////////////////////////////////////////////////////////////////////////////
236 /// Constructor from named argument list.
237 /// \param[in] name Name used by RooFit
238 /// \param[in] title Title used for plotting
239 /// \param[in] fullPdfSet Set of "regular" PDFs that are normalised over all their observables
240 /// \param[in] argX Optional arguments according to table below.
241 ///
242 /// <table>
243 /// <tr><th> Argument <th> Description
244 /// <tr><td> `Conditional(pdfSet,depSet)` <td> Add PDF to product with condition that it
245 /// only be normalized over specified observables. Any remaining observables will be conditional observables.
246 /// </table>
247 ///
248 /// For example, given a PDF \f$ F(x,y) \f$ and \f$ G(y) \f$,
249 ///
250 /// `RooProdPdf("P", "P", G, Conditional(F,x))` will construct a 2-dimensional PDF as follows:
251 /// \f[
252 /// P(x,y) = \frac{G(y)}{\int_y G(y)} \cdot \frac{F(x,y)}{\int_x F(x,y)},
253 /// \f]
254 ///
255 /// which is a well normalised and properly defined PDF, but different from
256 /// \f[
257 /// P'(x,y) = \frac{F(x,y) \cdot G(y)}{\int_x\int_y F(x,y) \cdot G(y)}.
258 /// \f]
259 ///
260 /// In the former case, the \f$ y \f$ distribution of \f$ P \f$ is identical to that of \f$ G \f$, while
261 /// \f$ F \f$ only is used to determine the correlation between \f$ X \f$ and \f$ Y \f$. In the latter
262 /// case, the \f$ Y \f$ distribution is defined by the product of \f$ F \f$ and \f$ G \f$.
263 ///
264 /// This \f$ P(x,y) \f$ construction is analoguous to generating events from \f$ F(x,y) \f$ with
265 /// a prototype dataset sampled from \f$ G(y) \f$.
266 
267 RooProdPdf::RooProdPdf(const char* name, const char* title, const RooArgSet& fullPdfSet,
268  const RooCmdArg& arg1, const RooCmdArg& arg2,
269  const RooCmdArg& arg3, const RooCmdArg& arg4,
270  const RooCmdArg& arg5, const RooCmdArg& arg6,
271  const RooCmdArg& arg7, const RooCmdArg& arg8) :
272  RooAbsPdf(name,title),
273  _cacheMgr(this,10),
274  _genCode(10),
275  _cutOff(0),
276  _pdfList("!pdfs","List of PDFs",this),
277  _extendedIndex(-1),
278  _useDefaultGen(kFALSE),
279  _refRangeName(0),
280  _selfNorm(kTRUE)
281 {
282  RooLinkedList l ;
283  l.Add((TObject*)&arg1) ; l.Add((TObject*)&arg2) ;
284  l.Add((TObject*)&arg3) ; l.Add((TObject*)&arg4) ;
285  l.Add((TObject*)&arg5) ; l.Add((TObject*)&arg6) ;
286  l.Add((TObject*)&arg7) ; l.Add((TObject*)&arg8) ;
287 
288  initializeFromCmdArgList(fullPdfSet,l) ;
289  TRACE_CREATE
290 }
291 
292 
293 
294 ////////////////////////////////////////////////////////////////////////////////
295 /// Constructor from named argument list
296 
297 RooProdPdf::RooProdPdf(const char* name, const char* title,
298  const RooCmdArg& arg1, const RooCmdArg& arg2,
299  const RooCmdArg& arg3, const RooCmdArg& arg4,
300  const RooCmdArg& arg5, const RooCmdArg& arg6,
301  const RooCmdArg& arg7, const RooCmdArg& arg8) :
302  RooAbsPdf(name,title),
303  _cacheMgr(this,10),
304  _genCode(10),
305  _cutOff(0),
306  _pdfList("!pdfList","List of PDFs",this),
307  _extendedIndex(-1),
308  _useDefaultGen(kFALSE),
309  _refRangeName(0),
310  _selfNorm(kTRUE)
311 {
312  RooLinkedList l ;
313  l.Add((TObject*)&arg1) ; l.Add((TObject*)&arg2) ;
314  l.Add((TObject*)&arg3) ; l.Add((TObject*)&arg4) ;
315  l.Add((TObject*)&arg5) ; l.Add((TObject*)&arg6) ;
316  l.Add((TObject*)&arg7) ; l.Add((TObject*)&arg8) ;
317 
318  initializeFromCmdArgList(RooArgSet(),l) ;
319  TRACE_CREATE
320 }
321 
322 
323 
324 ////////////////////////////////////////////////////////////////////////////////
325 /// Internal constructor from list of named arguments
326 
327 RooProdPdf::RooProdPdf(const char* name, const char* title, const RooArgSet& fullPdfSet, const RooLinkedList& cmdArgList) :
328  RooAbsPdf(name,title),
329  _cacheMgr(this,10),
330  _genCode(10),
331  _cutOff(0),
332  _pdfList("!pdfs","List of PDFs",this),
333  _extendedIndex(-1),
334  _useDefaultGen(kFALSE),
335  _refRangeName(0),
336  _selfNorm(kTRUE)
337 {
338  initializeFromCmdArgList(fullPdfSet, cmdArgList) ;
339  TRACE_CREATE
340 }
341 
342 
343 
344 ////////////////////////////////////////////////////////////////////////////////
345 /// Copy constructor
346 
347 RooProdPdf::RooProdPdf(const RooProdPdf& other, const char* name) :
348  RooAbsPdf(other,name),
349  _cacheMgr(other._cacheMgr,this),
350  _genCode(other._genCode),
351  _cutOff(other._cutOff),
352  _pdfList("!pdfs",this,other._pdfList),
353  _extendedIndex(other._extendedIndex),
354  _useDefaultGen(other._useDefaultGen),
355  _refRangeName(other._refRangeName),
356  _selfNorm(other._selfNorm),
357  _defNormSet(other._defNormSet)
358 {
359  // Clone contents of normalizarion set list
360  RooFIter iter = other._pdfNSetList.fwdIterator();
361  RooArgSet* nset ;
362  while((nset=(RooArgSet*)iter.next())) {
363  RooArgSet* tmp = (RooArgSet*) nset->snapshot() ;
364  tmp->setName(nset->GetName()) ;
365  _pdfNSetList.Add(tmp) ;
366  }
367  TRACE_CREATE
368 }
369 
370 
371 
372 ////////////////////////////////////////////////////////////////////////////////
373 /// Initialize RooProdPdf configuration from given list of RooCmdArg configuration arguments
374 /// and set of 'regular' p.d.f.s in product
375 
376 void RooProdPdf::initializeFromCmdArgList(const RooArgSet& fullPdfSet, const RooLinkedList& l)
377 {
378  Int_t numExtended(0) ;
379 
380  // Process set of full PDFS
381  RooFIter siter = fullPdfSet.fwdIterator() ;
382  RooAbsPdf* pdf ;
383  while((pdf=(RooAbsPdf*)siter.next())) {
384  _pdfList.add(*pdf) ;
385  RooArgSet* nset1 = new RooArgSet("nset") ;
386  _pdfNSetList.Add(nset1) ;
387 
388  if (pdf->canBeExtended()) {
389  _extendedIndex = _pdfList.index(pdf) ;
390  numExtended++ ;
391  }
392 
393  }
394 
395  // Process list of conditional PDFs
396  RooFIter iter = l.fwdIterator();
397  RooCmdArg* carg ;
398  while((carg=(RooCmdArg*)iter.next())) {
399 
400  if (0 == strcmp(carg->GetName(), "Conditional")) {
401 
402  Int_t argType = carg->getInt(0) ;
403  RooArgSet* pdfSet = (RooArgSet*) carg->getSet(0) ;
404  RooArgSet* normSet = (RooArgSet*) carg->getSet(1) ;
405 
406  RooFIter siter2 = pdfSet->fwdIterator() ;
407  RooAbsPdf* thePdf ;
408  while ((thePdf=(RooAbsPdf*)siter2.next())) {
409  _pdfList.add(*thePdf) ;
410 
411  RooArgSet* tmp = (RooArgSet*) normSet->snapshot() ;
412  tmp->setName(0 == argType ? "nset" : "cset") ;
413  _pdfNSetList.Add(tmp) ;
414 
415  if (thePdf->canBeExtended()) {
416  _extendedIndex = _pdfList.index(thePdf) ;
417  numExtended++ ;
418  }
419 
420  }
421 
422  } else if (0 != strlen(carg->GetName())) {
423  coutW(InputArguments) << "Unknown arg: " << carg->GetName() << endl ;
424  }
425  }
426 
427  // Protect against multiple extended terms
428  if (numExtended>1) {
429  coutW(InputArguments) << "RooProdPdf::RooProdPdf(" << GetName()
430  << ") WARNING: multiple components with extended terms detected,"
431  << " product will not be extendible." << endl ;
432  _extendedIndex = -1 ;
433  }
434 
435 
436 }
437 
438 
439 
440 ////////////////////////////////////////////////////////////////////////////////
441 /// Destructor
442 
443 RooProdPdf::~RooProdPdf()
444 {
445  _pdfNSetList.Delete() ;
446  TRACE_DESTROY
447 }
448 
449 
450 
451 ////////////////////////////////////////////////////////////////////////////////
452 /// Overload getVal() to intercept normalization set for use in evaluate()
453 
454 Double_t RooProdPdf::getValV(const RooArgSet* set) const
455 {
456  _curNormSet = (RooArgSet*)set ;
457  return RooAbsPdf::getValV(set) ;
458 }
459 
460 
461 
462 ////////////////////////////////////////////////////////////////////////////////
463 /// Calculate current value of object
464 
465 Double_t RooProdPdf::evaluate() const
466 {
467  Int_t code ;
468  CacheElem* cache = (CacheElem*) _cacheMgr.getObj(_curNormSet,0,&code) ;
469 
470  // If cache doesn't have our configuration, recalculate here
471  if (!cache) {
472  code = getPartIntList(_curNormSet, nullptr) ;
473  cache = (CacheElem*) _cacheMgr.getObj(_curNormSet,0,&code) ;
474  }
475 
476 
477  return calculate(*cache) ;
478 }
479 
480 
481 
482 ////////////////////////////////////////////////////////////////////////////////
483 /// Calculate running product of pdfs terms, using the supplied
484 /// normalization set in 'normSetList' for each component
485 
486 Double_t RooProdPdf::calculate(const RooProdPdf::CacheElem& cache, Bool_t /*verbose*/) const
487 {
488  //cout << "RooProdPdf::calculate from cache" << endl ;
489 
490  if (cache._isRearranged) {
491  if (dologD(Eval)) {
492  cxcoutD(Eval) << "RooProdPdf::calculate(" << GetName() << ") rearranged product calculation"
493  << " calculate: num = " << cache._rearrangedNum->GetName() << " = " << cache._rearrangedNum->getVal() << endl ;
494 // cache._rearrangedNum->printComponentTree("",0,5) ;
495  cxcoutD(Eval) << "calculate: den = " << cache._rearrangedDen->GetName() << " = " << cache._rearrangedDen->getVal() << endl ;
496 // cache._rearrangedDen->printComponentTree("",0,5) ;
497  }
498 
499  return cache._rearrangedNum->getVal() / cache._rearrangedDen->getVal();
500  } else {
501 
502  Double_t value = 1.0;
503  assert(cache._normList.size() == cache._partList.size());
504  for (std::size_t i = 0; i < cache._partList.size(); ++i) {
505  const auto& partInt = static_cast<const RooAbsReal&>(cache._partList[i]);
506  const auto normSet = cache._normList[i].get();
507 
508  const Double_t piVal = partInt.getVal(normSet->getSize() > 0 ? normSet : nullptr);
509  value *= piVal ;
510  if (value <= _cutOff) break;
511  }
512 
513  return value ;
514  }
515 }
516 
517 RooSpan<double> RooProdPdf::evaluateBatch(std::size_t begin, std::size_t size) const {
518  int code;
519  auto cache = static_cast<CacheElem*>(_cacheMgr.getObj(_curNormSet, nullptr, &code));
520 
521  // If cache doesn't have our configuration, recalculate here
522  if (!cache) {
523  code = getPartIntList(_curNormSet, nullptr);
524  cache = static_cast<CacheElem*>(_cacheMgr.getObj(_curNormSet, nullptr, &code));
525  }
526 
527  if (cache->_isRearranged) {
528  if (dologD(Eval)) {
529  cxcoutD(Eval) << "RooProdPdf::calculate(" << GetName() << ") rearranged product calculation"
530  << " calculate: num = " << cache->_rearrangedNum->GetName() << " = " << cache->_rearrangedNum->getVal() << endl ;
531  cxcoutD(Eval) << "calculate: den = " << cache->_rearrangedDen->GetName() << " = " << cache->_rearrangedDen->getVal() << endl ;
532  }
533 
534  auto outputs = _batchData.makeWritableBatchUnInit(begin, size);
535  auto numerator = cache->_rearrangedNum->getValBatch(begin, size);
536  auto denominator = cache->_rearrangedDen->getValBatch(begin, size);
537 
538  for (std::size_t i=0; i < outputs.size(); ++i) {
539  outputs[i] = numerator[i] / denominator[i];
540  }
541 
542  return outputs;
543  } else {
544 
545  auto outputs = _batchData.makeWritableBatchInit(begin, size, 1.);
546  assert(cache->_normList.size() == cache->_partList.size());
547  for (std::size_t i = 0; i < cache->_partList.size(); ++i) {
548  const auto& partInt = static_cast<const RooAbsReal&>(cache->_partList[i]);
549  const auto normSet = cache->_normList[i].get();
550 
551  const auto partialInts = partInt.getValBatch(begin, size, normSet->getSize() > 0 ? normSet : nullptr);
552  for (std::size_t j=0; j < outputs.size(); ++j) {
553  outputs[j] *= partialInts[j];
554  }
555  }
556 
557  return outputs;
558  }
559 }
560 
561 
562 
563 ////////////////////////////////////////////////////////////////////////////////
564 /// Factorize product in irreducible terms for given choice of integration/normalization
565 
566 void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& intSet,
567  RooLinkedList& termList, RooLinkedList& normList,
568  RooLinkedList& impDepList, RooLinkedList& crossDepList,
569  RooLinkedList& intList) const
570 {
571  // List of all term dependents: normalization and imported
572  RooLinkedList depAllList;
573  RooLinkedList depIntNoNormList;
574 
575  // Setup lists for factorization terms and their dependents
576  RooArgSet* term(0);
577  RooArgSet* termNormDeps(0);
578  RooArgSet* termAllDeps(0);
579  RooArgSet* termIntDeps(0);
580  RooArgSet* termIntNoNormDeps(0);
581 
582  // Loop over the PDFs
583  RooAbsPdf* pdf;
584  RooArgSet* pdfNSetOrig;
585  for (RooFIter pdfIter = _pdfList.fwdIterator(),
586  nIter = _pdfNSetList.fwdIterator();
587  (pdfNSetOrig = (RooArgSet*) nIter.next(),
588  pdf = (RooAbsPdf*) pdfIter.next()); ) {
589  RooArgSet* pdfNSet, *pdfCSet;
590 
591  // Reduce pdfNSet to actual dependents
592  if (0 == strcmp("nset", pdfNSetOrig->GetName())) {
593  pdfNSet = pdf->getObservables(*pdfNSetOrig);
594  pdfCSet = new RooArgSet;
595  } else if (0 == strcmp("cset", pdfNSetOrig->GetName())) {
596  RooArgSet* tmp = pdf->getObservables(normSet);
597  tmp->remove(*pdfNSetOrig, kTRUE, kTRUE);
598  pdfCSet = pdfNSetOrig;
599  pdfNSet = tmp;
600  } else {
601  // Legacy mode. Interpret at NSet for backward compatibility
602  pdfNSet = pdf->getObservables(*pdfNSetOrig);
603  pdfCSet = new RooArgSet;
604  }
605 
606 
607  RooArgSet pdfNormDeps; // Dependents to be normalized for the PDF
608  RooArgSet pdfAllDeps; // All dependents of this PDF
609 
610  // Make list of all dependents of this PDF
611  RooArgSet* tmp = pdf->getObservables(normSet);
612  pdfAllDeps.add(*tmp);
613  delete tmp;
614 
615 
616 // cout << GetName() << ": pdf = " << pdf->GetName() << " pdfAllDeps = " << pdfAllDeps << " pdfNSet = " << *pdfNSet << " pdfCSet = " << *pdfCSet << endl;
617 
618  // Make list of normalization dependents for this PDF;
619  if (pdfNSet->getSize() > 0) {
620  // PDF is conditional
621  RooArgSet* tmp2 = (RooArgSet*) pdfAllDeps.selectCommon(*pdfNSet);
622  pdfNormDeps.add(*tmp2);
623  delete tmp2;
624  } else {
625  // PDF is regular
626  pdfNormDeps.add(pdfAllDeps);
627  }
628 
629 // cout << GetName() << ": pdfNormDeps for " << pdf->GetName() << " = " << pdfNormDeps << endl;
630 
631  RooArgSet* pdfIntSet = pdf->getObservables(intSet) ;
632 
633  // WVE if we have no norm deps, conditional observables should be taken out of pdfIntSet
634  if (0 == pdfNormDeps.getSize() && pdfCSet->getSize() > 0) {
635  pdfIntSet->remove(*pdfCSet, kTRUE, kTRUE);
636 // cout << GetName() << ": have no norm deps, removing conditional observables from intset" << endl;
637  }
638 
639  RooArgSet pdfIntNoNormDeps(*pdfIntSet);
640  pdfIntNoNormDeps.remove(pdfNormDeps, kTRUE, kTRUE);
641 
642 // cout << GetName() << ": pdf = " << pdf->GetName() << " intset = " << *pdfIntSet << " pdfIntNoNormDeps = " << pdfIntNoNormDeps << endl;
643 
644  // Check if this PDF has dependents overlapping with one of the existing terms
645  Bool_t done(kFALSE);
646  for (RooFIter lIter = termList.fwdIterator(),
647  ldIter = normList.fwdIterator(),
648  laIter = depAllList.fwdIterator();
649  (termNormDeps = (RooArgSet*) ldIter.next(),
650  termAllDeps = (RooArgSet*) laIter.next(),
651  term = (RooArgSet*) lIter.next()); ) {
652  // PDF should be added to existing term if
653  // 1) It has overlapping normalization dependents with any other PDF in existing term
654  // 2) It has overlapping dependents of any class for which integration is requested
655  // 3) If normalization happens over multiple ranges, and those ranges are both defined
656  // in either observable
657 
658  Bool_t normOverlap = pdfNormDeps.overlaps(*termNormDeps);
659  //Bool_t intOverlap = pdfIntSet->overlaps(*termAllDeps);
660 
661  if (normOverlap) {
662 // cout << GetName() << ": this term overlaps with term " << (*term) << " in normalization observables" << endl;
663 
664  term->add(*pdf);
665  termNormDeps->add(pdfNormDeps, kFALSE);
666  termAllDeps->add(pdfAllDeps, kFALSE);
667  if (!termIntDeps) {
668  termIntDeps = new RooArgSet("termIntDeps");
669  }
670  termIntDeps->add(*pdfIntSet, kFALSE);
671  if (!termIntNoNormDeps) {
672  termIntNoNormDeps = new RooArgSet("termIntNoNormDeps");
673  }
674  termIntNoNormDeps->add(pdfIntNoNormDeps, kFALSE);
675  done = kTRUE;
676  }
677  }
678 
679  // If not, create a new term
680  if (!done) {
681  if (!(0 == pdfNormDeps.getSize() && 0 == pdfAllDeps.getSize() &&
682  0 == pdfIntSet->getSize()) || 0 == normSet.getSize()) {
683 // cout << GetName() << ": creating new term" << endl;
684  term = new RooArgSet("term");
685  termNormDeps = new RooArgSet("termNormDeps");
686  termAllDeps = new RooArgSet("termAllDeps");
687  termIntDeps = new RooArgSet("termIntDeps");
688  termIntNoNormDeps = new RooArgSet("termIntNoNormDeps");
689 
690  term->add(*pdf);
691  termNormDeps->add(pdfNormDeps, kFALSE);
692  termAllDeps->add(pdfAllDeps, kFALSE);
693  termIntDeps->add(*pdfIntSet, kFALSE);
694  termIntNoNormDeps->add(pdfIntNoNormDeps, kFALSE);
695 
696  termList.Add(term);
697  normList.Add(termNormDeps);
698  depAllList.Add(termAllDeps);
699  intList.Add(termIntDeps);
700  depIntNoNormList.Add(termIntNoNormDeps);
701  }
702  }
703 
704  // We own the reduced version of pdfNSet
705  delete pdfNSet;
706  delete pdfIntSet;
707  if (pdfCSet != pdfNSetOrig) {
708  delete pdfCSet;
709  }
710  }
711 
712  // Loop over list of terms again to determine 'imported' observables
713  RooArgSet *normDeps, *allDeps, *intNoNormDeps;
714  for (RooFIter lIter = termList.fwdIterator(),
715  ldIter = normList.fwdIterator(),
716  laIter = depAllList.fwdIterator(),
717  innIter = depIntNoNormList.fwdIterator();
718  (normDeps = (RooArgSet*) ldIter.next(),
719  allDeps = (RooArgSet*) laIter.next(),
720  intNoNormDeps = (RooArgSet*) innIter.next(),
721  term=(RooArgSet*)lIter.next()); ) {
722  // Make list of wholly imported dependents
723  RooArgSet impDeps(*allDeps);
724  impDeps.remove(*normDeps, kTRUE, kTRUE);
725  impDepList.Add(impDeps.snapshot());
726 // cout << GetName() << ": list of imported dependents for term " << (*term) << " set to " << impDeps << endl ;
727 
728  // Make list of cross dependents (term is self contained for these dependents,
729  // but components import dependents from other components)
730  RooArgSet* crossDeps = (RooArgSet*) intNoNormDeps->selectCommon(*normDeps);
731  crossDepList.Add(crossDeps->snapshot());
732 // cout << GetName() << ": list of cross dependents for term " << (*term) << " set to " << *crossDeps << endl ;
733  delete crossDeps;
734  }
735 
736  depAllList.Delete();
737  depIntNoNormList.Delete();
738 
739  return;
740 }
741 
742 
743 
744 
745 ////////////////////////////////////////////////////////////////////////////////
746 /// Return list of (partial) integrals of product terms for integration
747 /// of p.d.f over observables iset while normalization over observables nset.
748 /// Also return list of normalization sets to be used to evaluate
749 /// each component in the list correctly.
750 
751 Int_t RooProdPdf::getPartIntList(const RooArgSet* nset, const RooArgSet* iset, const char* isetRangeName) const
752 {
753 // cout << " FOLKERT::RooProdPdf::getPartIntList(" << GetName() <<") nset = " << (nset?*nset:RooArgSet()) << endl
754 // << " _normRange = " << _normRange << endl
755 // << " iset = " << (iset?*iset:RooArgSet()) << endl
756 // << " isetRangeName = " << (isetRangeName?isetRangeName:"<null>") << endl ;
757 
758  // Check if this configuration was created before
759  Int_t sterileIdx(-1);
760 
761  CacheElem* cache = (CacheElem*) _cacheMgr.getObj(nset,iset,&sterileIdx,isetRangeName);
762  if (cache) {
763  return _cacheMgr.lastIndex();
764  }
765 
766  // Create containers for partial integral components to be generated
767  cache = new CacheElem;
768 
769  // Factorize the product in irreducible terms for this nset
770  RooLinkedList terms, norms, imp, ints, cross;
771 // cout << "RooProdPdf::getPIL -- now calling factorizeProduct()" << endl ;
772 
773 
774  // Normalization set used for factorization
775  RooArgSet factNset(nset ? (*nset) : _defNormSet);
776 // cout << GetName() << "factNset = " << factNset << endl ;
777 
778  factorizeProduct(factNset, iset ? (*iset) : RooArgSet(), terms, norms, imp, cross, ints);
779 
780  RooArgSet *norm, *integ, *xdeps, *imps;
781 
782  // Group irriducible terms that need to be (partially) integrated together
783  RooLinkedList groupedList;
784  RooArgSet outerIntDeps;
785 // cout << "RooProdPdf::getPIL -- now calling groupProductTerms()" << endl;
786  groupProductTerms(groupedList, outerIntDeps, terms, norms, imp, ints, cross);
787  RooFIter gIter = groupedList.fwdIterator();
788  RooLinkedList* group;
789 
790  // Loop over groups
791 // cout<<"FK: pdf("<<GetName()<<") Starting selecting F(x|y)!"<<endl;
792  // Find groups of type F(x|y), i.e. termImpSet!=0, construct ratio object
793  map<string, RooArgSet> ratioTerms;
794  while ((group = (RooLinkedList*) gIter.next())) {
795  if (1 == group->GetSize()) {
796 // cout<<"FK: Starting Single Term"<<endl;
797 
798  RooArgSet* term = (RooArgSet*) group->At(0);
799 
800  Int_t termIdx = terms.IndexOf(term);
801  norm=(RooArgSet*) norms.At(termIdx);
802  imps=(RooArgSet*)imp.At(termIdx);
803  RooArgSet termNSet(*norm), termImpSet(*imps);
804 
805 // cout<<"FK: termImpSet.getSize() = "<<termImpSet.getSize()<< " " << termImpSet << endl;
806 // cout<<"FK: _refRangeName = "<<_refRangeName<<endl;
807 
808  if (termImpSet.getSize() > 0 && 0 != _refRangeName) {
809 
810 // cout << "WVE now here" << endl;
811 
812  // WVE we can skip this if the ref range is equal to the normalization range
813  Bool_t rangeIdentical(kTRUE);
814  RooFIter niter = termNSet.fwdIterator();
815  RooRealVar* normObs;
816 // cout << "_normRange = " << _normRange << " _refRangeName = " << RooNameReg::str(_refRangeName) << endl ;
817  while ((normObs = (RooRealVar*) niter.next())) {
818  //FK: Here the refRange should be compared to _normRange, if it's set, and to the normObs range if it's not set
819  if (_normRange.Length() > 0) {
820  if (normObs->getMin(_normRange.Data()) != normObs->getMin(RooNameReg::str(_refRangeName))) rangeIdentical = kFALSE;
821  if (normObs->getMax(_normRange.Data()) != normObs->getMax(RooNameReg::str(_refRangeName))) rangeIdentical = kFALSE;
822  }
823  else{
824  if (normObs->getMin() != normObs->getMin(RooNameReg::str(_refRangeName))) rangeIdentical = kFALSE;
825  if (normObs->getMax() != normObs->getMax(RooNameReg::str(_refRangeName))) rangeIdentical = kFALSE;
826  }
827  }
828 // cout<<"FK: rangeIdentical Single = "<<(rangeIdentical ? 'T':'F')<<endl;
829  // coverity[CONSTANT_EXPRESSION_RESULT]
830  if (!rangeIdentical || 1) {
831 // cout << "PREPARING RATIO HERE (SINGLE TERM)" << endl ;
832  RooAbsReal* ratio = makeCondPdfRatioCorr(*(RooAbsReal*)term->first(), termNSet, termImpSet, normRange(), RooNameReg::str(_refRangeName));
833  ostringstream str; termImpSet.printValue(str);
834 // cout << GetName() << "inserting ratio term" << endl;
835  ratioTerms[str.str()].add(*ratio);
836  }
837  }
838 
839  } else {
840 // cout<<"FK: Starting Composite Term"<<endl;
841 
842  RooArgSet compTermSet, compTermNorm;
843  RooFIter tIter = group->fwdIterator();
844  RooArgSet* term;
845  while ((term = (RooArgSet*) tIter.next())) {
846 
847  Int_t termIdx = terms.IndexOf(term);
848  norm=(RooArgSet*) norms.At(termIdx);
849  imps=(RooArgSet*)imp.At(termIdx);
850  RooArgSet termNSet(*norm), termImpSet(*imps);
851 
852  if (termImpSet.getSize() > 0 && 0 != _refRangeName) {
853 
854  // WVE we can skip this if the ref range is equal to the normalization range
855  Bool_t rangeIdentical(kTRUE);
856  RooFIter niter = termNSet.fwdIterator();
857  RooRealVar* normObs;
858  //FK: Here the refRange should be compared to _normRange, if it's set, and to the normObs range if it's not set
859  if(_normRange.Length() > 0) {
860  while ((normObs = (RooRealVar*) niter.next())) {
861  if (normObs->getMin(_normRange.Data()) != normObs->getMin(RooNameReg::str(_refRangeName))) rangeIdentical = kFALSE;
862  if (normObs->getMax(_normRange.Data()) != normObs->getMax(RooNameReg::str(_refRangeName))) rangeIdentical = kFALSE;
863  }
864  } else {
865  while ((normObs = (RooRealVar*) niter.next())) {
866  if (normObs->getMin() != normObs->getMin(RooNameReg::str(_refRangeName))) rangeIdentical = kFALSE;
867  if (normObs->getMax() != normObs->getMax(RooNameReg::str(_refRangeName))) rangeIdentical = kFALSE;
868  }
869  }
870 // cout<<"FK: rangeIdentical Composite = "<<(rangeIdentical ? 'T':'F') <<endl;
871  if (!rangeIdentical || 1) {
872 // cout << "PREPARING RATIO HERE (COMPOSITE TERM)" << endl ;
873  RooAbsReal* ratio = makeCondPdfRatioCorr(*(RooAbsReal*)term->first(), termNSet, termImpSet, normRange(), RooNameReg::str(_refRangeName));
874  ostringstream str; termImpSet.printValue(str);
875  ratioTerms[str.str()].add(*ratio);
876  }
877  }
878  }
879  }
880 
881  }
882 
883  // Find groups with y as termNSet
884  // Replace G(y) with (G(y),ratio)
885  gIter = groupedList.fwdIterator();
886  while ((group = (RooLinkedList*) gIter.next())) {
887  if (1 == group->GetSize()) {
888  RooArgSet* term = (RooArgSet*) group->At(0);
889 
890  Int_t termIdx = terms.IndexOf(term);
891  norm = (RooArgSet*) norms.At(termIdx);
892  imps = (RooArgSet*) imp.At(termIdx);
893  RooArgSet termNSet(*norm), termImpSet(*imps);
894 
895  // If termNset matches index of ratioTerms, insert ratio here
896  ostringstream str; termNSet.printValue(str);
897  if (ratioTerms[str.str()].getSize() > 0) {
898 // cout << "MUST INSERT RATIO OBJECT IN TERM (SINGLE) " << *term << endl;
899  term->add(ratioTerms[str.str()]);
900  }
901  } else {
902  RooArgSet compTermSet, compTermNorm;
903  RooFIter tIter = group->fwdIterator();
904  RooArgSet* term;
905  while ((term = (RooArgSet*) tIter.next())) {
906  Int_t termIdx = terms.IndexOf(term);
907  norm = (RooArgSet*) norms.At(termIdx);
908  imps = (RooArgSet*) imp.At(termIdx);
909  RooArgSet termNSet(*norm), termImpSet(*imps);
910 
911  // If termNset matches index of ratioTerms, insert ratio here
912  ostringstream str; termNSet.printValue(str);
913  if (ratioTerms[str.str()].getSize() > 0) {
914 // cout << "MUST INSERT RATIO OBJECT IN TERM (COMPOSITE)" << *term << endl;
915  term->add(ratioTerms[str.str()]);
916  }
917  }
918  }
919  }
920 
921  gIter = groupedList.fwdIterator();
922  while ((group = (RooLinkedList*) gIter.next())) {
923 // cout << GetName() << ":now processing group" << endl;
924 // group->Print("1");
925 
926  if (1 == group->GetSize()) {
927 // cout << "processing atomic item" << endl;
928  RooArgSet* term = (RooArgSet*) group->At(0);
929 
930  Int_t termIdx = terms.IndexOf(term);
931  norm = (RooArgSet*) norms.At(termIdx);
932  integ = (RooArgSet*) ints.At(termIdx);
933  xdeps = (RooArgSet*) cross.At(termIdx);
934  imps = (RooArgSet*) imp.At(termIdx);
935 
936  RooArgSet termNSet, termISet, termXSet, termImpSet;
937 
938  // Take list of normalization, integrated dependents from factorization algorithm
939  termISet.add(*integ);
940  termNSet.add(*norm);
941 
942  // Cross-imported integrated dependents
943  termXSet.add(*xdeps);
944  termImpSet.add(*imps);
945 
946 // cout << GetName() << ": termISet = " << termISet << endl;
947 // cout << GetName() << ": termNSet = " << termNSet << endl;
948 // cout << GetName() << ": termXSet = " << termXSet << endl;
949 // cout << GetName() << ": termImpSet = " << termImpSet << endl;
950 
951  // Add prefab term to partIntList.
952  Bool_t isOwned(kFALSE);
953  vector<RooAbsReal*> func = processProductTerm(nset, iset, isetRangeName, term, termNSet, termISet, isOwned);
954  if (func[0]) {
955  cache->_partList.add(*func[0]);
956  if (isOwned) cache->_ownedList.addOwned(*func[0]);
957 
958  cache->_normList.emplace_back(norm->snapshot(kFALSE));
959 
960  cache->_numList.addOwned(*func[1]);
961  cache->_denList.addOwned(*func[2]);
962 // cout << "func[0]=" << func[0]->IsA()->GetName() << "::" << func[0]->GetName() << endl;
963 // cout << "func[1]=" << func[1]->IsA()->GetName() << "::" << func[1]->GetName() << endl;
964 // cout << "func[2]=" << func[2]->IsA()->GetName() << "::" << func[2]->GetName() << endl;
965  }
966  } else {
967 // cout << "processing composite item" << endl;
968  RooArgSet compTermSet, compTermNorm, compTermNum, compTermDen;
969  RooFIter tIter = group->fwdIterator();
970  RooArgSet* term;
971  while ((term = (RooArgSet*) tIter.next())) {
972 // cout << GetName() << ": processing term " << (*term) << " of composite item" << endl ;
973  Int_t termIdx = terms.IndexOf(term);
974  norm = (RooArgSet*) norms.At(termIdx);
975  integ = (RooArgSet*) ints.At(termIdx);
976  xdeps = (RooArgSet*) cross.At(termIdx);
977  imps = (RooArgSet*) imp.At(termIdx);
978 
979  RooArgSet termNSet, termISet, termXSet, termImpSet;
980  termISet.add(*integ);
981  termNSet.add(*norm);
982  termXSet.add(*xdeps);
983  termImpSet.add(*imps);
984 
985  // Remove outer integration dependents from termISet
986  termISet.remove(outerIntDeps, kTRUE, kTRUE);
987 // cout << "termISet = "; termISet.Print("1");
988 
989 // cout << GetName() << ": termISet = " << termISet << endl;
990 // cout << GetName() << ": termNSet = " << termNSet << endl;
991 // cout << GetName() << ": termXSet = " << termXSet << endl;
992 // cout << GetName() << ": termImpSet = " << termImpSet << endl;
993 
994  Bool_t isOwned = false;
995  vector<RooAbsReal*> func = processProductTerm(nset, iset, isetRangeName, term, termNSet, termISet, isOwned, kTRUE);
996 // cout << GetName() << ": created composite term component " << func[0]->GetName() << endl;
997  if (func[0]) {
998  compTermSet.add(*func[0]);
999  if (isOwned) cache->_ownedList.addOwned(*func[0]);
1000  compTermNorm.add(*norm, kFALSE);
1001 
1002  compTermNum.add(*func[1]);
1003  compTermDen.add(*func[2]);
1004  //cache->_numList.add(*func[1]);
1005  //cache->_denList.add(*func[2]);
1006 
1007 // cout << "func[0]=" << func[0]->IsA()->GetName() << "::" << func[0]->GetName() << endl;
1008 // cout << "func[1]=" << func[1]->IsA()->GetName() << "::" << func[1]->GetName() << endl;
1009 // cout << "func[2]=" << func[2]->IsA()->GetName() << "::" << func[2]->GetName() << endl;
1010  }
1011  }
1012 
1013 // cout << GetName() << ": constructing special composite product" << endl;
1014 // cout << GetName() << ": compTermSet = " ; compTermSet.Print("1");
1015 
1016  // WVE THIS NEEDS TO BE REARRANGED
1017 
1018  // compTermset is set van partial integrals to be multiplied
1019  // prodtmp = product (compTermSet)
1020  // inttmp = int ( prodtmp ) d (outerIntDeps) _range_isetRangeName
1021 
1022  const std::string prodname = makeRGPPName("SPECPROD", compTermSet, outerIntDeps, RooArgSet(), isetRangeName);
1023  RooProduct* prodtmp = new RooProduct(prodname.c_str(), prodname.c_str(), compTermSet);
1024  cache->_ownedList.addOwned(*prodtmp);
1025 
1026  const std::string intname = makeRGPPName("SPECINT", compTermSet, outerIntDeps, RooArgSet(), isetRangeName);
1027  RooRealIntegral* inttmp = new RooRealIntegral(intname.c_str(), intname.c_str(), *prodtmp, outerIntDeps, 0, 0, isetRangeName);
1028  inttmp->setStringAttribute("PROD_TERM_TYPE", "SPECINT");
1029 
1030  cache->_ownedList.addOwned(*inttmp);
1031  cache->_partList.add(*inttmp);
1032 
1033  // Product of numerator terms
1034  const string prodname_num = makeRGPPName("SPECPROD_NUM", compTermNum, RooArgSet(), RooArgSet(), 0);
1035  RooProduct* prodtmp_num = new RooProduct(prodname_num.c_str(), prodname_num.c_str(), compTermNum);
1036  prodtmp_num->addOwnedComponents(compTermNum);
1037  cache->_ownedList.addOwned(*prodtmp_num);
1038 
1039  // Product of denominator terms
1040  const string prodname_den = makeRGPPName("SPECPROD_DEN", compTermDen, RooArgSet(), RooArgSet(), 0);
1041  RooProduct* prodtmp_den = new RooProduct(prodname_den.c_str(), prodname_den.c_str(), compTermDen);
1042  prodtmp_den->addOwnedComponents(compTermDen);
1043  cache->_ownedList.addOwned(*prodtmp_den);
1044 
1045  // Ratio
1046  string name = Form("SPEC_RATIO(%s,%s)", prodname_num.c_str(), prodname_den.c_str());
1047  RooFormulaVar* ndr = new RooFormulaVar(name.c_str(), "@0/@1", RooArgList(*prodtmp_num, *prodtmp_den));
1048 
1049  // Integral of ratio
1050  RooAbsReal* numtmp = ndr->createIntegral(outerIntDeps,isetRangeName);
1051  numtmp->addOwnedComponents(*ndr);
1052 
1053  cache->_numList.addOwned(*numtmp);
1054  cache->_denList.addOwned(*(RooAbsArg*)RooFit::RooConst(1).clone("1"));
1055  cache->_normList.emplace_back(compTermNorm.snapshot(kFALSE));
1056  }
1057  }
1058 
1059  // Store the partial integral list and return the assigned code
1060  Int_t returnCode = _cacheMgr.setObj(nset, iset, (RooAbsCacheElement*)cache, RooNameReg::ptr(isetRangeName));
1061 
1062  // WVE DEBUG PRINTING
1063 // cout << "RooProdPdf::getPartIntList(" << GetName() << ") made cache " << cache << " with the following nset pointers ";
1064 // TIterator* nliter = nsetList->MakeIterator();
1065 // RooArgSet* ns;
1066 // while((ns=(RooArgSet*)nliter->Next())) {
1067 // cout << ns << " ";
1068 // }
1069 // cout << endl;
1070 // delete nliter;
1071 
1072 // cout << " FOLKERT::RooProdPdf::getPartIntList END(" << GetName() <<") nset = " << (nset?*nset:RooArgSet()) << endl
1073 // << " _normRange = " << _normRange << endl
1074 // << " iset = " << (iset?*iset:RooArgSet()) << endl
1075 // << " partList = ";
1076 // if(partListPointer) partListPointer->Print();
1077 // cout << " nsetList = ";
1078 // if(nsetListPointer) nsetListPointer->Print("");
1079 // cout << " code = " << returnCode << endl
1080 // << " isetRangeName = " << (isetRangeName?isetRangeName:"<null>") << endl;
1081 
1082 
1083  // Need to rearrange product in case of multiple ranges
1084  if (_normRange.Contains(",")) {
1085  rearrangeProduct(*cache);
1086  }
1087 
1088  // We own contents of all lists filled by factorizeProduct()
1089  groupedList.Delete();
1090  terms.Delete();
1091  ints.Delete();
1092  imp.Delete();
1093  norms.Delete();
1094  cross.Delete();
1095 
1096  return returnCode;
1097 }
1098 
1099 
1100 
1101 
1102 ////////////////////////////////////////////////////////////////////////////////
1103 /// For single normalization ranges
1104 
1105 RooAbsReal* RooProdPdf::makeCondPdfRatioCorr(RooAbsReal& pdf, const RooArgSet& termNset, const RooArgSet& /*termImpSet*/, const char* normRangeTmp, const char* refRange) const
1106 {
1107  RooAbsReal* ratio_num = pdf.createIntegral(termNset,normRangeTmp) ;
1108  RooAbsReal* ratio_den = pdf.createIntegral(termNset,refRange) ;
1109  RooFormulaVar* ratio = new RooFormulaVar(Form("ratio(%s,%s)",ratio_num->GetName(),ratio_den->GetName()),"@0/@1",
1110  RooArgList(*ratio_num,*ratio_den)) ;
1111 
1112  ratio->addOwnedComponents(RooArgSet(*ratio_num,*ratio_den)) ;
1113  ratio->setAttribute("RATIO_TERM") ;
1114  return ratio ;
1115 }
1116 
1117 
1118 
1119 
1120 ////////////////////////////////////////////////////////////////////////////////
1121 
1122 void RooProdPdf::rearrangeProduct(RooProdPdf::CacheElem& cache) const
1123 {
1124  RooAbsReal* part, *num, *den ;
1125  RooArgSet nomList ;
1126 
1127  list<string> rangeComps ;
1128  {
1129  char* buf = new char[strlen(_normRange.Data()) + 1] ;
1130  strcpy(buf,_normRange.Data()) ;
1131  char* save(0) ;
1132  char* token = R__STRTOK_R(buf,",",&save) ;
1133  while(token) {
1134  rangeComps.push_back(token) ;
1135  token = R__STRTOK_R(0,",",&save) ;
1136  }
1137  delete[] buf;
1138  }
1139 
1140 
1141  map<string,RooArgSet> denListList ;
1142  RooArgSet specIntDeps ;
1143  string specIntRange ;
1144 
1145 // cout << "THIS IS REARRANGEPRODUCT" << endl ;
1146 
1147  RooFIter iterp = cache._partList.fwdIterator() ;
1148  RooFIter iter1 = cache._numList.fwdIterator() ;
1149  RooFIter iter2 = cache._denList.fwdIterator() ;
1150  while((part=(RooAbsReal*)iterp.next())) {
1151 
1152  num = (RooAbsReal*) iter1.next() ;
1153  den = (RooAbsReal*) iter2.next() ;
1154 
1155 // cout << "now processing part " << part->GetName() << " of type " << part->getStringAttribute("PROD_TERM_TYPE") << endl ;
1156 // cout << "corresponding numerator = " << num->GetName() << endl ;
1157 // cout << "corresponding denominator = " << den->GetName() << endl ;
1158 
1159 
1160  RooFormulaVar* ratio(0) ;
1161  RooArgSet origNumTerm ;
1162 
1163  if (string("SPECINT")==part->getStringAttribute("PROD_TERM_TYPE")) {
1164 
1165  RooRealIntegral* orig = (RooRealIntegral*) num;
1166  RooFormulaVar* specratio = (RooFormulaVar*) &orig->integrand() ;
1167  RooProduct* func = (RooProduct*) specratio->getParameter(0) ;
1168 
1169  RooArgSet* comps = orig->getComponents() ;
1170  RooFIter iter = comps->fwdIterator() ;
1171  RooAbsArg* carg ;
1172  while((carg=(RooAbsArg*)iter.next())) {
1173  if (carg->getAttribute("RATIO_TERM")) {
1174  ratio = (RooFormulaVar*)carg ;
1175  break ;
1176  }
1177  }
1178  delete comps ;
1179 
1180  if (ratio) {
1181  RooCustomizer cust(*func,"blah") ;
1182  cust.replaceArg(*ratio,RooFit::RooConst(1)) ;
1183  RooAbsArg* funcCust = cust.build() ;
1184 // cout << "customized function = " << endl ;
1185 // funcCust->printComponentTree() ;
1186  nomList.add(*funcCust) ;
1187  } else {
1188  nomList.add(*func) ;
1189  }
1190 
1191 
1192  } else {
1193 
1194  // Find the ratio term
1195  RooAbsReal* func = num;
1196  // If top level object is integral, navigate to integrand
1197  if (func->InheritsFrom(RooRealIntegral::Class())) {
1198  func = (RooAbsReal*) &((RooRealIntegral*)(func))->integrand();
1199  }
1200  if (func->InheritsFrom(RooProduct::Class())) {
1201 // cout << "product term found: " ; func->Print() ;
1202  RooArgSet comps(((RooProduct*)(func))->components()) ;
1203  RooFIter iter = comps.fwdIterator() ;
1204  RooAbsArg* arg ;
1205  while((arg=(RooAbsArg*)iter.next())) {
1206  if (arg->getAttribute("RATIO_TERM")) {
1207  ratio = (RooFormulaVar*)(arg) ;
1208  } else {
1209  origNumTerm.add(*arg) ;
1210  }
1211  }
1212  }
1213 
1214  if (ratio) {
1215 // cout << "Found ratio term in numerator: " << ratio->GetName() << endl ;
1216 // cout << "Adding only original term to numerator: " << origNumTerm << endl ;
1217  nomList.add(origNumTerm) ;
1218  } else {
1219  nomList.add(*num) ;
1220  }
1221 
1222  }
1223 
1224  for (list<string>::iterator iter = rangeComps.begin() ; iter != rangeComps.end() ; ++iter) {
1225  // If denominator is an integral, make a clone with the integration range adjusted to
1226  // the selected component of the normalization integral
1227 // cout << "NOW PROCESSING DENOMINATOR " << den->IsA()->GetName() << "::" << den->GetName() << endl ;
1228 
1229  if (string("SPECINT")==part->getStringAttribute("PROD_TERM_TYPE")) {
1230 
1231 // cout << "create integral: SPECINT case" << endl ;
1232  RooRealIntegral* orig = (RooRealIntegral*) num;
1233  RooFormulaVar* specRatio = (RooFormulaVar*) &orig->integrand() ;
1234  specIntDeps.add(orig->intVars()) ;
1235  if (orig->intRange()) {
1236  specIntRange = orig->intRange() ;
1237  }
1238  //RooProduct* numtmp = (RooProduct*) specRatio->getParameter(0) ;
1239  RooProduct* dentmp = (RooProduct*) specRatio->getParameter(1) ;
1240 
1241 // cout << "numtmp = " << numtmp->IsA()->GetName() << "::" << numtmp->GetName() << endl ;
1242 // cout << "dentmp = " << dentmp->IsA()->GetName() << "::" << dentmp->GetName() << endl ;
1243 
1244 // cout << "denominator components are " << dentmp->components() << endl ;
1245  RooArgSet comps(dentmp->components()) ;
1246  RooFIter piter = comps.fwdIterator() ;
1247  RooAbsReal* parg ;
1248  while((parg=(RooAbsReal*)piter.next())) {
1249 // cout << "now processing denominator component " << parg->IsA()->GetName() << "::" << parg->GetName() << endl ;
1250 
1251  if (ratio && parg->dependsOn(*ratio)) {
1252 // cout << "depends in value of ratio" << endl ;
1253 
1254  // Make specialize ratio instance
1255  RooAbsReal* specializedRatio = specializeRatio(*(RooFormulaVar*)ratio,iter->c_str()) ;
1256 
1257 // cout << "specRatio = " << endl ;
1258 // specializedRatio->printComponentTree() ;
1259 
1260  // Replace generic ratio with specialized ratio
1261  RooAbsArg *partCust(0) ;
1262  if (parg->InheritsFrom(RooAddition::Class())) {
1263 
1264 
1265 
1266  RooAddition* tmpadd = (RooAddition*)(parg) ;
1267 
1268  RooCustomizer cust(*tmpadd->list1().first(),Form("blah_%s",iter->c_str())) ;
1269  cust.replaceArg(*ratio,*specializedRatio) ;
1270  partCust = cust.build() ;
1271 
1272  } else {
1273  RooCustomizer cust(*parg,Form("blah_%s",iter->c_str())) ;
1274  cust.replaceArg(*ratio,*specializedRatio) ;
1275  partCust = cust.build() ;
1276  }
1277 
1278  // Print customized denominator
1279 // cout << "customized function = " << endl ;
1280 // partCust->printComponentTree() ;
1281 
1282  RooAbsReal* specializedPartCust = specializeIntegral(*(RooAbsReal*)partCust,iter->c_str()) ;
1283 
1284  // Finally divide again by ratio
1285  string name = Form("%s_divided_by_ratio",specializedPartCust->GetName()) ;
1286  RooFormulaVar* specIntFinal = new RooFormulaVar(name.c_str(),"@0/@1",RooArgList(*specializedPartCust,*specializedRatio)) ;
1287 
1288  denListList[*iter].add(*specIntFinal) ;
1289  } else {
1290 
1291 // cout << "does NOT depend on value of ratio" << endl ;
1292 // parg->Print("t") ;
1293 
1294  denListList[*iter].add(*specializeIntegral(*parg,iter->c_str())) ;
1295 
1296  }
1297  }
1298 // cout << "end iteration over denominator components" << endl ;
1299  } else {
1300 
1301  if (ratio) {
1302 
1303  RooAbsReal* specRatio = specializeRatio(*(RooFormulaVar*)ratio,iter->c_str()) ;
1304 
1305  // If integral is 'Int r(y)*g(y) dy ' then divide a posteriori by r(y)
1306 // cout << "have ratio, orig den = " << den->GetName() << endl ;
1307 
1308  RooArgSet tmp(origNumTerm) ;
1309  tmp.add(*specRatio) ;
1310  const string pname = makeRGPPName("PROD",tmp,RooArgSet(),RooArgSet(),0) ;
1311  RooProduct* specDenProd = new RooProduct(pname.c_str(),pname.c_str(),tmp) ;
1312  RooAbsReal* specInt(0) ;
1313 
1314  if (den->InheritsFrom(RooRealIntegral::Class())) {
1315  specInt = specDenProd->createIntegral(((RooRealIntegral*)den)->intVars(),iter->c_str()) ;
1316  } else if (den->InheritsFrom(RooAddition::Class())) {
1317  RooAddition* orig = (RooAddition*)den ;
1318  RooRealIntegral* origInt = (RooRealIntegral*) orig->list1().first() ;
1319  specInt = specDenProd->createIntegral(origInt->intVars(),iter->c_str()) ;
1320  } else {
1321  throw string("this should not happen") ;
1322  }
1323 
1324  //RooAbsReal* specInt = specializeIntegral(*den,iter->c_str()) ;
1325  string name = Form("%s_divided_by_ratio",specInt->GetName()) ;
1326  RooFormulaVar* specIntFinal = new RooFormulaVar(name.c_str(),"@0/@1",RooArgList(*specInt,*specRatio)) ;
1327  denListList[*iter].add(*specIntFinal) ;
1328  } else {
1329  denListList[*iter].add(*specializeIntegral(*den,iter->c_str())) ;
1330  }
1331 
1332  }
1333  }
1334 
1335  }
1336 
1337  // Do not rearrage terms if numerator and denominator are effectively empty
1338  if (nomList.getSize()==0) {
1339  return ;
1340  }
1341 
1342  string name = Form("%s_numerator",GetName()) ;
1343  // WVE FIX THIS (2)
1344 
1345  RooAbsReal* numerator = new RooProduct(name.c_str(),name.c_str(),nomList) ;
1346 
1347  RooArgSet products ;
1348 // cout << "nomList = " << nomList << endl ;
1349  for (map<string,RooArgSet>::iterator iter = denListList.begin() ; iter != denListList.end() ; ++iter) {
1350 // cout << "denList[" << iter->first << "] = " << iter->second << endl ;
1351  name = Form("%s_denominator_comp_%s",GetName(),iter->first.c_str()) ;
1352  // WVE FIX THIS (2)
1353  RooProduct* prod_comp = new RooProduct(name.c_str(),name.c_str(),iter->second) ;
1354  products.add(*prod_comp) ;
1355  }
1356  name = Form("%s_denominator_sum",GetName()) ;
1357  RooAbsReal* norm = new RooAddition(name.c_str(),name.c_str(),products) ;
1358  norm->addOwnedComponents(products) ;
1359 
1360  if (specIntDeps.getSize()>0) {
1361  // Apply posterior integration required for SPECINT case
1362 
1363  string namesr = Form("SPEC_RATIO(%s,%s)",numerator->GetName(),norm->GetName()) ;
1364  RooFormulaVar* ndr = new RooFormulaVar(namesr.c_str(),"@0/@1",RooArgList(*numerator,*norm)) ;
1365 
1366  // Integral of ratio
1367  RooAbsReal* numtmp = ndr->createIntegral(specIntDeps,specIntRange.c_str()) ;
1368 
1369  numerator = numtmp ;
1370  norm = (RooAbsReal*) RooFit::RooConst(1).Clone() ;
1371  }
1372 
1373 
1374 // cout << "numerator" << endl ;
1375 // numerator->printComponentTree("",0,5) ;
1376 // cout << "denominator" << endl ;
1377 // norm->printComponentTree("",0,5) ;
1378 
1379 
1380  // WVE DEBUG
1381  //RooMsgService::instance().debugWorkspace()->import(RooArgSet(*numerator,*norm)) ;
1382 
1383  cache._rearrangedNum.reset(numerator);
1384  cache._rearrangedDen.reset(norm);
1385  cache._isRearranged = kTRUE ;
1386 
1387 }
1388 
1389 
1390 ////////////////////////////////////////////////////////////////////////////////
1391 
1392 RooAbsReal* RooProdPdf::specializeRatio(RooFormulaVar& input, const char* targetRangeName) const
1393 {
1394  RooRealIntegral* numint = (RooRealIntegral*) input.getParameter(0) ;
1395  RooRealIntegral* denint = (RooRealIntegral*) input.getParameter(1) ;
1396 
1397  RooAbsReal* numint_spec = specializeIntegral(*numint,targetRangeName) ;
1398 
1399  RooAbsReal* ret = new RooFormulaVar(Form("ratio(%s,%s)",numint_spec->GetName(),denint->GetName()),"@0/@1",RooArgList(*numint_spec,*denint)) ;
1400  ret->addOwnedComponents(*numint_spec) ;
1401 
1402  return ret ;
1403 }
1404 
1405 
1406 
1407 ////////////////////////////////////////////////////////////////////////////////
1408 
1409 RooAbsReal* RooProdPdf::specializeIntegral(RooAbsReal& input, const char* targetRangeName) const
1410 {
1411  if (input.InheritsFrom(RooRealIntegral::Class())) {
1412 
1413  // If input is integral, recreate integral but override integration range to be targetRangeName
1414  RooRealIntegral* orig = (RooRealIntegral*)&input ;
1415 // cout << "creating integral: integrand = " << orig->integrand().GetName() << " vars = " << orig->intVars() << " range = " << targetRangeName << endl ;
1416  return orig->integrand().createIntegral(orig->intVars(),targetRangeName) ;
1417 
1418  } else if (input.InheritsFrom(RooAddition::Class())) {
1419 
1420  // If input is sum of integrals, recreate integral from first component of set, but override integration range to be targetRangeName
1421  RooAddition* orig = (RooAddition*)&input ;
1422  RooRealIntegral* origInt = (RooRealIntegral*) orig->list1().first() ;
1423 // cout << "creating integral from addition: integrand = " << origInt->integrand().GetName() << " vars = " << origInt->intVars() << " range = " << targetRangeName << endl ;
1424  return origInt->integrand().createIntegral(origInt->intVars(),targetRangeName) ;
1425 
1426  } else {
1427 
1428 // cout << "specializeIntegral: unknown input type " << input.IsA()->GetName() << "::" << input.GetName() << endl ;
1429  }
1430 
1431  return &input ;
1432 }
1433 
1434 
1435 ////////////////////////////////////////////////////////////////////////////////
1436 /// Group product into terms that can be calculated independently
1437 
1438 void RooProdPdf::groupProductTerms(RooLinkedList& groupedTerms, RooArgSet& outerIntDeps,
1439  const RooLinkedList& terms, const RooLinkedList& norms,
1440  const RooLinkedList& imps, const RooLinkedList& ints, const RooLinkedList& /*cross*/) const
1441 {
1442  // Start out with each term in its own group
1443  RooFIter tIter = terms.fwdIterator() ;
1444  RooArgSet* term ;
1445  while((term=(RooArgSet*)tIter.next())) {
1446  RooLinkedList* group = new RooLinkedList ;
1447  group->Add(term) ;
1448  groupedTerms.Add(group) ;
1449  }
1450 
1451  // Make list of imported dependents that occur in any term
1452  RooArgSet allImpDeps ;
1453  RooFIter iIter = imps.fwdIterator() ;
1454  RooArgSet *impDeps ;
1455  while((impDeps=(RooArgSet*)iIter.next())) {
1456  allImpDeps.add(*impDeps,kFALSE) ;
1457  }
1458 
1459  // Make list of integrated dependents that occur in any term
1460  RooArgSet allIntDeps ;
1461  iIter = ints.fwdIterator() ;
1462  RooArgSet *intDeps ;
1463  while((intDeps=(RooArgSet*)iIter.next())) {
1464  allIntDeps.add(*intDeps,kFALSE) ;
1465  }
1466 
1467  RooArgSet* tmp = (RooArgSet*) allIntDeps.selectCommon(allImpDeps) ;
1468  outerIntDeps.removeAll() ;
1469  outerIntDeps.add(*tmp) ;
1470  delete tmp ;
1471 
1472  // Now iteratively merge groups that should be (partially) integrated together
1473  RooFIter oidIter = outerIntDeps.fwdIterator() ;
1474  RooAbsArg* outerIntDep ;
1475  while ((outerIntDep =(RooAbsArg*)oidIter.next())) {
1476 
1477  // Collect groups that feature this dependent
1478  RooLinkedList* newGroup = 0 ;
1479 
1480  // Loop over groups
1481  RooLinkedList* group ;
1482  RooFIter glIter = groupedTerms.fwdIterator() ;
1483  Bool_t needMerge = kFALSE ;
1484  while((group=(RooLinkedList*)glIter.next())) {
1485 
1486  // See if any term in this group depends in any ay on outerDepInt
1487  RooArgSet* term2 ;
1488  RooFIter tIter2 = group->fwdIterator() ;
1489  while((term2=(RooArgSet*)tIter2.next())) {
1490 
1491  Int_t termIdx = terms.IndexOf(term2) ;
1492  RooArgSet* termNormDeps = (RooArgSet*) norms.At(termIdx) ;
1493  RooArgSet* termIntDeps = (RooArgSet*) ints.At(termIdx) ;
1494  RooArgSet* termImpDeps = (RooArgSet*) imps.At(termIdx) ;
1495 
1496  if (termNormDeps->contains(*outerIntDep) ||
1497  termIntDeps->contains(*outerIntDep) ||
1498  termImpDeps->contains(*outerIntDep)) {
1499  needMerge = kTRUE ;
1500  }
1501 
1502  }
1503 
1504  if (needMerge) {
1505  // Create composite group if not yet existing
1506  if (newGroup==0) {
1507  newGroup = new RooLinkedList ;
1508  }
1509 
1510  // Add terms of this group to new term
1511  tIter2 = group->fwdIterator() ;
1512  while((term2=(RooArgSet*)tIter2.next())) {
1513  newGroup->Add(term2) ;
1514  }
1515 
1516  // Remove this group from list and delete it (but not its contents)
1517  groupedTerms.Remove(group) ;
1518  delete group ;
1519  }
1520  }
1521  // If a new group has been created to merge terms dependent on current outerIntDep, add it to group list
1522  if (newGroup) {
1523  groupedTerms.Add(newGroup) ;
1524  }
1525 
1526  }
1527 }
1528 
1529 
1530 
1531 ////////////////////////////////////////////////////////////////////////////////
1532 /// Calculate integrals of factorized product terms over observables iset while normalized
1533 /// to observables in nset.
1534 
1535 std::vector<RooAbsReal*> RooProdPdf::processProductTerm(const RooArgSet* nset, const RooArgSet* iset, const char* isetRangeName,
1536  const RooArgSet* term,const RooArgSet& termNSet, const RooArgSet& termISet,
1537  Bool_t& isOwned, Bool_t forceWrap) const
1538 {
1539 // cout << " FOLKERT::RooProdPdf(" << GetName() <<") processProductTerm nset = " << (nset?*nset:RooArgSet()) << endl
1540 // << " _normRange = " << _normRange << endl
1541 // << " iset = " << (iset?*iset:RooArgSet()) << endl
1542 // << " isetRangeName = " << (isetRangeName?isetRangeName:"<null>") << endl
1543 // << " term = " << (term?*term:RooArgSet()) << endl
1544 // << " termNSet = " << termNSet << endl
1545 // << " termISet = " << termISet << endl
1546 // << " isOwned = " << isOwned << endl
1547 // << " forceWrap = " << forceWrap << endl ;
1548 
1549  vector<RooAbsReal*> ret(3) ; ret[0] = 0 ; ret[1] = 0 ; ret[2] = 0 ;
1550 
1551  // CASE I: factorizing term: term is integrated over all normalizing observables
1552  // -----------------------------------------------------------------------------
1553  // Check if all observbales of this term are integrated. If so the term cancels
1554  if (termNSet.getSize()>0 && termNSet.getSize()==termISet.getSize() && isetRangeName==0) {
1555 
1556 
1557  //cout << "processProductTerm(" << GetName() << ") case I " << endl ;
1558 
1559  // Term factorizes
1560  return ret ;
1561  }
1562 
1563  // CASE II: Dropped terms: if term is entirely unnormalized, it should be dropped
1564  // ------------------------------------------------------------------------------
1565  if (nset && termNSet.getSize()==0) {
1566 
1567  //cout << "processProductTerm(" << GetName() << ") case II " << endl ;
1568 
1569  // Drop terms that are not asked to be normalized
1570  return ret ;
1571  }
1572 
1573  if (iset && termISet.getSize()>0) {
1574  if (term->getSize()==1) {
1575 
1576  // CASE IIIa: Normalized and partially integrated single PDF term
1577  //---------------------------------------------------------------
1578 
1579  RooAbsPdf* pdf = (RooAbsPdf*) term->first() ;
1580 
1581  RooAbsReal* partInt = pdf->createIntegral(termISet,termNSet,isetRangeName) ;
1582  //partInt->setOperMode(operMode()) ;
1583  partInt->setStringAttribute("PROD_TERM_TYPE","IIIa") ;
1584 
1585  isOwned=kTRUE ;
1586 
1587  //cout << "processProductTerm(" << GetName() << ") case IIIa func = " << partInt->GetName() << endl ;
1588 
1589  ret[0] = partInt ;
1590 
1591  // Split mode results
1592  ret[1] = pdf->createIntegral(termISet,isetRangeName) ;
1593  ret[2] = pdf->createIntegral(termNSet,normRange()) ;
1594 
1595  return ret ;
1596 
1597 
1598  } else {
1599 
1600  // CASE IIIb: Normalized and partially integrated composite PDF term
1601  //---------------------------------------------------------------
1602 
1603  // Use auxiliary class RooGenProdProj to calculate this term
1604  const std::string name = makeRGPPName("GENPROJ_",*term,termISet,termNSet,isetRangeName) ;
1605  RooAbsReal* partInt = new RooGenProdProj(name.c_str(),name.c_str(),*term,termISet,termNSet,isetRangeName) ;
1606  partInt->setStringAttribute("PROD_TERM_TYPE","IIIb") ;
1607  //partInt->setOperMode(operMode()) ;
1608 
1609  //cout << "processProductTerm(" << GetName() << ") case IIIb func = " << partInt->GetName() << endl ;
1610 
1611  isOwned=kTRUE ;
1612  ret[0] = partInt ;
1613 
1614  const std::string name1 = makeRGPPName("PROD",*term,RooArgSet(),RooArgSet(),0) ;
1615 
1616  // WVE FIX THIS
1617  RooProduct* tmp_prod = new RooProduct(name1.c_str(),name1.c_str(),*term) ;
1618 
1619  ret[1] = tmp_prod->createIntegral(termISet,isetRangeName) ;
1620  ret[2] = tmp_prod->createIntegral(termNSet,normRange()) ;
1621 
1622  return ret ;
1623  }
1624  }
1625 
1626  // CASE IVa: Normalized non-integrated composite PDF term
1627  // -------------------------------------------------------
1628  if (nset && nset->getSize()>0 && term->getSize()>1) {
1629  // Composite term needs normalized integration
1630 
1631  const std::string name = makeRGPPName("GENPROJ_",*term,termISet,termNSet,isetRangeName) ;
1632  RooAbsReal* partInt = new RooGenProdProj(name.c_str(),name.c_str(),*term,termISet,termNSet,isetRangeName,normRange()) ;
1633  partInt->setExpensiveObjectCache(expensiveObjectCache()) ;
1634 
1635  partInt->setStringAttribute("PROD_TERM_TYPE","IVa") ;
1636  //partInt->setOperMode(operMode()) ;
1637 
1638  //cout << "processProductTerm(" << GetName() << ") case IVa func = " << partInt->GetName() << endl ;
1639 
1640  isOwned=kTRUE ;
1641  ret[0] = partInt ;
1642 
1643  const std::string name1 = makeRGPPName("PROD",*term,RooArgSet(),RooArgSet(),0) ;
1644 
1645  // WVE FIX THIS
1646  RooProduct* tmp_prod = new RooProduct(name1.c_str(),name1.c_str(),*term) ;
1647 
1648  ret[1] = tmp_prod->createIntegral(termISet,isetRangeName) ;
1649  ret[2] = tmp_prod->createIntegral(termNSet,normRange()) ;
1650 
1651  return ret ;
1652  }
1653 
1654  // CASE IVb: Normalized, non-integrated single PDF term
1655  // -----------------------------------------------------
1656  RooFIter pIter = term->fwdIterator() ;
1657  RooAbsPdf* pdf ;
1658  while((pdf=(RooAbsPdf*)pIter.next())) {
1659 
1660  if (forceWrap) {
1661 
1662  // Construct representative name of normalization wrapper
1663  TString name(pdf->GetName()) ;
1664  name.Append("_NORM[") ;
1665  RooFIter nIter = termNSet.fwdIterator() ;
1666  RooAbsArg* arg ;
1667  Bool_t first(kTRUE) ;
1668  while((arg=(RooAbsArg*)nIter.next())) {
1669  if (!first) {
1670  name.Append(",") ;
1671  } else {
1672  first=kFALSE ;
1673  }
1674  name.Append(arg->GetName()) ;
1675  }
1676  if (normRange()) {
1677  name.Append("|") ;
1678  name.Append(normRange()) ;
1679  }
1680  name.Append("]") ;
1681 
1682  RooAbsReal* partInt = new RooRealIntegral(name.Data(),name.Data(),*pdf,RooArgSet(),&termNSet) ;
1683  partInt->setStringAttribute("PROD_TERM_TYPE","IVb") ;
1684  isOwned=kTRUE ;
1685 
1686  //cout << "processProductTerm(" << GetName() << ") case IVb func = " << partInt->GetName() << endl ;
1687 
1688  ret[0] = partInt ;
1689 
1690  ret[1] = pdf->createIntegral(RooArgSet()) ;
1691  ret[2] = pdf->createIntegral(termNSet,normRange()) ;
1692 
1693  return ret ;
1694 
1695 
1696  } else {
1697  isOwned=kFALSE ;
1698 
1699  //cout << "processProductTerm(" << GetName() << ") case IVb func = " << pdf->GetName() << endl ;
1700 
1701 
1702  pdf->setStringAttribute("PROD_TERM_TYPE","IVb") ;
1703  ret[0] = pdf ;
1704 
1705  ret[1] = pdf->createIntegral(RooArgSet()) ;
1706  ret[2] = termNSet.getSize()>0 ? pdf->createIntegral(termNSet,normRange()) : ((RooAbsReal*)RooFit::RooConst(1).clone("1")) ;
1707  return ret ;
1708  }
1709  }
1710 
1711  coutE(Eval) << "RooProdPdf::processProductTerm(" << GetName() << ") unidentified term!!!" << endl ;
1712  return ret ;
1713 }
1714 
1715 
1716 
1717 
1718 ////////////////////////////////////////////////////////////////////////////////
1719 /// Make an appropriate automatic name for a RooGenProdProj object in getPartIntList()
1720 
1721 std::string RooProdPdf::makeRGPPName(const char* pfx, const RooArgSet& term, const RooArgSet& iset,
1722  const RooArgSet& nset, const char* isetRangeName) const
1723 {
1724  // Make an appropriate automatic name for a RooGenProdProj object in getPartIntList()
1725 
1726  std::ostringstream os(pfx);
1727  os << "[";
1728 
1729  RooFIter pIter = term.fwdIterator() ;
1730  // Encode component names
1731  Bool_t first(kTRUE) ;
1732  RooAbsPdf* pdf ;
1733  while ((pdf=(RooAbsPdf*)pIter.next())) {
1734  if (!first) os << "_X_";
1735  first = kFALSE;
1736  os << pdf->GetName();
1737  }
1738  os << "]" << integralNameSuffix(iset,&nset,isetRangeName,kTRUE);
1739 
1740  return os.str();
1741 }
1742 
1743 
1744 
1745 ////////////////////////////////////////////////////////////////////////////////
1746 /// Force RooRealIntegral to offer all observables for internal integration
1747 
1748 Bool_t RooProdPdf::forceAnalyticalInt(const RooAbsArg& /*dep*/) const
1749 {
1750  return kTRUE ;
1751 }
1752 
1753 
1754 
1755 ////////////////////////////////////////////////////////////////////////////////
1756 /// Determine which part (if any) of given integral can be performed analytically.
1757 /// If any analytical integration is possible, return integration scenario code.
1758 ///
1759 /// RooProdPdf implements two strategies in implementing analytical integrals
1760 ///
1761 /// First, PDF components whose entire set of dependents are requested to be integrated
1762 /// can be dropped from the product, as they will integrate out to 1 by construction
1763 ///
1764 /// Second, RooProdPdf queries each remaining component PDF for its analytical integration
1765 /// capability of the requested set ('allVars'). It finds the largest common set of variables
1766 /// that can be integrated by all remaining components. If such a set exists, it reconfirms that
1767 /// each component is capable of analytically integrating the common set, and combines the components
1768 /// individual integration codes into a single integration code valid for RooProdPdf.
1769 
1770 Int_t RooProdPdf::getAnalyticalIntegralWN(RooArgSet& allVars, RooArgSet& analVars,
1771  const RooArgSet* normSet, const char* rangeName) const
1772 {
1773  if (_forceNumInt) return 0 ;
1774 
1775  // Declare that we can analytically integrate all requested observables
1776  analVars.add(allVars) ;
1777 
1778  // Retrieve (or create) the required partial integral list
1779  Int_t code = getPartIntList(normSet,&allVars,rangeName);
1780 
1781  return code+1 ;
1782 }
1783 
1784 
1785 
1786 
1787 ////////////////////////////////////////////////////////////////////////////////
1788 /// Return analytical integral defined by given scenario code
1789 
1790 Double_t RooProdPdf::analyticalIntegralWN(Int_t code, const RooArgSet* normSet, const char* rangeName) const
1791 {
1792  // No integration scenario
1793  if (code==0) {
1794  return getVal(normSet) ;
1795  }
1796 
1797 
1798  // WVE needs adaptation for rangename feature
1799 
1800  // Partial integration scenarios
1801  CacheElem* cache = (CacheElem*) _cacheMgr.getObjByIndex(code-1) ;
1802 
1803  // If cache has been sterilized, revive this slot
1804  if (cache==0) {
1805  RooArgSet* vars = getParameters(RooArgSet()) ;
1806  RooArgSet* nset = _cacheMgr.nameSet1ByIndex(code-1)->select(*vars) ;
1807  RooArgSet* iset = _cacheMgr.nameSet2ByIndex(code-1)->select(*vars) ;
1808 
1809  Int_t code2 = getPartIntList(nset, iset, rangeName) ;
1810 
1811  delete vars ;
1812 
1813  // preceding call to getPartIntList guarantees non-null return
1814  // coverity[NULL_RETURNS]
1815  cache = (CacheElem*) _cacheMgr.getObj(nset,iset,&code2,rangeName) ;
1816 
1817  delete nset ;
1818  delete iset ;
1819 
1820  }
1821 
1822  Double_t val = calculate(*cache,kTRUE) ;
1823 // cout << "RPP::aIWN(" << GetName() << ") ,code = " << code << ", value = " << val << endl ;
1824 
1825  return val ;
1826 }
1827 
1828 
1829 
1830 ////////////////////////////////////////////////////////////////////////////////
1831 /// Obsolete
1832 
1833 Bool_t RooProdPdf::checkObservables(const RooArgSet* /*nset*/) const
1834 { return kFALSE ; }
1835 
1836 
1837 
1838 
1839 ////////////////////////////////////////////////////////////////////////////////
1840 /// If this product contains exactly one extendable p.d.f return the extension abilities of
1841 /// that p.d.f, otherwise return CanNotBeExtended
1842 
1843 RooAbsPdf::ExtendMode RooProdPdf::extendMode() const
1844 {
1845  return (_extendedIndex>=0) ? ((RooAbsPdf*)_pdfList.at(_extendedIndex))->extendMode() : CanNotBeExtended ;
1846 }
1847 
1848 
1849 
1850 ////////////////////////////////////////////////////////////////////////////////
1851 /// Return the expected number of events associated with the extendable input PDF
1852 /// in the product. If there is no extendable term, abort.
1853 
1854 Double_t RooProdPdf::expectedEvents(const RooArgSet* nset) const
1855 {
1856  if (_extendedIndex<0) {
1857  coutF(Generation) << "Requesting expected number of events from a RooProdPdf that does not contain an extended p.d.f" << endl ;
1858  throw std::logic_error(std::string("RooProdPdf ") + GetName() + " could not be extended.");
1859  }
1860 
1861  return ((RooAbsPdf*)_pdfList.at(_extendedIndex))->expectedEvents(nset) ;
1862 }
1863 
1864 
1865 
1866 ////////////////////////////////////////////////////////////////////////////////
1867 /// Return generator context optimized for generating events from product p.d.f.s
1868 
1869 RooAbsGenContext* RooProdPdf::genContext(const RooArgSet &vars, const RooDataSet *prototype,
1870  const RooArgSet* auxProto, Bool_t verbose) const
1871 {
1872  if (_useDefaultGen) return RooAbsPdf::genContext(vars,prototype,auxProto,verbose) ;
1873  return new RooProdGenContext(*this,vars,prototype,auxProto,verbose) ;
1874 }
1875 
1876 
1877 
1878 ////////////////////////////////////////////////////////////////////////////////
1879 /// Query internal generation capabilities of component p.d.f.s and aggregate capabilities
1880 /// into master configuration passed to the generator context
1881 
1882 Int_t RooProdPdf::getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, Bool_t staticInitOK) const
1883 {
1884  if (!_useDefaultGen) return 0 ;
1885 
1886  // Find the subset directVars that only depend on a single PDF in the product
1887  RooArgSet directSafe ;
1888  RooFIter dIter = directVars.fwdIterator() ;
1889  RooAbsArg* arg ;
1890  while((arg=(RooAbsArg*)dIter.next())) {
1891  if (isDirectGenSafe(*arg)) directSafe.add(*arg) ;
1892  }
1893 
1894 
1895  // Now find direct integrator for relevant components ;
1896  RooAbsPdf* pdf ;
1897  std::vector<Int_t> code;
1898  code.reserve(64);
1899  RooFIter pdfIter = _pdfList.fwdIterator();
1900  while((pdf=(RooAbsPdf*)pdfIter.next())) {
1901  RooArgSet pdfDirect ;
1902  Int_t pdfCode = pdf->getGenerator(directSafe,pdfDirect,staticInitOK);
1903  code.push_back(pdfCode);
1904  if (pdfCode != 0) {
1905  generateVars.add(pdfDirect) ;
1906  }
1907  }
1908 
1909 
1910  if (generateVars.getSize()>0) {
1911  Int_t masterCode = _genCode.store(code) ;
1912  return masterCode+1 ;
1913  } else {
1914  return 0 ;
1915  }
1916 }
1917 
1918 
1919 
1920 ////////////////////////////////////////////////////////////////////////////////
1921 /// Forward one-time initialization call to component generation initialization
1922 /// methods.
1923 
1924 void RooProdPdf::initGenerator(Int_t code)
1925 {
1926  if (!_useDefaultGen) return ;
1927 
1928  const std::vector<Int_t>& codeList = _genCode.retrieve(code-1) ;
1929  RooAbsPdf* pdf ;
1930  Int_t i(0) ;
1931  RooFIter pdfIter = _pdfList.fwdIterator();
1932  while((pdf=(RooAbsPdf*)pdfIter.next())) {
1933  if (codeList[i]!=0) {
1934  pdf->initGenerator(codeList[i]) ;
1935  }
1936  i++ ;
1937  }
1938 }
1939 
1940 
1941 
1942 ////////////////////////////////////////////////////////////////////////////////
1943 /// Generate a single event with configuration specified by 'code'
1944 /// Defer internal generation to components as encoded in the _genCode
1945 /// registry for given generator code.
1946 
1947 void RooProdPdf::generateEvent(Int_t code)
1948 {
1949  if (!_useDefaultGen) return ;
1950 
1951  const std::vector<Int_t>& codeList = _genCode.retrieve(code-1) ;
1952  RooAbsPdf* pdf ;
1953  Int_t i(0) ;
1954  RooFIter pdfIter = _pdfList.fwdIterator();
1955  while((pdf=(RooAbsPdf*)pdfIter.next())) {
1956  if (codeList[i]!=0) {
1957  pdf->generateEvent(codeList[i]) ;
1958  }
1959  i++ ;
1960  }
1961 }
1962 
1963 
1964 
1965 ////////////////////////////////////////////////////////////////////////////////
1966 /// Return RooAbsArg components contained in the cache
1967 
1968 RooArgList RooProdPdf::CacheElem::containedArgs(Action)
1969 {
1970  RooArgList ret ;
1971  ret.add(_partList) ;
1972  ret.add(_numList) ;
1973  ret.add(_denList) ;
1974  if (_rearrangedNum) ret.add(*_rearrangedNum) ;
1975  if (_rearrangedDen) ret.add(*_rearrangedDen) ;
1976  return ret ;
1977 
1978 }
1979 
1980 
1981 
1982 ////////////////////////////////////////////////////////////////////////////////
1983 /// Hook function to print cache contents in tree printing of RooProdPdf
1984 
1985 void RooProdPdf::CacheElem::printCompactTreeHook(ostream& os, const char* indent, Int_t curElem, Int_t maxElem)
1986 {
1987  if (curElem==0) {
1988  os << indent << "RooProdPdf begin partial integral cache" << endl ;
1989  }
1990 
1991  RooFIter iter = _partList.fwdIterator() ;
1992  RooAbsArg* arg ;
1993  TString indent2(indent) ;
1994  indent2 += Form("[%d] ",curElem) ;
1995  while((arg=(RooAbsArg*)iter.next())) {
1996  arg->printCompactTree(os,indent2) ;
1997  }
1998 
1999  if (curElem==maxElem) {
2000  os << indent << "RooProdPdf end partial integral cache" << endl ;
2001  }
2002 }
2003 
2004 
2005 
2006 ////////////////////////////////////////////////////////////////////////////////
2007 /// Forward determination of safety of internal generator code to
2008 /// component p.d.f that would generate the given observable
2009 
2010 Bool_t RooProdPdf::isDirectGenSafe(const RooAbsArg& arg) const
2011 {
2012  // Only override base class behaviour if default generator method is enabled
2013  if (!_useDefaultGen) return RooAbsPdf::isDirectGenSafe(arg) ;
2014 
2015  // Argument may appear in only one PDF component
2016  RooAbsPdf* pdf, *thePdf(0) ;
2017  RooFIter pdfIter = _pdfList.fwdIterator();
2018  while((pdf=(RooAbsPdf*)pdfIter.next())) {
2019 
2020  if (pdf->dependsOn(arg)) {
2021  // Found PDF depending on arg
2022 
2023  // If multiple PDFs depend on arg directGen is not safe
2024  if (thePdf) return kFALSE ;
2025 
2026  thePdf = pdf ;
2027  }
2028  }
2029  // Forward call to relevant component PDF
2030  return thePdf?(thePdf->isDirectGenSafe(arg)):kFALSE ;
2031 }
2032 
2033 
2034 
2035 ////////////////////////////////////////////////////////////////////////////////
2036 /// Look up user specified normalization set for given input PDF component
2037 
2038 RooArgSet* RooProdPdf::findPdfNSet(RooAbsPdf& pdf) const
2039 {
2040  Int_t idx = _pdfList.index(&pdf) ;
2041  if (idx<0) return 0 ;
2042  return (RooArgSet*) _pdfNSetList.At(idx) ;
2043 }
2044 
2045 
2046 
2047 ////////////////////////////////////////////////////////////////////////////////
2048 /// Return all parameter constraint p.d.f.s on parameters listed in constrainedParams.
2049 /// The observables set is required to distinguish unambiguously p.d.f in terms
2050 /// of observables and parameters, which are not constraints, and p.d.fs in terms
2051 /// of parameters only, which can serve as constraints p.d.f.s
2052 
2053 RooArgSet* RooProdPdf::getConstraints(const RooArgSet& observables, RooArgSet& constrainedParams, Bool_t stripDisconnected) const
2054 {
2055  RooArgSet constraints ;
2056  RooArgSet pdfParams, conParams ;
2057 
2058  // Loop over p.d.f. components
2059  RooFIter piter = _pdfList.fwdIterator() ;
2060  RooAbsPdf* pdf ;
2061  while((pdf=(RooAbsPdf*)piter.next())) {
2062  // A constraint term is a p.d.f that does not depend on any of the listed observables
2063  // but does depends on any of the parameters that should be constrained
2064  if (!pdf->dependsOnValue(observables) && pdf->dependsOnValue(constrainedParams)) {
2065  constraints.add(*pdf) ;
2066  RooArgSet* tmp = pdf->getParameters(observables) ;
2067  conParams.add(*tmp,kTRUE) ;
2068  delete tmp ;
2069  } else {
2070  RooArgSet* tmp = pdf->getParameters(observables) ;
2071  pdfParams.add(*tmp,kTRUE) ;
2072  delete tmp ;
2073  }
2074  }
2075 
2076  // Strip any constraints that are completely decoupled from the other product terms
2077  RooArgSet* finalConstraints = new RooArgSet("constraints") ;
2078  RooFIter citer = constraints.fwdIterator() ;
2079  while((pdf=(RooAbsPdf*)citer.next())) {
2080  if (pdf->dependsOnValue(pdfParams) || !stripDisconnected) {
2081  finalConstraints->add(*pdf) ;
2082  } else {
2083  coutI(Minimization) << "RooProdPdf::getConstraints(" << GetName() << ") omitting term " << pdf->GetName()
2084  << " as constraint term as it does not share any parameters with the other pdfs in product. "
2085  << "To force inclusion in likelihood, add an explicit Constrain() argument for the target parameter" << endl ;
2086  }
2087  }
2088 
2089  // Now remove from constrainedParams all parameters that occur exclusively in constraint term and not in regular pdf term
2090 
2091  RooArgSet* cexl = (RooArgSet*) conParams.selectCommon(constrainedParams) ;
2092  cexl->remove(pdfParams,kTRUE,kTRUE) ;
2093  constrainedParams.remove(*cexl,kTRUE,kTRUE) ;
2094  delete cexl ;
2095 
2096  return finalConstraints ;
2097 }
2098 
2099 
2100 
2101 
2102 ////////////////////////////////////////////////////////////////////////////////
2103 /// Return all parameter constraint p.d.f.s on parameters listed in constrainedParams.
2104 /// The observables set is required to distinguish unambiguously p.d.f in terms
2105 /// of observables and parameters, which are not constraints, and p.d.fs in terms
2106 /// of parameters only, which can serve as constraints p.d.f.s
2107 
2108 RooArgSet* RooProdPdf::getConnectedParameters(const RooArgSet& observables) const
2109 {
2110  RooArgSet* connectedPars = new RooArgSet("connectedPars") ;
2111  for (const auto arg : _pdfList) {
2112  // Check if term is relevant
2113  if (arg->dependsOn(observables)) {
2114  RooArgSet* tmp = arg->getParameters(observables) ;
2115  connectedPars->add(*tmp) ;
2116  delete tmp ;
2117  }
2118  }
2119  return connectedPars ;
2120 }
2121 
2122 
2123 
2124 
2125 ////////////////////////////////////////////////////////////////////////////////
2126 
2127 void RooProdPdf::getParametersHook(const RooArgSet* nset, RooArgSet* params, Bool_t stripDisconnected) const
2128 {
2129  if (!stripDisconnected) return ;
2130  if (!nset || nset->getSize()==0) return ;
2131 
2132  // Get/create appropriate term list for this normalization set
2133  Int_t code = getPartIntList(nset, nullptr);
2134  RooArgList & plist = static_cast<CacheElem*>(_cacheMgr.getObj(nset, &code))->_partList;
2135 
2136  // Strip any terms from params that do not depend on any term
2137  RooArgSet tostrip ;
2138  for (auto param : *params) {
2139  Bool_t anyDep(kFALSE) ;
2140  for (auto term : plist) {
2141  if (term->dependsOnValue(*param)) {
2142  anyDep=kTRUE ;
2143  }
2144  }
2145  if (!anyDep) {
2146  tostrip.add(*param) ;
2147  }
2148  }
2149 
2150  if (tostrip.getSize()>0) {
2151  params->remove(tostrip,kTRUE,kTRUE);
2152  }
2153 
2154 }
2155 
2156 
2157 
2158 ////////////////////////////////////////////////////////////////////////////////
2159 /// Interface function used by test statistics to freeze choice of range
2160 /// for interpretation of conditional product terms
2161 
2162 void RooProdPdf::selectNormalizationRange(const char* rangeName, Bool_t force)
2163 {
2164  if (!force && _refRangeName) {
2165  return ;
2166  }
2167 
2168  fixRefRange(rangeName) ;
2169 }
2170 
2171 
2172 
2173 
2174 ////////////////////////////////////////////////////////////////////////////////
2175 
2176 void RooProdPdf::fixRefRange(const char* rangeName)
2177 {
2178  _refRangeName = (TNamed*)RooNameReg::ptr(rangeName) ;
2179 }
2180 
2181 
2182 
2183 ////////////////////////////////////////////////////////////////////////////////
2184 /// Forward the plot sampling hint from the p.d.f. that defines the observable obs
2185 
2186 std::list<Double_t>* RooProdPdf::plotSamplingHint(RooAbsRealLValue& obs, Double_t xlo, Double_t xhi) const
2187 {
2188  RooAbsPdf* pdf ;
2189  RooFIter pdfIter = _pdfList.fwdIterator();
2190  while((pdf=(RooAbsPdf*)pdfIter.next())) {
2191  list<Double_t>* hint = pdf->plotSamplingHint(obs,xlo,xhi) ;
2192  if (hint) {
2193  return hint ;
2194  }
2195  }
2196 
2197  return 0 ;
2198 }
2199 
2200 
2201 
2202 ////////////////////////////////////////////////////////////////////////////////
2203 /// If all components that depend on obs are binned that so is the product
2204 
2205 Bool_t RooProdPdf::isBinnedDistribution(const RooArgSet& obs) const
2206 {
2207  RooAbsPdf* pdf ;
2208  RooFIter pdfIter = _pdfList.fwdIterator();
2209  while((pdf=(RooAbsPdf*)pdfIter.next())) {
2210  if (pdf->dependsOn(obs) && !pdf->isBinnedDistribution(obs)) {
2211  return kFALSE ;
2212  }
2213  }
2214 
2215  return kTRUE ;
2216 }
2217 
2218 
2219 
2220 
2221 
2222 
2223 ////////////////////////////////////////////////////////////////////////////////
2224 /// Forward the plot sampling hint from the p.d.f. that defines the observable obs
2225 
2226 std::list<Double_t>* RooProdPdf::binBoundaries(RooAbsRealLValue& obs, Double_t xlo, Double_t xhi) const
2227 {
2228  RooAbsPdf* pdf ;
2229  RooFIter pdfIter = _pdfList.fwdIterator();
2230  while((pdf=(RooAbsPdf*)pdfIter.next())) {
2231  list<Double_t>* hint = pdf->binBoundaries(obs,xlo,xhi) ;
2232  if (hint) {
2233  return hint ;
2234  }
2235  }
2236 
2237  return 0 ;
2238 }
2239 
2240 
2241 ////////////////////////////////////////////////////////////////////////////////
2242 /// Label OK'ed components of a RooProdPdf with cache-and-track, _and_ label all RooProdPdf
2243 /// descendants with extra information about (conditional) normalization, needed to be able
2244 /// to Cache-And-Track them outside the RooProdPdf context.
2245 
2246 void RooProdPdf::setCacheAndTrackHints(RooArgSet& trackNodes)
2247 {
2248  for (const auto parg : _pdfList) {
2249 
2250  if (parg->canNodeBeCached()==Always) {
2251  trackNodes.add(*parg) ;
2252 // cout << "tracking node RooProdPdf component " << parg << " " << parg->IsA()->GetName() << "::" << parg->GetName() << endl ;
2253 
2254  // Additional processing to fix normalization sets in case product defines conditional observables
2255  RooArgSet* pdf_nset = findPdfNSet((RooAbsPdf&)(*parg)) ;
2256  if (pdf_nset) {
2257  // Check if conditional normalization is specified
2258  if (string("nset")==pdf_nset->GetName() && pdf_nset->getSize()>0) {
2259  RooNameSet n(*pdf_nset) ;
2260  parg->setStringAttribute("CATNormSet",n.content()) ;
2261  }
2262  if (string("cset")==pdf_nset->GetName()) {
2263  RooNameSet c(*pdf_nset) ;
2264  parg->setStringAttribute("CATCondSet",c.content()) ;
2265  }
2266  } else {
2267  coutW(Optimization) << "RooProdPdf::setCacheAndTrackHints(" << GetName() << ") WARNING product pdf does not specify a normalization set for component " << parg->GetName() << endl ;
2268  }
2269  }
2270  }
2271 }
2272 
2273 
2274 
2275 ////////////////////////////////////////////////////////////////////////////////
2276 /// Customized printing of arguments of a RooProdPdf to more intuitively reflect the contents of the
2277 /// product operator construction
2278 
2279 void RooProdPdf::printMetaArgs(ostream& os) const
2280 {
2281  RooFIter niter = _pdfNSetList.fwdIterator() ;
2282  for (int i=0 ; i<_pdfList.getSize() ; i++) {
2283  if (i>0) os << " * " ;
2284  RooArgSet* ncset = (RooArgSet*) niter.next() ;
2285  os << _pdfList.at(i)->GetName() ;
2286  if (ncset->getSize()>0) {
2287  if (string("nset")==ncset->GetName()) {
2288  os << *ncset ;
2289  } else {
2290  os << "|" ;
2291  RooFIter nciter = ncset->fwdIterator() ;
2292  RooAbsArg* arg ;
2293  Bool_t first(kTRUE) ;
2294  while((arg=(RooAbsArg*)nciter.next())) {
2295  if (!first) {
2296  os << "," ;
2297  } else {
2298  first = kFALSE ;
2299  }
2300  os << arg->GetName() ;
2301  }
2302  }
2303  }
2304  }
2305  os << " " ;
2306 }
2307 
2308 
2309 
2310 ////////////////////////////////////////////////////////////////////////////////
2311 /// Implement support for node removal
2312 
2313 Bool_t RooProdPdf::redirectServersHook(const RooAbsCollection& /*newServerList*/, Bool_t /*mustReplaceAll*/, Bool_t nameChange, Bool_t /*isRecursive*/)
2314 {
2315  if (nameChange && _pdfList.find("REMOVAL_DUMMY")) {
2316 
2317  cxcoutD(LinkStateMgmt) << "RooProdPdf::redirectServersHook(" << GetName() << "): removing REMOVAL_DUMMY" << endl ;
2318 
2319  // Remove node from _pdfList proxy and remove corresponding entry from normset list
2320  RooAbsArg* pdfDel = _pdfList.find("REMOVAL_DUMMY") ;
2321 
2322  TObject* setDel = _pdfNSetList.At(_pdfList.index("REMOVAL_DUMMY")) ;
2323  _pdfList.remove(*pdfDel) ;
2324  _pdfNSetList.Remove(setDel) ;
2325 
2326  // Clear caches
2327  _cacheMgr.reset() ;
2328  }
2329  return kFALSE ;
2330 }