Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooMomentMorphFuncND.cxx
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 *
4 * Copyright (c) 2023, CERN
5 *
6 * Redistribution and use in source and binary forms,
7 * with or without modification, are permitted according to the terms
8 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
9 */
10
11/** \class RooMomentMorphFuncND
12 \ingroup Roofit
13
14**/
15
17
18#include <RooAbsCategory.h>
19#include <RooAbsMoment.h>
20#include <RooAddPdf.h>
21#include <RooAddition.h>
22#include <RooChangeTracker.h>
23#include <RooConstVar.h>
24#include <RooCustomizer.h>
25#include <RooFormulaVar.h>
26#include <RooLinearVar.h>
27#include <RooMoment.h>
28#include <RooNumIntConfig.h>
29#include <RooRealSumFunc.h>
30#include <RooRealVar.h>
31
33
34#include <Riostream.h>
35
36#include <TMap.h>
37#include <TMath.h>
38#include <TVector.h>
39
40#include <algorithm>
41#include <map>
42
43using std::string, std::vector;
44
45
46//_____________________________________________________________________________
47RooMomentMorphFuncND::RooMomentMorphFuncND() : _cacheMgr(this, 10, true, true), _setting(RooMomentMorphFuncND::Linear), _useHorizMorph(true)
48{
49}
50
51//_____________________________________________________________________________
55 _cacheMgr(this, 10, true, true),
56 _parList("parList", "List of morph parameters", this),
57 _obsList("obsList", "List of observables", this),
58 _referenceGrid(referenceGrid),
59 _pdfList("pdfList", "List of pdfs", this),
60 _setting(setting),
61 _useHorizMorph(true)
62{
63 // morph parameters
65
66 // observables
68
70
71 // general initialization
72 initialize();
73
74}
75
76//_____________________________________________________________________________
78 const RooArgList &pdfList, const TVectorD &mrefpoints, Setting setting)
80 _cacheMgr(this, 10, true, true),
81 _parList("parList", "List of morph parameters", this),
82 _obsList("obsList", "List of observables", this),
83 _pdfList("pdfList", "List of pdfs", this),
84 _setting(setting),
85 _useHorizMorph(true)
86{
87 // make reference grid
88 RooBinning grid(mrefpoints.GetNrows() - 1, mrefpoints.GetMatrixArray());
90
91 for (int i = 0; i < mrefpoints.GetNrows(); ++i) {
92 for (int j = 0; j < grid.numBoundaries(); ++j) {
93 if (mrefpoints[i] == grid.array()[j]) {
94 _referenceGrid.addPdf(*static_cast<Base_t *>(pdfList.at(i)), j);
95 break;
96 }
97 }
98 }
99
101
102 // morph parameters
104 parList.add(_m);
106
107 // observables
109
110 // general initialization
111 initialize();
112
113}
114
115//_____________________________________________________________________________
117 const RooArgList &pdfList, const RooArgList &mrefList, Setting setting)
119 _cacheMgr(this, 10, true, true),
120 _parList("parList", "List of morph parameters", this),
121 _obsList("obsList", "List of observables", this),
122 _pdfList("pdfList", "List of pdfs", this),
123 _setting(setting),
124 _useHorizMorph(true)
125{
126 // make reference grid
128 Int_t i = 0;
129 for (auto *mref : mrefList) {
130 if (!dynamic_cast<RooAbsReal *>(mref)) {
131 coutE(InputArguments) << "RooMomentMorphFuncND::ctor(" << GetName() << ") ERROR: mref " << mref->GetName()
132 << " is not of type RooAbsReal" << std::endl;
133 throw string("RooMomentMorphFuncND::ctor() ERROR mref is not of type RooAbsReal");
134 }
135 if (!dynamic_cast<RooConstVar *>(mref)) {
136 coutW(InputArguments) << "RooMomentMorphFuncND::ctor(" << GetName() << ") WARNING mref point " << i
137 << " is not a constant, taking a snapshot of its value" << std::endl;
138 }
139 mrefpoints[i] = static_cast<RooAbsReal *>(mref)->getVal();
140 i++;
141 }
142
143 RooBinning grid(mrefpoints.GetNrows() - 1, mrefpoints.GetMatrixArray());
145 for (i = 0; i < mrefpoints.GetNrows(); ++i) {
146 for (int j = 0; j < grid.numBoundaries(); ++j) {
147 if (mrefpoints[i] == grid.array()[j]) {
148 _referenceGrid.addPdf(static_cast<Base_t &>(pdfList[i]), j);
149 break;
150 }
151 }
152 }
153
155
156 // morph parameters
158 parList.add(_m);
160
161 // observables
163
164 // general initialization
165 initialize();
166
167}
168
169//_____________________________________________________________________________
172 _cacheMgr(other._cacheMgr, this),
173 _parList("parList", this, other._parList),
174 _obsList("obsList", this, other._obsList),
175 _referenceGrid(other._referenceGrid),
176 _pdfList("pdfList", this, other._pdfList),
177 _setting(other._setting),
178 _useHorizMorph(other._useHorizMorph),
179 _isPdfMode{other._isPdfMode}
180{
181 // general initialization
182 initialize();
183
184}
185
186//_____________________________________________________________________________
190
191//_____________________________________________________________________________
193{
194 for (vector<RooAbsBinning *>::iterator itr = _referenceGrid._grid.begin(); itr != _referenceGrid._grid.end();
195 ++itr) {
196 _referenceGrid._nnuis.push_back((*itr)->numBins() + 1);
197 }
198
199 int nPar = _parList.size();
200 int nDim = _referenceGrid._grid.size();
202 int nRef = _referenceGrid._nref.size();
203 int depth = std::pow(2, nPar);
204
205 if (nPar != nDim) {
206 coutE(InputArguments) << "RooMomentMorphFuncND::initialize(" << GetName() << ") ERROR: nPar != nDim"
207 << ": " << nPar << " !=" << nDim << std::endl;
208 assert(0);
209 }
210
211 if (nPdf != nRef) {
212 coutE(InputArguments) << "RooMomentMorphFuncND::initialize(" << GetName() << ") ERROR: nPdf != nRef"
213 << ": " << nPdf << " !=" << nRef << std::endl;
214 assert(0);
215 }
216
217 // Transformation matrix for NonLinear settings
218 _M = std::make_unique<TMatrixD>(nPdf, nPdf);
219 _MSqr = std::make_unique<TMatrixD>(depth, depth);
221 TMatrixD M(nPdf, nPdf);
222
224 for (int k = 0; k < nPdf; ++k) {
226 for (int idim = 0; idim < nPar; idim++) {
227 double delta = _referenceGrid._nref[k][idim] - _referenceGrid._nref[0][idim];
228 dm2.push_back(delta);
229 }
230 dm[k] = dm2;
231 }
232
234 for (int idim = 0; idim < nPar; idim++) {
236 xtmp.reserve(_referenceGrid._nnuis[idim]);
237 for (int ix = 0; ix < _referenceGrid._nnuis[idim]; ix++) {
238 xtmp.push_back(ix);
239 }
240 powers.push_back(xtmp);
241 }
242
243 vector<vector<int>> output;
245 int nCombs = output.size();
246
247 for (int k = 0; k < nPdf; ++k) {
248 int nperm = 0;
249 for (int i = 0; i < nCombs; i++) {
250 double tmpDm = 1.0;
251 for (int ix = 0; ix < nPar; ix++) {
252 double delta = dm[k][ix];
253 tmpDm *= std::pow(delta, static_cast<double>(output[i][ix]));
254 }
255 M(k, nperm) = tmpDm;
256 nperm++;
257 }
258 }
259
260 // M.Print();
261 (*_M) = M.Invert();
262 }
263
264 // Resize transformation vectors
265 _squareVec.resize(std::pow(2, nPar));
266 _squareIdx.resize(std::pow(2, nPar));
267}
268
269//_____________________________________________________________________________
271 : _pdfList(other._pdfList), _pdfMap(other._pdfMap), _nref(other._nref)
272{
273 for (unsigned int i = 0; i < other._grid.size(); i++) {
274 _grid.push_back(other._grid[i]->clone());
275 }
276}
277
278//_____________________________________________________________________________
280{
281 for (RooAbsBinning *binning : _grid) {
282 delete binning;
283 }
284}
285
286//_____________________________________________________________________________
288{
291 thisBoundaries.push_back(bin_x);
292 thisBoundaryCoordinates.push_back(_grid[0]->array()[bin_x]);
293 _pdfList.add(pdf);
294 _pdfMap[thisBoundaries] = _pdfList.size() - 1;
295 _nref.push_back(thisBoundaryCoordinates);
296}
297
298//_____________________________________________________________________________
300{
303 thisBoundaries.push_back(bin_x);
304 thisBoundaryCoordinates.push_back(_grid[0]->array()[bin_x]);
305 thisBoundaries.push_back(bin_y);
306 thisBoundaryCoordinates.push_back(_grid[1]->array()[bin_y]);
307 _pdfList.add(pdf);
308 _pdfMap[thisBoundaries] = _pdfList.size() - 1;
309 _nref.push_back(thisBoundaryCoordinates);
310}
311
312//_____________________________________________________________________________
314{
317 thisBoundaries.push_back(bin_x);
318 thisBoundaryCoordinates.push_back(_grid[0]->array()[bin_x]);
319 thisBoundaries.push_back(bin_y);
320 thisBoundaryCoordinates.push_back(_grid[1]->array()[bin_y]);
321 thisBoundaries.push_back(bin_z);
322 thisBoundaryCoordinates.push_back(_grid[2]->array()[bin_z]);
323 _pdfList.add(pdf);
324 _pdfMap[thisBoundaries] = _pdfList.size() - 1;
325 _nref.push_back(thisBoundaryCoordinates);
326}
327
328//_____________________________________________________________________________
330{
332 int nBins = bins.size();
333 thisBoundaryCoordinates.reserve(nBins);
334 for (int i = 0; i < nBins; i++) {
335 thisBoundaryCoordinates.push_back(_grid[i]->array()[bins[i]]);
336 }
337 _pdfList.add(pdf);
338 _pdfMap[bins] = _pdfList.size() - 1;
339 _nref.push_back(thisBoundaryCoordinates);
340}
341
342//_____________________________________________________________________________
343std::unique_ptr<RooAbsArg>
345{
346 // Build (or fetch) the cache that holds the morph's internal compute graph:
347 // moment integrals, slope/offset formulas, RooLinearVar transforms, the per-pdf
348 // RooHistPdf clones, and the final RooAddPdf/RooRealSumFunc sum.
349 CacheElem *cache = getCache(&normSet);
350
351 // Make sure fractions hold sensible initial values (the replacement nodes
352 // below will keep them in sync going forward).
353 cache->calculateFractions(*this, false);
354
355 // The cache's subtree carries ORIGNAME: attributes left over from the
356 // RooCustomizer that built the per-pdf transformed RooHistPdf clones (it
357 // tagged each transVar with ORIGNAME:<obs>). RooCustomizer::build calls
358 // redirectServers with nameChange=true and will throw if it sees several
359 // candidates with the same ORIGNAME:* attribute, which is exactly what
360 // happens here once we ask it to clone the subtree. Strip those stale
361 // markers before cloning.
362 {
364 cache->_sum->branchNodeServerList(&branches);
365 for (auto *b : branches) {
366 std::vector<std::string> toRemove;
367 for (auto const &attr : b->attributes()) {
368 if (attr.rfind("ORIGNAME:", 0) == 0)
369 toRemove.push_back(attr);
370 }
371 for (auto const &attr : toRemove)
372 b->setAttribute(attr.c_str(), false);
373 }
374 }
375
376 // Replace each of the imperatively-updated fraction RooRealVars with a
377 // RooMomentMorphFraction node. This puts the fraction-recomputation inside
378 // the Evaluator's compute graph, so the moment integrals (which the
379 // fractions depend on transitively via the slope/offset formulas) become
380 // sibling nodes that the Evaluator caches once per minimization step.
382 const int nFrac = cache->_frac.size();
383 for (int i = 0; i < nFrac; ++i) {
384 auto frac = static_cast<RooRealVar *>(cache->_frac.at(i));
385 std::string newName = std::string{frac->GetName()} + "_compiled";
386 newFractions.addOwned(
387 std::make_unique<RooFit::Detail::RooMomentMorphFraction>(newName.c_str(), frac->GetTitle(), *this, i));
388 }
389
391 RooCustomizer cust(*cache->_sum, "compiled");
392 cust.setCloneBranchSet(clonedBranches);
393 for (int i = 0; i < nFrac; ++i) {
394 cust.replaceArg(*cache->_frac.at(i), newFractions[i]);
395 }
396
397 // RooCustomizer::build() already transfers ownership of the cloned branches
398 // (everything in `clonedBranches` except the returned top node) to the new
399 // top node's owned-components list, so we only have to attach the
400 // newly-created fraction nodes here.
401 std::unique_ptr<RooAbsReal> newSum{static_cast<RooAbsReal *>(cust.build())};
402 newSum->addOwnedComponents(std::move(newFractions));
403
404 if (_isPdfMode) {
405 // In pdf mode, _sum is a RooAddPdf whose value should be the normalized
406 // morph density. We must let the inner RooHistPdf clones go through
407 // their own compileForNormSet so they get wrapped in a RooNormalizedPdf.
409 newSum->branchNodeServerList(&branches);
410 for (auto *b : branches) {
411 if (dynamic_cast<RooFit::Detail::RooMomentMorphFraction *>(b))
412 ctx.markAsCompiled(*b);
413 }
415 } else {
416 // Non-pdf mode: _sum is a RooRealSumFunc and the legacy path returns
417 // the raw weighted sum of the per-pdf bin values, with no per-component
418 // normalization. So cloned subtree is already in its final form.
421 }
422
423 return newSum;
424}
425
426namespace RooFit {
427namespace Detail {
428
429RooMomentMorphFraction::RooMomentMorphFraction(const char *name, const char *title, RooMomentMorphFuncND const &parent,
430 int index)
431 : RooAbsReal(name, title), _parList("parList", "parList", this), _parent(&parent), _index(index)
432{
433 _parList.add(parent._parList);
434}
435
437 : RooAbsReal(other, name), _parList("parList", this, other._parList), _parent(other._parent), _index(other._index)
438{
439}
440
442{
443 auto *cache = _parent->getCache(nullptr);
444 if (cache->_tracker->hasChanged(true)) {
445 cache->calculateFractions(*_parent, false);
446 }
447 return cache->frac(_index)->getVal();
448}
449
450} // namespace Detail
451} // namespace RooFit
452
453//_____________________________________________________________________________
455{
456 auto cache = static_cast<CacheElem *>(_cacheMgr.getObj(nullptr, static_cast<RooArgSet const*>(nullptr)));
457 if (cache) {
458 return cache;
459 }
460
461 int nObs = _obsList.size();
463
464 RooAbsReal *null = nullptr;
465 vector<RooAbsReal *> meanrv(nPdf * nObs, null);
466 vector<RooAbsReal *> sigmarv(nPdf * nObs, null);
467 vector<RooAbsReal *> myrms(nObs, null);
468 vector<RooAbsReal *> mypos(nObs, null);
469 vector<RooAbsReal *> slope(nPdf * nObs, null);
470 vector<RooAbsReal *> offsets(nPdf * nObs, null);
471 vector<RooAbsReal *> transVar(nPdf * nObs, null);
473
476
477 // fraction parameters
478 RooArgList coefList("coefList"); // fractions multiplied with input pdfs
479 RooArgList coefList2("coefList2"); // fractions multiplied with mean position of observable contribution
480 RooArgList coefList3("coefList3"); // fractions multiplied with rms position of observable contribution
481
482 for (int i = 0; i < 3 * nPdf; ++i) {
483 string fracName = Form("frac_%d", i);
484 double initval = _isPdfMode ? 1.0 : 0.0;
485 RooRealVar *frac = new RooRealVar(fracName.c_str(), fracName.c_str(), initval); // to be set later
486
487 fracl.add(*frac);
488 if (i < nPdf) {
489 coefList.add(*static_cast<RooRealVar *>(fracl.at(i)));
490 } else if (i < 2 * nPdf) {
491 coefList2.add(*static_cast<RooRealVar *>(fracl.at(i)));
492 } else {
493 coefList3.add(*static_cast<RooRealVar *>(fracl.at(i)));
494 }
495 ownedComps.add(*static_cast<RooRealVar *>(fracl.at(i)));
496 }
497
498 std::unique_ptr<RooAbsReal> theSum;
499 string sumName = Form("%s_sum", GetName());
500
502 if (_useHorizMorph) {
503 // mean and sigma
505 for (int i = 0; i < nPdf; ++i) {
506 for (int j = 0; j < nObs; ++j) {
507 RooAbsMoment *mom = nObs == 1 ? (static_cast<Base_t *>(_pdfList.at(i)))->sigma(static_cast<RooRealVar &>(*obsList.at(j)))
508 : (static_cast<Base_t *>(_pdfList.at(i)))->sigma(static_cast<RooRealVar &>(*obsList.at(j)), obsList);
509
510 mom->setLocalNoDirtyInhibit(true);
511 mom->mean()->setLocalNoDirtyInhibit(true);
512
513 sigmarv[sij(i, j)] = mom;
514 meanrv[sij(i, j)] = mom->mean();
515
516 ownedComps.add(*sigmarv[sij(i, j)]);
517 }
518 }
519
520 // slope and offset (to be set later, depend on nuisance parameters)
521 for (int j = 0; j < nObs; ++j) {
522 RooArgList meanList("meanList");
523 RooArgList rmsList("rmsList");
524 for (int i = 0; i < nPdf; ++i) {
525 meanList.add(*meanrv[sij(i, j)]);
526 rmsList.add(*sigmarv[sij(i, j)]);
527 }
528 string myrmsName = Form("%s_rms_%d", GetName(), j);
529 string myposName = Form("%s_pos_%d", GetName(), j);
530 mypos[j] = new RooAddition(myposName.c_str(), myposName.c_str(), meanList, coefList2);
531 myrms[j] = new RooAddition(myrmsName.c_str(), myrmsName.c_str(), rmsList, coefList3);
532 ownedComps.add(RooArgSet(*myrms[j], *mypos[j]));
533 }
534
535 // construction of unit pdfs
536
537 Int_t i = 0;
538 for (auto const *pdf : static_range_cast<Base_t *>(_pdfList)) {
539
540 string pdfName = Form("pdf_%d", i);
541 RooCustomizer cust(*pdf, pdfName.c_str());
542
543 Int_t j = 0;
544 for (auto *var : static_range_cast<RooRealVar *>(obsList)) {
545 // slope and offset formulas
546 string slopeName = Form("%s_slope_%d_%d", GetName(), i, j);
547 string offsetName = Form("%s_offset_%d_%d", GetName(), i, j);
548
549 slope[sij(i, j)] =
550 new RooFormulaVar(slopeName.c_str(), "@0/@1", RooArgList(*sigmarv[sij(i, j)], *myrms[j]));
551 offsets[sij(i, j)] = new RooFormulaVar(offsetName.c_str(), "@0-(@1*@2)",
552 RooArgList(*meanrv[sij(i, j)], *mypos[j], *slope[sij(i, j)]));
553 ownedComps.add(RooArgSet(*slope[sij(i, j)], *offsets[sij(i, j)]));
554
555 // linear transformations, so pdf can be renormalized easily
556 string transVarName = Form("%s_transVar_%d_%d", GetName(), i, j);
557 transVar[sij(i, j)] = new RooLinearVar(transVarName.c_str(), transVarName.c_str(), *var, *slope[sij(i, j)],
558 *offsets[sij(i, j)]);
559
560 // *** WVE this is important *** this declares that frac effectively depends on the morphing parameters
561 // This will prevent the likelihood optimizers from erroneously declaring terms constant
562 transVar[sij(i, j)]->addServerList((RooAbsCollection &)_parList);
563
564 ownedComps.add(*transVar[sij(i, j)]);
565 cust.replaceArg(*var, *transVar[sij(i, j)]);
566 ++j;
567 }
568 transPdf[i] = static_cast<Base_t *>(cust.build());
569 transPdfList.add(*transPdf[i]);
570 ownedComps.add(*transPdf[i]);
571 ++i;
572 }
573 }
574
575 // sum pdf
576 RooArgList const &pdfList = _useHorizMorph ? transPdfList : static_cast<RooArgList const &>(_pdfList);
577 if (_isPdfMode) {
578 theSum = std::make_unique<RooAddPdf>(sumName.c_str(), sumName.c_str(), pdfList, coefList);
579 } else {
580 theSum = std::make_unique<RooRealSumFunc>(sumName.c_str(), sumName.c_str(), pdfList, coefList);
581 }
582
583 // *** WVE this is important *** this declares that frac effectively depends on the morphing parameters
584 // This will prevent the likelihood optimizers from erroneously declaring terms constant
585 theSum->addServerList((RooAbsCollection &)_parList);
586 theSum->addOwnedComponents(ownedComps);
587
588 // change tracker for fraction parameters
589 std::string trackerName = std::string(GetName()) + "_frac_tracker";
590
591 // Store it in the cache
592 cache = new CacheElem(std::move(theSum),
593 std::make_unique<RooChangeTracker>(trackerName.c_str(), trackerName.c_str(), _parList, true),
594 fracl);
595 _cacheMgr.setObj(nullptr, nullptr, cache, nullptr);
596
597 return cache;
598}
599
600RooMomentMorphFuncND::CacheElem::CacheElem(std::unique_ptr<RooAbsReal> &&sumFunc,
601 std::unique_ptr<RooChangeTracker> &&tracker, const RooArgList &flist)
602 : _sum(std::move(sumFunc)), _tracker(std::move(tracker))
603{
604 _frac.add(flist);
605}
606
607//_____________________________________________________________________________
612
613//_____________________________________________________________________________
615
616//_____________________________________________________________________________
618{
619 // Special version of getValV() overrides Base_t::getValV() to save value of current normalization set
620 _curNormSet = set ? const_cast<RooArgSet *>(set) : const_cast<RooArgSet *>(static_cast<RooArgSet const*>(&_obsList));
621 return Base_t::getValV(set);
622}
623
624//_____________________________________________________________________________
626{
627 CacheElem *cache = getCache(nset ? nset : _curNormSet);
628
629 if (cache->_tracker->hasChanged(true)) {
630 cache->calculateFractions(*this, false); // verbose turned off
631 }
632 return cache->_sum.get();
633}
634
635//_____________________________________________________________________________
637{
639
640 if (cache->_tracker->hasChanged(true)) {
641 cache->calculateFractions(*this, false); // verbose turned off
642 }
643
644 double ret = cache->_sum->getVal(_obsList.nset());
645
646 return ret;
647}
648
649//_____________________________________________________________________________
651{
652 return static_cast<RooRealVar *>(_frac.at(i));
653}
654
655//_____________________________________________________________________________
657{
658 return static_cast<RooRealVar *>(_frac.at(i));
659}
660
661//_____________________________________________________________________________
663{
664 int nPdf = self._pdfList.size();
665 int nPar = self._parList.size();
666
667 double fracLinear(1.);
668 double fracNonLinear(1.);
669
670 if (self._setting == NonLinear || self._setting == NonLinearLinFractions || self._setting == NonLinearPosFractions) {
671 // Calculate the delta vector
673 for (int idim = 0; idim < nPar; idim++) {
674 double delta = (static_cast<RooRealVar *>(self._parList.at(idim)))->getVal() - self._referenceGrid._nref[0][idim];
675 dm2.push_back(delta);
676 }
677
679 for (int idim = 0; idim < nPar; idim++) {
681 xtmp.reserve(self._referenceGrid._nnuis[idim]);
682 for (int ix = 0; ix < self._referenceGrid._nnuis[idim]; ix++) {
683 xtmp.push_back(ix);
684 }
685 powers.push_back(xtmp);
686 }
687
688 vector<vector<int>> output;
690 int nCombs = output.size();
691
693
694 int nperm = 0;
695 for (int i = 0; i < nCombs; i++) {
696 double tmpDm = 1.0;
697 for (int ix = 0; ix < nPar; ix++) {
698 double delta = dm2[ix];
699 tmpDm *= std::pow(delta, static_cast<double>(output[i][ix]));
700 }
702 nperm++;
703 }
704
705 double sumposfrac = 0.0;
706 for (int i = 0; i < nPdf; ++i) {
707 double ffrac = 0.0;
708
709 for (int j = 0; j < nPdf; ++j) {
710 ffrac += (*self._M)(j, i) * deltavec[j] * fracNonLinear;
711 }
712
713 if (ffrac >= 0) {
714 sumposfrac += ffrac;
715 }
716
717 // fractions for pdf
718 if (self._setting != NonLinearLinFractions) {
719 const_cast<RooRealVar *>(frac(i))->setVal(ffrac);
720 }
721
722 // fractions for rms and mean
723 const_cast<RooRealVar *>(frac(nPdf + i))->setVal(ffrac); // need to add up
724 const_cast<RooRealVar *>(frac(2 * nPdf + i))->setVal(ffrac); // need to add up
725
726 if (verbose) {
727 std::cout << "NonLinear fraction " << ffrac << std::endl;
728 frac(i)->Print();
729 frac(nPdf + i)->Print();
730 frac(2 * nPdf + i)->Print();
731 }
732 }
733
734 if (self._setting == NonLinearPosFractions) {
735 for (int i = 0; i < nPdf; ++i) {
736 if (frac(i)->getVal() < 0)
737 const_cast<RooRealVar *>(frac(i))->setVal(0.);
738 const_cast<RooRealVar *>(frac(i))->setVal(frac(i)->getVal() / sumposfrac);
739 }
740 }
741 }
742
743 if (self._setting == Linear || self._setting == NonLinearLinFractions) {
744 // zero all fractions
745 // for (int i = 0; i < 3*nPdf; ++i) {
746 for (int i = 0; i < nPdf; ++i) {
747 double initval = 0;
748 const_cast<RooRealVar *>(frac(i))->setVal(initval);
749 const_cast<RooRealVar *>(frac(nPdf + i))->setVal(initval);
750 const_cast<RooRealVar *>(frac(2 * nPdf + i))->setVal(initval);
751 }
752
753 std::vector<double> mtmp;
754
755 // loop over parList
756 for (auto *m : static_range_cast<RooRealVar *>(self._parList)) {
757 mtmp.push_back(m->getVal());
758 }
759
760 self.findShape(mtmp); // this sets _squareVec and _squareIdx quantities
761
762 int depth = std::pow(2, nPar);
764
765 int nperm = 0;
766
768 xtmp.reserve(nPar);
769 for (int ix = 0; ix < nPar; ix++) {
770 xtmp.push_back(ix);
771 }
772
773 for (int iperm = 1; iperm <= nPar; ++iperm) {
774 do {
775 double dtmp = mtmp[xtmp[0]] - self._squareVec[0][xtmp[0]];
776 for (int itmp = 1; itmp < iperm; ++itmp) {
777 dtmp *= mtmp[xtmp[itmp]] - self._squareVec[0][xtmp[itmp]];
778 }
779 deltavec[nperm + 1] = dtmp;
780 nperm++;
782 }
783
784 double origFrac1(0.);
785 double origFrac2(0.);
786 for (int i = 0; i < depth; ++i) {
787 double ffrac = 0.;
788 for (int j = 0; j < depth; ++j) {
789 ffrac += (*self._MSqr)(j, i) * deltavec[j] * fracLinear;
790 }
791
792 // set fractions for pdf
793 origFrac1 = frac(self._squareIdx[i])->getVal(); // already set in case of smoothlinear
794 const_cast<RooRealVar *>(frac(self._squareIdx[i]))->setVal(origFrac1 + ffrac); // need to add up
795
796 // set fractions for rms and mean
797 if (self._setting != NonLinearLinFractions) {
798 origFrac2 =
799 frac(nPdf + self._squareIdx[i])->getVal(); // already set in case of smoothlinear
800 const_cast<RooRealVar *>(frac(nPdf + self._squareIdx[i]))->setVal(origFrac2 + ffrac); // need to add up
801 const_cast<RooRealVar *>(frac(2 * nPdf + self._squareIdx[i]))->setVal(origFrac2 + ffrac); // need to add up
802 }
803
804 if (verbose) {
805 std::cout << "Linear fraction " << ffrac << std::endl;
806 frac(self._squareIdx[i])->Print();
807 frac(nPdf + self._squareIdx[i])->Print();
808 frac(2 * nPdf + self._squareIdx[i])->Print();
809 }
810 }
811 }
812}
813
814//_____________________________________________________________________________
816{
817 int nPar = _parList.size();
818 int nRef = _referenceGrid._nref.size();
819
820 // Find hypercube enclosing the location to morph to
821 // bool isEnclosed = true;
822 // for (int i = 0; i < nPar; i++) {
823 // if (x[i] < _referenceGrid._grid[i]->lowBound())
824 // isEnclosed = false;
825 // if (x[i] > _referenceGrid._grid[i]->highBound())
826 // isEnclosed = false;
827 // }
828
829 // std::cout << "isEnclosed = " << isEnclosed << std::endl;
830
831 int depth = std::pow(2, nPar);
832
833 vector<vector<double>> boundaries(nPar);
834 for (int idim = 0; idim < nPar; idim++) {
835 int bin = _referenceGrid._grid[idim]->binNumber(x[idim]);
836 double lo = _referenceGrid._grid[idim]->binLow(bin);
837 double hi = _referenceGrid._grid[idim]->binHigh(bin);
838 boundaries[idim].push_back(lo);
839 boundaries[idim].push_back(hi);
840 }
841
842 vector<vector<double>> output;
843 RooFit::Detail::cartesianProduct(output, boundaries);
844 _squareVec = output;
845
846 for (int isq = 0; isq < depth; isq++) {
847 // Reset to a sentinel before searching: if no matching reference point is
848 // found below, we must not silently keep the value left over from a
849 // previous, unrelated call to findShape() (e.g. from a different
850 // hypercube visited earlier in the fit). Falling through to a stale
851 // index here would make the interpolation depend on evaluation history
852 // instead of only on the current parameter point.
853 _squareIdx[isq] = -1;
854 for (int iref = 0; iref < nRef; iref++) {
857 break;
858 }
859 }
860 if (_squareIdx[isq] < 0) {
861 coutE(InputArguments) << "RooMomentMorphFuncND::findShape(" << GetName()
862 << ") ERROR: no reference pdf found for grid corner (";
863 for (unsigned int ix = 0; ix < _squareVec[isq].size(); ++ix) {
864 ccoutE(InputArguments) << (ix ? ", " : "") << _squareVec[isq][ix];
865 }
866 ccoutE(InputArguments) << ") of the hypercube enclosing the current morphing "
867 << "parameter point. The reference grid is missing a pdf at this "
868 << "coordinate -- check that RooMomentMorphFuncND::Grid::addPdf() was "
869 << "called for every corner of the parameter range." << std::endl;
870 throw string("RooMomentMorphFuncND::findShape() ERROR: incomplete reference grid");
871 }
872 }
873
874 // std::cout << std::endl;
875
876 // for (int isq = 0; isq < _squareVec.size(); isq++) {
877 // std::cout << _squareIdx[isq];
878 // std::cout << " (";
879 // for (int isqq = 0; isqq < _squareVec[isq].size(); isqq++) {
880 // std::cout << _squareVec[isq][isqq] << ((isqq<_squareVec[isq].size()-1)?",":"");
881 // }
882 // std::cout << ") ";
883 // }
884
885 // construct transformation matrix for linear extrapolation
886 TMatrixD M(depth, depth);
887
889 xtmp.reserve(nPar);
890 for (int ix = 0; ix < nPar; ix++) {
891 xtmp.push_back(ix);
892 }
893
894 for (int k = 0; k < depth; ++k) {
895 M(k, 0) = 1.0;
896
897 int nperm = 0;
899
900 for (int iperm = 1; iperm <= nPar; ++iperm) {
901 do {
902 double dtmp = _squareVec[k][xtmp[0]] - squareBase[xtmp[0]];
903 for (int itmp = 1; itmp < iperm; ++itmp) {
905 }
906 M(k, nperm + 1) = dtmp;
907 nperm++;
909 }
910 }
911
912 // M.Print();
913 (*_MSqr) = M.Invert();
914}
915
916//_____________________________________________________________________________
918{
919 if (allVars.size() == 1) {
920 RooAbsReal *temp = const_cast<RooMomentMorphFuncND *>(this);
921 temp->specialIntegratorConfig(true)->method1D().setLabel("RooBinIntegrator");
922 int nbins = (static_cast<RooRealVar *>(allVars.first()))->numBins();
923 temp->specialIntegratorConfig(true)->getConfigSection("RooBinIntegrator").setRealValue("numBins", nbins);
924 return true;
925 } else {
926 std::cout << "Currently BinIntegrator only knows how to deal with 1-d " << std::endl;
927 return false;
928 }
929 return false;
930}
#define b(i)
Definition RSha256.hxx:100
#define ccoutE(a)
#define coutW(a)
#define coutE(a)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t attr
char name[80]
Definition TGX11.cxx:148
#define hi
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2570
const_iterator begin() const
const_iterator end() const
Abstract base class for RooRealVar binning definitions.
Abstract container object that can hold multiple RooAbsArg objects.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
RooAbsArg * first() const
bool addTyped(const RooAbsCollection &list, bool silent=false)
Adds elements of a given RooAbsCollection to the container if they match the specified type.
const RooArgSet * nset() const
Definition RooAbsProxy.h:52
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:107
virtual double getValV(const RooArgSet *normalisationSet=nullptr) const
Return value of object.
RooNumIntConfig * specialIntegratorConfig() const
Returns the specialized integrator configuration for this RooAbsReal.
Calculates the sum of a set of RooAbsReal terms, or when constructed with two sets,...
Definition RooAddition.h:27
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooAbsArg * at(Int_t idx) const
Return object at given index, or nullptr if index is out of range.
Definition RooArgList.h:110
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
Implements a RooAbsBinning in terms of an array of boundary values, posing no constraints on the choi...
Definition RooBinning.h:27
Int_t setObj(const RooArgSet *nset, T *obj, const TNamed *isetRangeName=nullptr)
Setter function without integration set.
T * getObj(const RooArgSet *nset, Int_t *sterileIndex=nullptr, const TNamed *isetRangeName=nullptr)
Getter function without integration set.
bool setLabel(const char *label, bool printError=true) override
Set value by specifying the name of the desired state.
bool add(const RooAbsArg &var, bool valueServer, bool shapeServer, bool silent)
Overloaded RooCollection_t::add() method insert object into set and registers object as server to own...
Represents a constant real-valued object.
Definition RooConstVar.h:23
RooCustomizer is a factory class to produce clones of a prototype composite PDF object with the same ...
void markAsCompiled(RooAbsArg &arg) const
void compileServers(RooAbsArg &arg, RooArgSet const &normSet)
void markSubtreeAsCompiled(RooAbsArg &arg) const
Mark arg and every branch node reachable through its server tree as already compiled.
Helper compute-graph node that exposes one of the morph mixing fractions to the RooFit::Evaluator.
const RooMomentMorphFuncND * _parent
! morph that owns the cache (not owned)
double evaluate() const override
Evaluate this PDF / function / constant. Needs to be overridden by all derived classes.
A RooFormulaVar is a generic implementation of a real-valued object, which takes a RooArgList of serv...
RooLinearVar is the most general form of a derived real-valued object that can be used by RooRealInte...
void calculateFractions(const RooMomentMorphFuncND &self, bool verbose=true) const
std::unique_ptr< RooChangeTracker > _tracker
std::unique_ptr< RooAbsReal > _sum
RooArgList containedArgs(Action) override
CacheElem(std::unique_ptr< RooAbsReal > &&sumFunc, std::unique_ptr< RooChangeTracker > &&tracker, const RooArgList &flist)
void addBinning(const RooAbsBinning &binning)
std::vector< RooAbsBinning * > _grid
std::vector< std::vector< double > > _nref
void addPdf(const RooAbsReal &func, int bin_x)
RooObjCacheManager _cacheMgr
! Transient cache manager
std::unique_ptr< TMatrixD > _MSqr
void findShape(const std::vector< double > &x) const
double evaluate() const override
Evaluate this PDF / function / constant. Needs to be overridden by all derived classes.
RooAbsReal * sumFunc(const RooArgSet *nset)
CacheElem * getCache(const RooArgSet *nset) const
std::unique_ptr< TMatrixD > _M
RooArgSet * _curNormSet
! Transient cache manager
bool setBinIntegrator(RooArgSet &allVars)
double getValV(const RooArgSet *set=nullptr) const override
Return value of object.
std::vector< std::vector< double > > _squareVec
int sij(const int &i, const int &j) const
std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const override
std::vector< int > _squareIdx
const RooArgSet & getConfigSection(const char *name) const
Retrieve configuration information specific to integrator with given name.
RooCategory & method1D()
Variable that can be changed from the outside.
Definition RooRealVar.h:37
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
Double_t x[n]
Definition legend1.C:17
void cartesianProduct(std::vector< std::vector< T > > &out, std::vector< std::vector< T > > &in)
Definition Algorithms.h:22
bool nextCombination(const Iterator first, Iterator k, const Iterator last)
Definition Algorithms.h:64
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
Definition CodegenImpl.h:72
TMarker m
Definition textangle.C:8