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 <TMap.h>
35#include <TMath.h>
36#include <TVector.h>
37
38#include <map>
39
40using std::string, std::vector;
41
42
43//_____________________________________________________________________________
44RooMomentMorphFuncND::RooMomentMorphFuncND() : _cacheMgr(this, 10, true, true), _setting(RooMomentMorphFuncND::Linear), _useHorizMorph(true)
45{
46}
47
48//_____________________________________________________________________________
52 _cacheMgr(this, 10, true, true),
53 _parList("parList", "List of morph parameters", this),
54 _obsList("obsList", "List of observables", this),
55 _referenceGrid(referenceGrid),
56 _pdfList("pdfList", "List of pdfs", this),
57 _setting(setting),
58 _useHorizMorph(true)
59{
60 // morph parameters
62
63 // observables
65
67
68 // general initialization
69 initialize();
70
71}
72
73//_____________________________________________________________________________
75 const RooArgList &pdfList, const TVectorD &mrefpoints, Setting setting)
77 _cacheMgr(this, 10, true, true),
78 _parList("parList", "List of morph parameters", this),
79 _obsList("obsList", "List of observables", this),
80 _pdfList("pdfList", "List of pdfs", this),
81 _setting(setting),
82 _useHorizMorph(true)
83{
84 // make reference grid
85 RooBinning grid(mrefpoints.GetNrows() - 1, mrefpoints.GetMatrixArray());
87
88 for (int i = 0; i < mrefpoints.GetNrows(); ++i) {
89 for (int j = 0; j < grid.numBoundaries(); ++j) {
90 if (mrefpoints[i] == grid.array()[j]) {
91 _referenceGrid.addPdf(*static_cast<Base_t *>(pdfList.at(i)), j);
92 break;
93 }
94 }
95 }
96
98
99 // morph parameters
101 parList.add(_m);
103
104 // observables
106
107 // general initialization
108 initialize();
109
110}
111
112//_____________________________________________________________________________
114 const RooArgList &pdfList, const RooArgList &mrefList, Setting setting)
116 _cacheMgr(this, 10, true, true),
117 _parList("parList", "List of morph parameters", this),
118 _obsList("obsList", "List of observables", this),
119 _pdfList("pdfList", "List of pdfs", this),
120 _setting(setting),
121 _useHorizMorph(true)
122{
123 // make reference grid
125 Int_t i = 0;
126 for (auto *mref : mrefList) {
127 if (!dynamic_cast<RooAbsReal *>(mref)) {
128 coutE(InputArguments) << "RooMomentMorphFuncND::ctor(" << GetName() << ") ERROR: mref " << mref->GetName()
129 << " is not of type RooAbsReal" << std::endl;
130 throw string("RooMomentMorphFuncND::ctor() ERROR mref is not of type RooAbsReal");
131 }
132 if (!dynamic_cast<RooConstVar *>(mref)) {
133 coutW(InputArguments) << "RooMomentMorphFuncND::ctor(" << GetName() << ") WARNING mref point " << i
134 << " is not a constant, taking a snapshot of its value" << std::endl;
135 }
136 mrefpoints[i] = static_cast<RooAbsReal *>(mref)->getVal();
137 i++;
138 }
139
140 RooBinning grid(mrefpoints.GetNrows() - 1, mrefpoints.GetMatrixArray());
142 for (i = 0; i < mrefpoints.GetNrows(); ++i) {
143 for (int j = 0; j < grid.numBoundaries(); ++j) {
144 if (mrefpoints[i] == grid.array()[j]) {
145 _referenceGrid.addPdf(static_cast<Base_t &>(pdfList[i]), j);
146 break;
147 }
148 }
149 }
150
152
153 // morph parameters
155 parList.add(_m);
157
158 // observables
160
161 // general initialization
162 initialize();
163
164}
165
166//_____________________________________________________________________________
169 _cacheMgr(other._cacheMgr, this),
170 _parList("parList", this, other._parList),
171 _obsList("obsList", this, other._obsList),
172 _referenceGrid(other._referenceGrid),
173 _pdfList("pdfList", this, other._pdfList),
174 _setting(other._setting),
175 _useHorizMorph(other._useHorizMorph),
176 _isPdfMode{other._isPdfMode}
177{
178 // general initialization
179 initialize();
180
181}
182
183//_____________________________________________________________________________
187
188//_____________________________________________________________________________
190{
191 for (vector<RooAbsBinning *>::iterator itr = _referenceGrid._grid.begin(); itr != _referenceGrid._grid.end();
192 ++itr) {
193 _referenceGrid._nnuis.push_back((*itr)->numBins() + 1);
194 }
195
196 int nPar = _parList.size();
197 int nDim = _referenceGrid._grid.size();
199 int nRef = _referenceGrid._nref.size();
200 int depth = std::pow(2, nPar);
201
202 if (nPar != nDim) {
203 coutE(InputArguments) << "RooMomentMorphFuncND::initialize(" << GetName() << ") ERROR: nPar != nDim"
204 << ": " << nPar << " !=" << nDim << std::endl;
205 assert(0);
206 }
207
208 if (nPdf != nRef) {
209 coutE(InputArguments) << "RooMomentMorphFuncND::initialize(" << GetName() << ") ERROR: nPdf != nRef"
210 << ": " << nPdf << " !=" << nRef << std::endl;
211 assert(0);
212 }
213
214 // Transformation matrix for NonLinear settings
215 _M = std::make_unique<TMatrixD>(nPdf, nPdf);
216 _MSqr = std::make_unique<TMatrixD>(depth, depth);
218 TMatrixD M(nPdf, nPdf);
219
221 for (int k = 0; k < nPdf; ++k) {
223 for (int idim = 0; idim < nPar; idim++) {
224 double delta = _referenceGrid._nref[k][idim] - _referenceGrid._nref[0][idim];
225 dm2.push_back(delta);
226 }
227 dm[k] = dm2;
228 }
229
231 for (int idim = 0; idim < nPar; idim++) {
233 xtmp.reserve(_referenceGrid._nnuis[idim]);
234 for (int ix = 0; ix < _referenceGrid._nnuis[idim]; ix++) {
235 xtmp.push_back(ix);
236 }
237 powers.push_back(xtmp);
238 }
239
240 vector<vector<int>> output;
242 int nCombs = output.size();
243
244 for (int k = 0; k < nPdf; ++k) {
245 int nperm = 0;
246 for (int i = 0; i < nCombs; i++) {
247 double tmpDm = 1.0;
248 for (int ix = 0; ix < nPar; ix++) {
249 double delta = dm[k][ix];
250 tmpDm *= std::pow(delta, static_cast<double>(output[i][ix]));
251 }
252 M(k, nperm) = tmpDm;
253 nperm++;
254 }
255 }
256
257 // M.Print();
258 (*_M) = M.Invert();
259 }
260
261 // Resize transformation vectors
262 _squareVec.resize(std::pow(2, nPar));
263 _squareIdx.resize(std::pow(2, nPar));
264}
265
266//_____________________________________________________________________________
268 : _pdfList(other._pdfList), _pdfMap(other._pdfMap), _nref(other._nref)
269{
270 for (unsigned int i = 0; i < other._grid.size(); i++) {
271 _grid.push_back(other._grid[i]->clone());
272 }
273}
274
275//_____________________________________________________________________________
277{
278 for (RooAbsBinning *binning : _grid) {
279 delete binning;
280 }
281}
282
283//_____________________________________________________________________________
285{
288 thisBoundaries.push_back(bin_x);
289 thisBoundaryCoordinates.push_back(_grid[0]->array()[bin_x]);
290 _pdfList.add(pdf);
291 _pdfMap[thisBoundaries] = _pdfList.size() - 1;
292 _nref.push_back(thisBoundaryCoordinates);
293}
294
295//_____________________________________________________________________________
297{
300 thisBoundaries.push_back(bin_x);
301 thisBoundaryCoordinates.push_back(_grid[0]->array()[bin_x]);
302 thisBoundaries.push_back(bin_y);
303 thisBoundaryCoordinates.push_back(_grid[1]->array()[bin_y]);
304 _pdfList.add(pdf);
305 _pdfMap[thisBoundaries] = _pdfList.size() - 1;
306 _nref.push_back(thisBoundaryCoordinates);
307}
308
309//_____________________________________________________________________________
311{
314 thisBoundaries.push_back(bin_x);
315 thisBoundaryCoordinates.push_back(_grid[0]->array()[bin_x]);
316 thisBoundaries.push_back(bin_y);
317 thisBoundaryCoordinates.push_back(_grid[1]->array()[bin_y]);
318 thisBoundaries.push_back(bin_z);
319 thisBoundaryCoordinates.push_back(_grid[2]->array()[bin_z]);
320 _pdfList.add(pdf);
321 _pdfMap[thisBoundaries] = _pdfList.size() - 1;
322 _nref.push_back(thisBoundaryCoordinates);
323}
324
325//_____________________________________________________________________________
327{
329 int nBins = bins.size();
330 thisBoundaryCoordinates.reserve(nBins);
331 for (int i = 0; i < nBins; i++) {
332 thisBoundaryCoordinates.push_back(_grid[i]->array()[bins[i]]);
333 }
334 _pdfList.add(pdf);
335 _pdfMap[bins] = _pdfList.size() - 1;
336 _nref.push_back(thisBoundaryCoordinates);
337}
338
339//_____________________________________________________________________________
340std::unique_ptr<RooAbsArg>
342{
343 // Build (or fetch) the cache that holds the morph's internal compute graph:
344 // moment integrals, slope/offset formulas, RooLinearVar transforms, the per-pdf
345 // RooHistPdf clones, and the final RooAddPdf/RooRealSumFunc sum.
346 CacheElem *cache = getCache(&normSet);
347
348 // Make sure fractions hold sensible initial values (the replacement nodes
349 // below will keep them in sync going forward).
350 cache->calculateFractions(*this, false);
351
352 // The cache's subtree carries ORIGNAME: attributes left over from the
353 // RooCustomizer that built the per-pdf transformed RooHistPdf clones (it
354 // tagged each transVar with ORIGNAME:<obs>). RooCustomizer::build calls
355 // redirectServers with nameChange=true and will throw if it sees several
356 // candidates with the same ORIGNAME:* attribute, which is exactly what
357 // happens here once we ask it to clone the subtree. Strip those stale
358 // markers before cloning.
359 {
361 cache->_sum->branchNodeServerList(&branches);
362 for (auto *b : branches) {
363 std::vector<std::string> toRemove;
364 for (auto const &attr : b->attributes()) {
365 if (attr.rfind("ORIGNAME:", 0) == 0)
366 toRemove.push_back(attr);
367 }
368 for (auto const &attr : toRemove)
369 b->setAttribute(attr.c_str(), false);
370 }
371 }
372
373 // Replace each of the imperatively-updated fraction RooRealVars with a
374 // RooMomentMorphFraction node. This puts the fraction-recomputation inside
375 // the Evaluator's compute graph, so the moment integrals (which the
376 // fractions depend on transitively via the slope/offset formulas) become
377 // sibling nodes that the Evaluator caches once per minimization step.
379 const int nFrac = cache->_frac.size();
380 for (int i = 0; i < nFrac; ++i) {
381 auto frac = static_cast<RooRealVar *>(cache->_frac.at(i));
382 std::string newName = std::string{frac->GetName()} + "_compiled";
383 newFractions.addOwned(
384 std::make_unique<RooFit::Detail::RooMomentMorphFraction>(newName.c_str(), frac->GetTitle(), *this, i));
385 }
386
388 RooCustomizer cust(*cache->_sum, "compiled");
389 cust.setCloneBranchSet(clonedBranches);
390 for (int i = 0; i < nFrac; ++i) {
391 cust.replaceArg(*cache->_frac.at(i), newFractions[i]);
392 }
393
394 // RooCustomizer::build() already transfers ownership of the cloned branches
395 // (everything in `clonedBranches` except the returned top node) to the new
396 // top node's owned-components list, so we only have to attach the
397 // newly-created fraction nodes here.
398 std::unique_ptr<RooAbsReal> newSum{static_cast<RooAbsReal *>(cust.build())};
399 newSum->addOwnedComponents(std::move(newFractions));
400
401 if (_isPdfMode) {
402 // In pdf mode, _sum is a RooAddPdf whose value should be the normalized
403 // morph density. We must let the inner RooHistPdf clones go through
404 // their own compileForNormSet so they get wrapped in a RooNormalizedPdf.
406 newSum->branchNodeServerList(&branches);
407 for (auto *b : branches) {
408 if (dynamic_cast<RooFit::Detail::RooMomentMorphFraction *>(b))
409 ctx.markAsCompiled(*b);
410 }
411 ctx.compileServers(*newSum, normSet);
412 } else {
413 // Non-pdf mode: _sum is a RooRealSumFunc and the legacy path returns
414 // the raw weighted sum of the per-pdf bin values, with no per-component
415 // normalization. So cloned subtree is already in its final form.
416 ctx.markSubtreeAsCompiled(*newSum);
417 ctx.compileServers(*newSum, normSet);
418 }
419
420 return newSum;
421}
422
423namespace RooFit {
424namespace Detail {
425
426RooMomentMorphFraction::RooMomentMorphFraction(const char *name, const char *title, RooMomentMorphFuncND const &parent,
427 int index)
428 : RooAbsReal(name, title), _parList("parList", "parList", this), _parent(&parent), _index(index)
429{
430 _parList.add(parent._parList);
431}
432
434 : RooAbsReal(other, name), _parList("parList", this, other._parList), _parent(other._parent), _index(other._index)
435{
436}
437
439{
440 auto *cache = _parent->getCache(nullptr);
441 if (cache->_tracker->hasChanged(true)) {
442 cache->calculateFractions(*_parent, false);
443 }
444 return cache->frac(_index)->getVal();
445}
446
447} // namespace Detail
448} // namespace RooFit
449
450//_____________________________________________________________________________
452{
453 auto cache = static_cast<CacheElem *>(_cacheMgr.getObj(nullptr, static_cast<RooArgSet const*>(nullptr)));
454 if (cache) {
455 return cache;
456 }
457
458 int nObs = _obsList.size();
460
461 RooAbsReal *null = nullptr;
462 vector<RooAbsReal *> meanrv(nPdf * nObs, null);
463 vector<RooAbsReal *> sigmarv(nPdf * nObs, null);
464 vector<RooAbsReal *> myrms(nObs, null);
465 vector<RooAbsReal *> mypos(nObs, null);
466 vector<RooAbsReal *> slope(nPdf * nObs, null);
467 vector<RooAbsReal *> offsets(nPdf * nObs, null);
468 vector<RooAbsReal *> transVar(nPdf * nObs, null);
470
473
474 // fraction parameters
475 RooArgList coefList("coefList"); // fractions multiplied with input pdfs
476 RooArgList coefList2("coefList2"); // fractions multiplied with mean position of observable contribution
477 RooArgList coefList3("coefList3"); // fractions multiplied with rms position of observable contribution
478
479 for (int i = 0; i < 3 * nPdf; ++i) {
480 string fracName = Form("frac_%d", i);
481 double initval = _isPdfMode ? 1.0 : 0.0;
482 RooRealVar *frac = new RooRealVar(fracName.c_str(), fracName.c_str(), initval); // to be set later
483
484 fracl.add(*frac);
485 if (i < nPdf) {
486 coefList.add(*static_cast<RooRealVar *>(fracl.at(i)));
487 } else if (i < 2 * nPdf) {
488 coefList2.add(*static_cast<RooRealVar *>(fracl.at(i)));
489 } else {
490 coefList3.add(*static_cast<RooRealVar *>(fracl.at(i)));
491 }
492 ownedComps.add(*static_cast<RooRealVar *>(fracl.at(i)));
493 }
494
495 std::unique_ptr<RooAbsReal> theSum;
496 string sumName = Form("%s_sum", GetName());
497
499 if (_useHorizMorph) {
500 // mean and sigma
502 for (int i = 0; i < nPdf; ++i) {
503 for (int j = 0; j < nObs; ++j) {
504 RooAbsMoment *mom = nObs == 1 ? (static_cast<Base_t *>(_pdfList.at(i)))->sigma(static_cast<RooRealVar &>(*obsList.at(j)))
505 : (static_cast<Base_t *>(_pdfList.at(i)))->sigma(static_cast<RooRealVar &>(*obsList.at(j)), obsList);
506
507 mom->setLocalNoDirtyInhibit(true);
508 mom->mean()->setLocalNoDirtyInhibit(true);
509
510 sigmarv[sij(i, j)] = mom;
511 meanrv[sij(i, j)] = mom->mean();
512
513 ownedComps.add(*sigmarv[sij(i, j)]);
514 }
515 }
516
517 // slope and offset (to be set later, depend on nuisance parameters)
518 for (int j = 0; j < nObs; ++j) {
519 RooArgList meanList("meanList");
520 RooArgList rmsList("rmsList");
521 for (int i = 0; i < nPdf; ++i) {
522 meanList.add(*meanrv[sij(i, j)]);
523 rmsList.add(*sigmarv[sij(i, j)]);
524 }
525 string myrmsName = Form("%s_rms_%d", GetName(), j);
526 string myposName = Form("%s_pos_%d", GetName(), j);
527 mypos[j] = new RooAddition(myposName.c_str(), myposName.c_str(), meanList, coefList2);
528 myrms[j] = new RooAddition(myrmsName.c_str(), myrmsName.c_str(), rmsList, coefList3);
529 ownedComps.add(RooArgSet(*myrms[j], *mypos[j]));
530 }
531
532 // construction of unit pdfs
533
534 Int_t i = 0;
535 for (auto const *pdf : static_range_cast<Base_t *>(_pdfList)) {
536
537 string pdfName = Form("pdf_%d", i);
538 RooCustomizer cust(*pdf, pdfName.c_str());
539
540 Int_t j = 0;
541 for (auto *var : static_range_cast<RooRealVar *>(obsList)) {
542 // slope and offset formulas
543 string slopeName = Form("%s_slope_%d_%d", GetName(), i, j);
544 string offsetName = Form("%s_offset_%d_%d", GetName(), i, j);
545
546 slope[sij(i, j)] =
547 new RooFormulaVar(slopeName.c_str(), "@0/@1", RooArgList(*sigmarv[sij(i, j)], *myrms[j]));
548 offsets[sij(i, j)] = new RooFormulaVar(offsetName.c_str(), "@0-(@1*@2)",
549 RooArgList(*meanrv[sij(i, j)], *mypos[j], *slope[sij(i, j)]));
550 ownedComps.add(RooArgSet(*slope[sij(i, j)], *offsets[sij(i, j)]));
551
552 // linear transformations, so pdf can be renormalized easily
553 string transVarName = Form("%s_transVar_%d_%d", GetName(), i, j);
554 transVar[sij(i, j)] = new RooLinearVar(transVarName.c_str(), transVarName.c_str(), *var, *slope[sij(i, j)],
555 *offsets[sij(i, j)]);
556
557 // *** WVE this is important *** this declares that frac effectively depends on the morphing parameters
558 // This will prevent the likelihood optimizers from erroneously declaring terms constant
559 transVar[sij(i, j)]->addServerList((RooAbsCollection &)_parList);
560
561 ownedComps.add(*transVar[sij(i, j)]);
562 cust.replaceArg(*var, *transVar[sij(i, j)]);
563 ++j;
564 }
565 transPdf[i] = static_cast<Base_t *>(cust.build());
566 transPdfList.add(*transPdf[i]);
567 ownedComps.add(*transPdf[i]);
568 ++i;
569 }
570 }
571
572 // sum pdf
573 RooArgList const &pdfList = _useHorizMorph ? transPdfList : static_cast<RooArgList const &>(_pdfList);
574 if (_isPdfMode) {
575 theSum = std::make_unique<RooAddPdf>(sumName.c_str(), sumName.c_str(), pdfList, coefList);
576 } else {
577 theSum = std::make_unique<RooRealSumFunc>(sumName.c_str(), sumName.c_str(), pdfList, coefList);
578 }
579
580 // *** WVE this is important *** this declares that frac effectively depends on the morphing parameters
581 // This will prevent the likelihood optimizers from erroneously declaring terms constant
582 theSum->addServerList((RooAbsCollection &)_parList);
583 theSum->addOwnedComponents(ownedComps);
584
585 // change tracker for fraction parameters
586 std::string trackerName = std::string(GetName()) + "_frac_tracker";
587
588 // Store it in the cache
589 cache = new CacheElem(std::move(theSum),
590 std::make_unique<RooChangeTracker>(trackerName.c_str(), trackerName.c_str(), _parList, true),
591 fracl);
592 _cacheMgr.setObj(nullptr, nullptr, cache, nullptr);
593
594 return cache;
595}
596
597RooMomentMorphFuncND::CacheElem::CacheElem(std::unique_ptr<RooAbsReal> &&sumFunc,
598 std::unique_ptr<RooChangeTracker> &&tracker, const RooArgList &flist)
599 : _sum(std::move(sumFunc)), _tracker(std::move(tracker))
600{
601 _frac.add(flist);
602}
603
604//_____________________________________________________________________________
609
610//_____________________________________________________________________________
612
613//_____________________________________________________________________________
615{
616 // Special version of getValV() overrides Base_t::getValV() to save value of current normalization set
617 _curNormSet = set ? const_cast<RooArgSet *>(set) : const_cast<RooArgSet *>(static_cast<RooArgSet const*>(&_obsList));
618 return Base_t::getValV(set);
619}
620
621//_____________________________________________________________________________
623{
624 CacheElem *cache = getCache(nset ? nset : _curNormSet);
625
626 if (cache->_tracker->hasChanged(true)) {
627 cache->calculateFractions(*this, false); // verbose turned off
628 }
629 return cache->_sum.get();
630}
631
632//_____________________________________________________________________________
634{
636
637 if (cache->_tracker->hasChanged(true)) {
638 cache->calculateFractions(*this, false); // verbose turned off
639 }
640
641 double ret = cache->_sum->getVal(_obsList.nset());
642
643 return ret;
644}
645
646//_____________________________________________________________________________
648{
649 return static_cast<RooRealVar *>(_frac.at(i));
650}
651
652//_____________________________________________________________________________
654{
655 return static_cast<RooRealVar *>(_frac.at(i));
656}
657
658//_____________________________________________________________________________
660{
661 int nPdf = self._pdfList.size();
662 int nPar = self._parList.size();
663
664 double fracLinear(1.);
665 double fracNonLinear(1.);
666
667 if (self._setting == NonLinear || self._setting == NonLinearLinFractions || self._setting == NonLinearPosFractions) {
668 // Calculate the delta vector
670 for (int idim = 0; idim < nPar; idim++) {
671 double delta = (static_cast<RooRealVar *>(self._parList.at(idim)))->getVal() - self._referenceGrid._nref[0][idim];
672 dm2.push_back(delta);
673 }
674
676 for (int idim = 0; idim < nPar; idim++) {
678 xtmp.reserve(self._referenceGrid._nnuis[idim]);
679 for (int ix = 0; ix < self._referenceGrid._nnuis[idim]; ix++) {
680 xtmp.push_back(ix);
681 }
682 powers.push_back(xtmp);
683 }
684
685 vector<vector<int>> output;
687 int nCombs = output.size();
688
690
691 int nperm = 0;
692 for (int i = 0; i < nCombs; i++) {
693 double tmpDm = 1.0;
694 for (int ix = 0; ix < nPar; ix++) {
695 double delta = dm2[ix];
696 tmpDm *= std::pow(delta, static_cast<double>(output[i][ix]));
697 }
699 nperm++;
700 }
701
702 double sumposfrac = 0.0;
703 for (int i = 0; i < nPdf; ++i) {
704 double ffrac = 0.0;
705
706 for (int j = 0; j < nPdf; ++j) {
707 ffrac += (*self._M)(j, i) * deltavec[j] * fracNonLinear;
708 }
709
710 if (ffrac >= 0) {
711 sumposfrac += ffrac;
712 }
713
714 // fractions for pdf
715 if (self._setting != NonLinearLinFractions) {
716 const_cast<RooRealVar *>(frac(i))->setVal(ffrac);
717 }
718
719 // fractions for rms and mean
720 const_cast<RooRealVar *>(frac(nPdf + i))->setVal(ffrac); // need to add up
721 const_cast<RooRealVar *>(frac(2 * nPdf + i))->setVal(ffrac); // need to add up
722
723 if (verbose) {
724 std::cout << "NonLinear fraction " << ffrac << std::endl;
725 frac(i)->Print();
726 frac(nPdf + i)->Print();
727 frac(2 * nPdf + i)->Print();
728 }
729 }
730
731 if (self._setting == NonLinearPosFractions) {
732 for (int i = 0; i < nPdf; ++i) {
733 if (frac(i)->getVal() < 0)
734 const_cast<RooRealVar *>(frac(i))->setVal(0.);
735 const_cast<RooRealVar *>(frac(i))->setVal(frac(i)->getVal() / sumposfrac);
736 }
737 }
738 }
739
740 if (self._setting == Linear || self._setting == NonLinearLinFractions) {
741 // zero all fractions
742 // for (int i = 0; i < 3*nPdf; ++i) {
743 for (int i = 0; i < nPdf; ++i) {
744 double initval = 0;
745 const_cast<RooRealVar *>(frac(i))->setVal(initval);
746 const_cast<RooRealVar *>(frac(nPdf + i))->setVal(initval);
747 const_cast<RooRealVar *>(frac(2 * nPdf + i))->setVal(initval);
748 }
749
750 std::vector<double> mtmp;
751
752 // loop over parList
753 for (auto *m : static_range_cast<RooRealVar *>(self._parList)) {
754 mtmp.push_back(m->getVal());
755 }
756
757 self.findShape(mtmp); // this sets _squareVec and _squareIdx quantities
758
759 int depth = std::pow(2, nPar);
761
762 int nperm = 0;
763
765 xtmp.reserve(nPar);
766 for (int ix = 0; ix < nPar; ix++) {
767 xtmp.push_back(ix);
768 }
769
770 for (int iperm = 1; iperm <= nPar; ++iperm) {
771 do {
772 double dtmp = mtmp[xtmp[0]] - self._squareVec[0][xtmp[0]];
773 for (int itmp = 1; itmp < iperm; ++itmp) {
774 dtmp *= mtmp[xtmp[itmp]] - self._squareVec[0][xtmp[itmp]];
775 }
776 deltavec[nperm + 1] = dtmp;
777 nperm++;
779 }
780
781 double origFrac1(0.);
782 double origFrac2(0.);
783 for (int i = 0; i < depth; ++i) {
784 double ffrac = 0.;
785 for (int j = 0; j < depth; ++j) {
786 ffrac += (*self._MSqr)(j, i) * deltavec[j] * fracLinear;
787 }
788
789 // set fractions for pdf
790 origFrac1 = frac(self._squareIdx[i])->getVal(); // already set in case of smoothlinear
791 const_cast<RooRealVar *>(frac(self._squareIdx[i]))->setVal(origFrac1 + ffrac); // need to add up
792
793 // set fractions for rms and mean
794 if (self._setting != NonLinearLinFractions) {
795 origFrac2 =
796 frac(nPdf + self._squareIdx[i])->getVal(); // already set in case of smoothlinear
797 const_cast<RooRealVar *>(frac(nPdf + self._squareIdx[i]))->setVal(origFrac2 + ffrac); // need to add up
798 const_cast<RooRealVar *>(frac(2 * nPdf + self._squareIdx[i]))->setVal(origFrac2 + ffrac); // need to add up
799 }
800
801 if (verbose) {
802 std::cout << "Linear fraction " << ffrac << std::endl;
803 frac(self._squareIdx[i])->Print();
804 frac(nPdf + self._squareIdx[i])->Print();
805 frac(2 * nPdf + self._squareIdx[i])->Print();
806 }
807 }
808 }
809}
810
811//_____________________________________________________________________________
813{
814 int nPar = _parList.size();
815 int nRef = _referenceGrid._nref.size();
816
817 // Find hypercube enclosing the location to morph to
818 // bool isEnclosed = true;
819 // for (int i = 0; i < nPar; i++) {
820 // if (x[i] < _referenceGrid._grid[i]->lowBound())
821 // isEnclosed = false;
822 // if (x[i] > _referenceGrid._grid[i]->highBound())
823 // isEnclosed = false;
824 // }
825
826 // std::cout << "isEnclosed = " << isEnclosed << std::endl;
827
828 int depth = std::pow(2, nPar);
829
830 vector<vector<double>> boundaries(nPar);
831 for (int idim = 0; idim < nPar; idim++) {
832 int bin = _referenceGrid._grid[idim]->binNumber(x[idim]);
833 double lo = _referenceGrid._grid[idim]->binLow(bin);
834 double hi = _referenceGrid._grid[idim]->binHigh(bin);
835 boundaries[idim].push_back(lo);
836 boundaries[idim].push_back(hi);
837 }
838
839 vector<vector<double>> output;
840 RooFit::Detail::cartesianProduct(output, boundaries);
841 _squareVec = output;
842
843 for (int isq = 0; isq < depth; isq++) {
844 // Reset to a sentinel before searching: if no matching reference point is
845 // found below, we must not silently keep the value left over from a
846 // previous, unrelated call to findShape() (e.g. from a different
847 // hypercube visited earlier in the fit). Falling through to a stale
848 // index here would make the interpolation depend on evaluation history
849 // instead of only on the current parameter point.
850 _squareIdx[isq] = -1;
851 for (int iref = 0; iref < nRef; iref++) {
854 break;
855 }
856 }
857 if (_squareIdx[isq] < 0) {
858 coutE(InputArguments) << "RooMomentMorphFuncND::findShape(" << GetName()
859 << ") ERROR: no reference pdf found for grid corner (";
860 for (unsigned int ix = 0; ix < _squareVec[isq].size(); ++ix) {
861 ccoutE(InputArguments) << (ix ? ", " : "") << _squareVec[isq][ix];
862 }
863 ccoutE(InputArguments) << ") of the hypercube enclosing the current morphing "
864 << "parameter point. The reference grid is missing a pdf at this "
865 << "coordinate -- check that RooMomentMorphFuncND::Grid::addPdf() was "
866 << "called for every corner of the parameter range." << std::endl;
867 throw string("RooMomentMorphFuncND::findShape() ERROR: incomplete reference grid");
868 }
869 }
870
871 // std::cout << std::endl;
872
873 // for (int isq = 0; isq < _squareVec.size(); isq++) {
874 // std::cout << _squareIdx[isq];
875 // std::cout << " (";
876 // for (int isqq = 0; isqq < _squareVec[isq].size(); isqq++) {
877 // std::cout << _squareVec[isq][isqq] << ((isqq<_squareVec[isq].size()-1)?",":"");
878 // }
879 // std::cout << ") ";
880 // }
881
882 // construct transformation matrix for linear extrapolation
883 TMatrixD M(depth, depth);
884
886 xtmp.reserve(nPar);
887 for (int ix = 0; ix < nPar; ix++) {
888 xtmp.push_back(ix);
889 }
890
891 for (int k = 0; k < depth; ++k) {
892 M(k, 0) = 1.0;
893
894 int nperm = 0;
896
897 for (int iperm = 1; iperm <= nPar; ++iperm) {
898 do {
899 double dtmp = _squareVec[k][xtmp[0]] - squareBase[xtmp[0]];
900 for (int itmp = 1; itmp < iperm; ++itmp) {
902 }
903 M(k, nperm + 1) = dtmp;
904 nperm++;
906 }
907 }
908
909 // M.Print();
910 (*_MSqr) = M.Invert();
911}
912
913//_____________________________________________________________________________
915{
916 if (allVars.size() == 1) {
917 RooAbsReal *temp = const_cast<RooMomentMorphFuncND *>(this);
918 temp->specialIntegratorConfig(true)->method1D().setLabel("RooBinIntegrator");
919 int nbins = (static_cast<RooRealVar *>(allVars.first()))->numBins();
920 temp->specialIntegratorConfig(true)->getConfigSection("RooBinIntegrator").setRealValue("numBins", nbins);
921 return true;
922 } else {
923 std::cout << "Currently BinIntegrator only knows how to deal with 1-d " << std::endl;
924 return false;
925 }
926 return false;
927}
#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:142
#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 ...
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:73
TMarker m
Definition textangle.C:8