Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooSimultaneous.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 RooSimultaneous.cxx
19\class RooSimultaneous
20\ingroup Roofitcore
21
22Facilitates simultaneous fitting of multiple PDFs to subsets of a given dataset.
23The class takes an index category, which is used as a selector
24for PDFs, and a list of PDFs, each associated
25with a state of the index category. RooSimultaneous always returns
26the value of the PDF that is associated with the current value
27of the index category.
28
29Extended likelihood fitting is supported if all components support
30extended likelihood mode. The expected number of events by a RooSimultaneous
31is that of the component p.d.f. selected by the index category.
32
33The index category can be accessed using indexCategory().
34
35###Generating events
36When generating events from a RooSimultaneous, the index category has to be added to
37the dataset. Further, the PDF needs to know the relative probabilities of each category, i.e.,
38how many events are in which category. This can be achieved in two ways:
39- Generating with proto data that have category entries: An event from the same category as
40in the proto data is created for each event in the proto data.
41See RooAbsPdf::generate(const RooArgSet&,const RooDataSet&,Int_t,bool,bool,bool) const.
42- No proto data: A category is chosen randomly.
43\note This requires that the PDFs building the simultaneous are extended. In this way,
44the relative probability of each category can be calculated from the number of events
45in each category.
46**/
47
48#include "RooSimultaneous.h"
49
50#include "Roo1DTable.h"
52#include "RooAbsData.h"
53#include "RooAddPdf.h"
54#include "RooArgSet.h"
55#include "RooBinSamplingPdf.h"
56#include "RooCategory.h"
57#include "RooCmdConfig.h"
59#include "RooDataHist.h"
60#include "RooDataSet.h"
61#include "RooGlobalFunc.h"
62#include "RooMsgService.h"
63#include "RooNameReg.h"
64#include "RooPlot.h"
65#include "RooRandom.h"
66#include "RooRealVar.h"
67#include "RooSimGenContext.h"
69#include "RooSuperCategory.h"
70
71#include "RooFitImplHelpers.h"
72
73#include <ROOT/StringUtils.hxx>
74
75#include <iostream>
76
77namespace {
78
79std::map<std::string, RooAbsPdf *> createPdfMap(const RooArgList &inPdfList, RooAbsCategoryLValue &inIndexCat)
80{
81 std::map<std::string, RooAbsPdf *> pdfMap;
83 for (unsigned int i = 0; i < inPdfList.size(); ++i) {
84 auto pdf = static_cast<RooAbsPdf *>(&inPdfList[i]);
85 const auto &nameIdx = (*indexCatIt++);
86 pdfMap[nameIdx.first] = pdf;
87 }
88 return pdfMap;
89}
90
92{
93 TObject *old = lst.FindObject(obj.GetName());
94 if (old)
95 lst.Replace(old, &obj);
96 else
97 lst.Add(&obj);
98}
99
100} // namespace
101
103
105{
106 finalPdfs.push_back(&pdf);
107 finalCatLabels.emplace_back(catLabel);
108}
109
110using std::string;
111
112
113
114
115////////////////////////////////////////////////////////////////////////////////
116/// Constructor with index category. PDFs associated with indexCat
117/// states can be added after construction with the addPdf() function.
118///
119/// RooSimultaneous can function without having a PDF associated
120/// with every single state. The normalization in such cases is taken
121/// from the number of registered PDFs, but getVal() will assert if
122/// when called for an unregistered index state.
123
124RooSimultaneous::RooSimultaneous(const char *name, const char *title,
126 RooSimultaneous{name, title, std::map<std::string, RooAbsPdf*>{}, inIndexCat}
127{
128}
129
130
131////////////////////////////////////////////////////////////////////////////////
132/// Constructor from index category and full list of PDFs.
133/// In this constructor form, a PDF must be supplied for each indexCat state
134/// to avoid ambiguities. The PDFs are associated with the states of the
135/// index category as they appear when iterating through the category states
136/// with RooAbsCategory::begin() and RooAbsCategory::end(). This usually means
137/// they are associated by ascending index numbers.
138///
139/// PDFs may not overlap (i.e. share any variables) with the index category (function)
140
141RooSimultaneous::RooSimultaneous(const char *name, const char *title,
144{
145 if (inPdfList.size() != inIndexCat.size()) {
146 std::stringstream errMsg;
147 errMsg << "RooSimultaneous::ctor(" << GetName()
148 << " ERROR: Number PDF list entries must match number of index category states, no PDFs added";
149 coutE(InputArguments) << errMsg.str() << std::endl;
150 throw std::invalid_argument(errMsg.str());
151 }
152}
153
154
155////////////////////////////////////////////////////////////////////////////////
156
157RooSimultaneous::RooSimultaneous(const char *name, const char *title, std::map<string, RooAbsPdf *> pdfMap,
159 : RooSimultaneous(name, title, std::move(*initialize(name ? name : "", inIndexCat, pdfMap)))
160{
161}
162
163/// For internal use in RooFit.
164RooSimultaneous::RooSimultaneous(const char *name, const char *title,
167 : RooSimultaneous(name, title, RooFit::Detail::flatMapToStdMap(pdfMap), inIndexCat)
168{
169}
170
172 : RooAbsPdf(name, title),
173 _plotCoefNormSet("!plotCoefNormSet", "plotCoefNormSet", this, false, false),
174 _partIntMgr(this, 10),
175 _indexCat("indexCat", "Index category", this, *initInfo.indexCat)
176{
177 for (std::size_t i = 0; i < initInfo.finalPdfs.size(); ++i) {
178 addPdf(*initInfo.finalPdfs[i], initInfo.finalCatLabels[i].c_str());
179 }
180
181 // Take ownership of eventual super category
182 if (initInfo.superIndex) {
183 addOwnedComponents(std::move(initInfo.superIndex));
184 }
185}
186
187/// \cond ROOFIT_INTERNAL
188
189// This class cannot be locally defined in initialize as it cannot be
190// used as a template argument in that case
191namespace RooSimultaneousAux {
192 struct CompInfo {
193 RooAbsPdf* pdf ;
196 std::unique_ptr<RooArgSet> subIndexComps;
197 } ;
198}
199
200/// \endcond
201
202std::unique_ptr<RooSimultaneous::InitializationOutput>
204 std::map<std::string, RooAbsPdf *> const& pdfMap)
205
206{
207 auto out = std::make_unique<RooSimultaneous::InitializationOutput>();
208 out->indexCat = &inIndexCat;
209
210 // First see if there are any RooSimultaneous input components
211 bool simComps(false) ;
212 for (auto const& item : pdfMap) {
213 if (dynamic_cast<RooSimultaneous*>(item.second)) {
214 simComps = true ;
215 break ;
216 }
217 }
218
219 // If there are no simultaneous component p.d.f. do simple processing through addPdf()
220 if (!simComps) {
221 for (auto const& item : pdfMap) {
222 out->addPdf(*item.second,item.first);
223 }
224 return out;
225 }
226
227 std::string msgPrefix = "RooSimultaneous::initialize(" + name + ") ";
228
229 // Issue info message that we are about to do some rearranging
230 oocoutI(nullptr, InputArguments) << msgPrefix << "INFO: one or more input component of simultaneous p.d.f.s are"
231 << " simultaneous p.d.f.s themselves, rewriting composite expressions as one-level simultaneous p.d.f. in terms of"
232 << " final constituents and extended index category" << std::endl;
233
234
236 std::map<string,RooSimultaneousAux::CompInfo> compMap ;
237 for (auto const& item : pdfMap) {
238 RooSimultaneousAux::CompInfo ci ;
239 ci.pdf = item.second ;
240 RooSimultaneous* simComp = dynamic_cast<RooSimultaneous*>(item.second) ;
241 if (simComp) {
242 ci.simPdf = simComp ;
243 ci.subIndex = &simComp->indexCat() ;
244 ci.subIndexComps = simComp->indexCat().isFundamental()
245 ? std::make_unique<RooArgSet>(simComp->indexCat())
246 : std::unique_ptr<RooArgSet>(simComp->indexCat().getVariables());
247 allAuxCats.add(*ci.subIndexComps,true) ;
248 } else {
249 ci.simPdf = nullptr;
250 ci.subIndex = nullptr;
251 }
252 compMap[item.first] = std::move(ci);
253 }
254
255 // Construct the 'superIndex' from the nominal index category and all auxiliary components
256 RooArgSet allCats(inIndexCat) ;
257 allCats.add(allAuxCats) ;
258 std::string siname = name + "_index";
259 out->superIndex = std::make_unique<RooSuperCategory>(siname.c_str(),siname.c_str(),allCats) ;
260 auto *superIndex = out->superIndex.get();
261 out->indexCat = superIndex;
262
263 // Now process each of original pdf/state map entries
264 for (auto const& citem : compMap) {
265
267 if (citem.second.subIndexComps) {
268 repliCats.remove(*citem.second.subIndexComps) ;
269 }
270 inIndexCat.setLabel(citem.first.c_str()) ;
271
272 if (!citem.second.simPdf) {
273
274 // Entry is a plain p.d.f. assign it to every state permutation of the repliCats set
276
277 // Iterator over all states of repliSuperCat
278 for (const auto& nameIdx : repliSuperCat) {
279 // Set value
280 repliSuperCat.setLabel(nameIdx.first) ;
281 // Retrieve corresponding label of superIndex
282 string superLabel = superIndex->getCurrentLabel() ;
283 out->addPdf(*citem.second.pdf,superLabel);
284 oocxcoutD(static_cast<RooAbsArg*>(nullptr), InputArguments) << msgPrefix
285 << "assigning pdf " << citem.second.pdf->GetName() << " to super label " << superLabel << std::endl ;
286 }
287 } else {
288
289 // Entry is a simultaneous p.d.f
290
291 if (repliCats.empty()) {
292
293 // Case 1 -- No replication of components of RooSim component are required
294
295 for (const auto& type : *citem.second.subIndex) {
296 const_cast<RooAbsCategoryLValue*>(citem.second.subIndex)->setLabel(type.first.c_str());
297 string superLabel = superIndex->getCurrentLabel() ;
298 RooAbsPdf* compPdf = citem.second.simPdf->getPdf(type.first);
299 if (compPdf) {
300 out->addPdf(*compPdf,superLabel);
301 oocxcoutD(static_cast<RooAbsArg*>(nullptr), InputArguments) << msgPrefix
302 << "assigning pdf " << compPdf->GetName() << "(member of " << citem.second.pdf->GetName()
303 << ") to super label " << superLabel << std::endl ;
304 } else {
305 oocoutW(nullptr, InputArguments) << msgPrefix << "WARNING: No p.d.f. associated with label "
306 << type.second << " for component RooSimultaneous p.d.f " << citem.second.pdf->GetName()
307 << "which is associated with master index label " << citem.first << std::endl ;
308 }
309 }
310
311 } else {
312
313 // Case 2 -- Replication of components of RooSim component are required
314
315 // Make replication supercat
317
318 for (const auto& stype : *citem.second.subIndex) {
319 const_cast<RooAbsCategoryLValue*>(citem.second.subIndex)->setLabel(stype.first.c_str());
320
321 for (const auto& nameIdx : repliSuperCat) {
322 repliSuperCat.setLabel(nameIdx.first) ;
323 const string superLabel = superIndex->getCurrentLabel() ;
324 RooAbsPdf* compPdf = citem.second.simPdf->getPdf(stype.first);
325 if (compPdf) {
326 out->addPdf(*compPdf,superLabel);
327 oocxcoutD(static_cast<RooAbsArg*>(nullptr), InputArguments) << msgPrefix
328 << "assigning pdf " << compPdf->GetName() << "(member of " << citem.second.pdf->GetName()
329 << ") to super label " << superLabel << std::endl ;
330 } else {
331 oocoutW(nullptr, InputArguments) << msgPrefix << "WARNING: No p.d.f. associated with label "
332 << stype.second << " for component RooSimultaneous p.d.f " << citem.second.pdf->GetName()
333 << "which is associated with master index label " << citem.first << std::endl ;
334 }
335 }
336 }
337 }
338 }
339 }
340
341 return out;
342}
343
344
345////////////////////////////////////////////////////////////////////////////////
346/// Copy constructor
347
350 _plotCoefNormSet("!plotCoefNormSet",this,other._plotCoefNormSet),
351 _plotCoefNormRange(other._plotCoefNormRange),
352 _partIntMgr(other._partIntMgr,this),
353 _indexCat("indexCat",this,other._indexCat),
354 _numPdf(other._numPdf)
355{
356 // Copy proxy list
357 for(auto* proxy : static_range_cast<RooRealProxy*>(other._pdfProxyList)) {
358 _pdfProxyList.Add(new RooRealProxy(proxy->GetName(),this,*proxy)) ;
359 }
360}
361
362
363
364////////////////////////////////////////////////////////////////////////////////
365/// Destructor
366
371
372
373
374////////////////////////////////////////////////////////////////////////////////
375/// Return the p.d.f associated with the given index category name
376
378{
380 return proxy ? static_cast<RooAbsPdf*>(proxy->absArg()) : nullptr;
381}
382
383
384
385////////////////////////////////////////////////////////////////////////////////
386/// Associate given PDF with index category state label 'catLabel'.
387/// The name state must be already defined in the index category.
388///
389/// RooSimultaneous can function without having a PDF associated
390/// with every single state. The normalization in such cases is taken
391/// from the number of registered PDFs, but getVal() will fail if
392/// called for an unregistered index state.
393///
394/// PDFs may not overlap (i.e. share any variables) with the index category (function).
395/// \param[in] pdf PDF to be added.
396/// \param[in] catLabel Name of the category state to be associated to the PDF.
397/// \return `true` in case of failure.
398
399bool RooSimultaneous::addPdf(const RooAbsPdf& pdf, const char* catLabel)
400{
401 // PDFs cannot overlap with the index category
402 if (pdf.dependsOn(_indexCat.arg())) {
403 coutE(InputArguments) << "RooSimultaneous::addPdf(" << GetName() << "): PDF '" << pdf.GetName()
404 << "' overlaps with index category '" << _indexCat.arg().GetName() << "'."<< std::endl ;
405 return true ;
406 }
407
408 // Each index state can only have one PDF associated with it
410 coutE(InputArguments) << "RooSimultaneous::addPdf(" << GetName() << "): index state '"
411 << catLabel << "' has already an associated PDF." << std::endl ;
412 return true ;
413 }
414
415 const RooSimultaneous* simPdf = dynamic_cast<const RooSimultaneous*>(&pdf) ;
416 if (simPdf) {
417
418 coutE(InputArguments) << "RooSimultaneous::addPdf(" << GetName()
419 << ") ERROR: you cannot add a RooSimultaneous component to a RooSimultaneous using addPdf()."
420 << " Use the constructor with RooArgList if input p.d.f.s or the map<string,RooAbsPdf&> instead." << std::endl ;
421 return true ;
422
423 } else {
424
425 // Create a proxy named after the associated index state
426 TObject* proxy = new RooRealProxy(catLabel,catLabel,this,const_cast<RooAbsPdf&>(pdf));
428 _numPdf += 1 ;
429 }
430
431 return false ;
432}
433
434////////////////////////////////////////////////////////////////////////////////
435/// Examine the pdf components and check if one of them can be extended or must be extended.
436/// It is enough to have one component that can be extended or must be extended to return the flag in
437/// the total simultaneous pdf.
438
440{
441 bool anyCanExtend = false;
442
444 auto &pdf = static_cast<RooAbsPdf const&>(proxy->arg());
445 if (pdf.mustBeExtended())
446 return MustBeExtended;
447 anyCanExtend |= pdf.canBeExtended();
448 }
450}
451
452////////////////////////////////////////////////////////////////////////////////
453/// Return the current value:
454/// the value of the PDF associated with the current index category state
455
457{
458 // Retrieve the proxy by index name
460 if(!proxy) {
461 return 0;
462 }
463
464 double nEvtTot = 1.0;
465 double nEvtCat = 1.0;
466
467 // Calculate relative weighting factor for sim-pdfs of all extendable components
468 if (canBeExtended()) {
469
470 nEvtTot = 0;
471 nEvtCat = 0;
472
474 auto &pdf2 = static_cast<RooAbsPdf const &>(proxy2->arg());
475 if(!pdf2.canBeExtended()) {
476 // If one of the pdfs can't be expected, reset the normalization
477 // factor to one and break out of the loop.
478 nEvtTot = 1.0;
479 nEvtCat = 1.0;
480 break;
481 }
482 const double nEvt = pdf2.expectedEvents(_normSet);
483 nEvtTot += nEvt;
484 if (proxy == proxy2) {
485 // Matching by proxy by pointer rather than pdfs, because it's
486 // possible to have the same pdf used in different states.
487 nEvtCat += nEvt;
488 }
489 }
490 }
491 double catFrac = nEvtCat / nEvtTot;
492
493 // Return the selected PDF value, normalized by the relative number of
494 // expected events if applicable.
495 return *proxy * catFrac;
496}
497
498////////////////////////////////////////////////////////////////////////////////
499/// Return the number of expected events: If the index is in nset,
500/// then return the sum of the expected events of all components,
501/// otherwise return the number of expected events of the PDF
502/// associated with the current index category state
503
505{
506 if (nset->contains(_indexCat.arg())) {
507
508 double sum(0) ;
509
511 sum += (static_cast<RooAbsPdf*>(proxy->absArg()))->expectedEvents(nset) ;
512 }
513
514 return sum ;
515
516 } else {
517
518 // Retrieve the proxy by index name
520
521 //assert(proxy!=0) ;
522 if (proxy==nullptr) return 0 ;
523
524 // Return the selected PDF value, normalized by the number of index states
525 return (static_cast<RooAbsPdf*>(proxy->absArg()))->expectedEvents(nset);
526 }
527}
528
529
530
531////////////////////////////////////////////////////////////////////////////////
532/// Forward determination of analytical integration capabilities to component p.d.f.s
533/// A unique code is assigned to the combined integration capabilities of all associated
534/// p.d.f.s
535
537 const RooArgSet* normSet, const char* rangeName) const
538{
539 // Declare that we can analytically integrate all requested observables
540 analVars.add(allVars) ;
541
542 // Retrieve (or create) the required partial integral list
543 Int_t code ;
544
545 // Check if this configuration was created before
547 if (cache) {
548 code = _partIntMgr.lastIndex() ;
549 return code+1 ;
550 }
551 cache = new CacheElem ;
552
553 // Create the partial integral set for this request
555 cache->_partIntList.addOwned(std::unique_ptr<RooAbsReal>{proxy->arg().createIntegral(analVars,normSet,nullptr,rangeName)});
556 }
557
558 // Store the partial integral list and return the assigned code ;
560
561 return code+1 ;
562}
563
564
565
566////////////////////////////////////////////////////////////////////////////////
567/// Return analytical integration defined by given code
568
569double RooSimultaneous::analyticalIntegralWN(Int_t code, const RooArgSet* normSet, const char* /*rangeName*/) const
570{
571 // No integration scenario
572 if (code==0) {
573 return getVal(normSet) ;
574 }
575
576 // Partial integration scenarios, rangeName already encoded in 'code'
577 CacheElem* cache = static_cast<CacheElem*>(_partIntMgr.getObjByIndex(code-1)) ;
578
581 return (static_cast<RooAbsReal*>(cache->_partIntList.at(idx)))->getVal(normSet) ;
582}
583
584
585
586
587
588
589////////////////////////////////////////////////////////////////////////////////
590/// Back-end for plotOn() implementation on RooSimultaneous which
591/// needs special handling because a RooSimultaneous PDF cannot
592/// project out its index category via integration. plotOn() will
593/// abort if this is requested without providing a projection dataset.
594
596{
597 // Sanity checks
598 if (plotSanityChecks(frame)) return frame ;
599
600 // Special case: if an asymmetry is requested with respect to our index
601 // category, we cannot reroute the plotting to the component pdfs. The
602 // component pdfs don't depend on the index category, so the asymmetry engine
603 // in the base class would not be able to split them by index state. Instead,
604 // we delegate directly to the base class implementation, which constructs the
605 // asymmetry from the two index-state component pdfs (see the overridden
606 // createAsymmetryComponent() and GitHub issue #14255).
607 if (auto *asymCmd = static_cast<RooCmdArg *>(cmdList.FindObject("Asymmetry"))) {
608 auto *asymCat = dynamic_cast<RooAbsCategory const *>(asymCmd->getObject(0));
609 if (asymCat && asymCat == &_indexCat.arg()) {
610
612
613 // The base-class asymmetry-plotting engine averages the projection over
614 // the projection dataset. This is not supported for the composite data
615 // stores that back datasets with a category index, so we flatten such a
616 // projection dataset into a plain (vector-backed) copy first. Both the
617 // copy and the replacement command must outlive the plotOn() call below,
618 // because the command list only stores pointers to them.
619 std::unique_ptr<RooAbsData> flatProjData;
621 if (auto *projWData = static_cast<RooCmdArg *>(cmdList2.FindObject("ProjData"))) {
622 auto *projData = dynamic_cast<RooDataSet const *>(projWData->getObject(1));
623 if (projData && dynamic_cast<RooCompositeDataStore const *>(projData->store())) {
624 flatProjData = std::make_unique<RooDataSet>(projData->GetName(), projData->GetTitle(), *projData->get(),
625 RooFit::Import(*const_cast<RooDataSet *>(projData)));
626 const RooArgSet *projDataSet = projWData->getSet(0);
627 newProjWData = projDataSet ? RooFit::ProjWData(*projDataSet, *flatProjData)
630 }
631 }
632
633 return RooAbsReal::plotOn(frame, cmdList2);
634 }
635 }
636
637 // Extract projection configuration from command list
638 RooCmdConfig pc("RooSimultaneous::plotOn(" + std::string(GetName()) + ")");
639 pc.defineString("sliceCatState","SliceCat",0,"",true) ;
640 pc.defineDouble("scaleFactor","Normalization",0,1.0) ;
641 pc.defineInt("scaleType","Normalization",0,RooAbsPdf::Relative) ;
642 pc.defineObject("sliceCatList","SliceCat",0,nullptr,true) ;
643 // This dummy is needed for plotOn to recognize the "SliceCatMany" command.
644 // It is not used directly, but the "SliceCat" commands are nested in it.
645 // Removing this dummy definition results in "ERROR: unrecognized command: SliceCatMany".
646 pc.defineObject("dummy1","SliceCatMany",0) ;
647 pc.defineSet("projSet","Project",0) ;
648 pc.defineSet("sliceSet","SliceVars",0) ;
649 pc.defineSet("projDataSet","ProjData",0) ;
650 pc.defineObject("projData","ProjData",1) ;
651 pc.defineMutex("Project","SliceVars") ;
652 pc.allowUndefined() ; // there may be commands we don't handle here
653
654 // Process and check varargs
655 pc.process(cmdList) ;
656 if (!pc.ok(true)) {
657 return frame ;
658 }
659
660 RooAbsData* projData = static_cast<RooAbsData*>(pc.getObject("projData")) ;
661 const RooArgSet* projDataSet = pc.getSet("projDataSet");
662 const RooArgSet* sliceSetTmp = pc.getSet("sliceSet") ;
663 std::unique_ptr<RooArgSet> sliceSet( sliceSetTmp ? (static_cast<RooArgSet*>(sliceSetTmp->Clone())) : nullptr );
664 const RooArgSet* projSet = pc.getSet("projSet") ;
665 double scaleFactor = pc.getDouble("scaleFactor") ;
666 ScaleType stype = (ScaleType) pc.getInt("scaleType") ;
667
668
669 // Look for category slice arguments and add them to the master slice list if found
670 const char* sliceCatState = pc.getString("sliceCatState",nullptr,true) ;
671 const RooLinkedList& sliceCatList = pc.getObjectList("sliceCatList") ;
672 if (sliceCatState) {
673
674 // Make the master slice set if it doesnt exist
675 if (!sliceSet) {
676 sliceSet = std::make_unique<RooArgSet>();
677 }
678
679 // Prepare comma separated label list for parsing
681
682 // Loop over all categories provided by (multiple) Slice() arguments
683 unsigned int tokenIndex = 0;
685 const char* slabel = tokenIndex >= catTokens.size() ? nullptr : catTokens[tokenIndex++].c_str();
686
687 if (slabel) {
688 // Set the slice position to the value indicated by slabel
689 scat->setLabel(slabel) ;
690 // Add the slice category to the master slice set
691 sliceSet->add(*scat,false) ;
692 }
693 }
694 }
695
696 // Check if we have a projection dataset
697 if (!projData) {
698 coutE(InputArguments) << "RooSimultaneous::plotOn(" << GetName() << ") ERROR: must have a projection dataset for index category" << std::endl ;
699 return frame ;
700 }
701
702 // Make list of variables to be projected
704 if (sliceSet) {
705 makeProjectionSet(frame->getPlotVar(),frame->getNormVars(),projectedVars,true) ;
706
707 // Take out the sliced variables
708 for (const auto sliceArg : *sliceSet) {
709 RooAbsArg* arg = projectedVars.find(sliceArg->GetName()) ;
710 if (arg) {
711 projectedVars.remove(*arg) ;
712 } else {
713 coutI(Plotting) << "RooAbsReal::plotOn(" << GetName() << ") slice variable "
714 << sliceArg->GetName() << " was not projected anyway" << std::endl ;
715 }
716 }
717 } else if (projSet) {
718 makeProjectionSet(frame->getPlotVar(),projSet,projectedVars,false) ;
719 } else {
720 makeProjectionSet(frame->getPlotVar(),frame->getNormVars(),projectedVars,true) ;
721 }
722
723 bool projIndex(false) ;
724
725 if (!_indexCat.arg().isDerived()) {
726 // *** Error checking for a fundamental index category ***
727 //cout << "RooSim::plotOn: index is fundamental" << std::endl ;
728
729 // Check that the provided projection dataset contains our index variable
730 if (!projData->get()->find(_indexCat.arg().GetName())) {
731 coutE(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") ERROR: Projection over index category "
732 << "requested, but projection data set doesn't contain index category" << std::endl ;
733 return frame ;
734 }
735
736 if (projectedVars.find(_indexCat.arg().GetName())) {
738 }
739
740 } else {
741 // *** Error checking for a composite index category ***
742
743 // Determine if any servers of the index category are in the projectedVars
745 bool anyServers(false) ;
746 for (const auto server : flattenedCatList()) {
747 if (projectedVars.find(server->GetName())) {
749 projIdxServers.add(*server) ;
750 }
751 }
752
753 // Check that the projection dataset contains all the
754 // index category components we're projecting over
755
756 // Determine if all projected servers of the index category are in the projection dataset
757 bool allServers(true) ;
758 std::string missing;
759 for (const auto server : projIdxServers) {
760 if (!projData->get()->find(server->GetName())) {
762 missing = server->GetName();
763 }
764 }
765
766 if (!allServers) {
767 coutE(Plotting) << "RooSimultaneous::plotOn(" << GetName()
768 << ") ERROR: Projection dataset doesn't contain complete set of index categories to do projection."
769 << "\n\tcategory " << missing << " is missing." << std::endl ;
770 return frame ;
771 }
772
773 if (anyServers) {
774 projIndex = true ;
775 }
776 }
777
778 // Calculate relative weight fractions of components
779 std::unique_ptr<Roo1DTable> wTable( projData->table(_indexCat.arg()) );
780
781 // Clone the index category to be able to cycle through the category states for plotting without
782 // affecting the category state of our instance
784 RooArgSet(*_indexCat).snapshot(idxCloneSet, true);
785 auto idxCatClone = static_cast<RooAbsCategoryLValue*>(idxCloneSet.find(_indexCat->GetName()) );
787
788 // Make list of category columns to exclude from projection data
789 std::unique_ptr<RooArgSet> idxCompSliceSet( idxCatClone->getObservables(frame->getNormVars()) );
790
791 // If we don't project over the index, just do the regular plotOn
792 if (!projIndex) {
793
794 coutI(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") plot on " << frame->getPlotVar()->GetName()
795 << " represents a slice in the index category (" << _indexCat.arg().GetName() << ")" << std::endl ;
796
797 // Reduce projData: take out fitCat (component) columns and entries that don't match selected slice
798 // Construct cut string to only select projection data event that match the current slice
799
800 // Make cut string to exclude rows from projection data
801 if (sliceSet) {
803 if (auto* slicedComponent = static_cast<const RooAbsCategory*>(sliceSet->find(*idxComp))) {
804 idxComp->setIndex(slicedComponent->getCurrentIndex(), false);
805 }
806 }
807 }
809
810 // Make temporary projData without RooSim index category components
811 RooArgSet projDataVars(*projData->get()) ;
812 projDataVars.remove(*idxCompSliceSet,true,true) ;
813
814 std::unique_ptr<RooAbsData>
816
817 // Override normalization and projection dataset
819 RooFit::Normalization(scaleFactor * wTable->get(idxCatClone->getCurrentLabel()), RooAbsReal::NumEvent);
821
822 // WVE -- do not adjust normalization for asymmetry plots
824 if (!cmdList.find("Asymmetry")) {
826 }
828
829 // Plot single component
830 RooPlot* retFrame = getPdf(idxCatClone->getCurrentLabel())->plotOn(frame,cmdList2);
831 return retFrame ;
832 }
833
834 // If we project over the index, plot using a temporary RooAddPdf
835 // using the weights from the data as coefficients
836
837 // Build the list of indexCat components that are sliced
838 idxCompSliceSet->remove(projectedVars,true,true) ;
839
840 // Make a new expression that is the weighted sum of requested components
843//RooAbsPdf* pdf ;
844 double sumWeight(0) ;
846
847 idxCatClone->setLabel(proxy->name()) ;
848
849 // Determine if this component is the current slice (if we slice)
850 bool skip(false) ;
851 for (const auto idxSliceCompArg : *idxCompSliceSet) {
852 const auto idxSliceComp = static_cast<RooAbsCategory*>(idxSliceCompArg);
853 RooAbsCategory* idxComp = static_cast<RooAbsCategory*>(idxCloneSet.find(idxSliceComp->GetName())) ;
854 if (idxComp->getCurrentIndex()!=idxSliceComp->getCurrentIndex()) {
855 skip=true ;
856 break ;
857 }
858 }
859 if (skip) continue ;
860
861 // Instantiate a RRV holding this pdfs weight
862 wgtCompList.addOwned(std::make_unique<RooRealVar>(proxy->name(),"coef",wTable->get(proxy->name())));
863 sumWeight += wTable->getFrac(proxy->name()) ;
864
865 // Add the PDF to list list
866 pdfCompList.add(proxy->arg()) ;
867 }
868
870 RooAddPdf plotVar{plotVarName,"weighted sum of RS components",pdfCompList,wgtCompList};
871
872 // Fix appropriate coefficient normalization in plot function
873 if (!_plotCoefNormSet.empty()) {
874 plotVar.fixAddCoefNormalization(_plotCoefNormSet) ;
875 }
876
877 std::unique_ptr<RooAbsData> projDataTmp;
879 if (projData) {
880
881 // Construct cut string to only select projection data event that match the current slice
883
884 // Make temporary projData without RooSim index category components
885 RooArgSet projDataVars(*projData->get()) ;
887 _indexCat.arg().getObservables(frame->getNormVars(), idxCatServers) ;
888
889 projDataVars.remove(idxCatServers,true,true) ;
890
891 projDataTmp = std::unique_ptr<RooAbsData>{projData->reduce(RooFit::SelectVars(projDataVars), RooFit::Cut(cutString.c_str()))};
892
893
894
895 if (projSet) {
896 projSetTmp.add(*projSet) ;
897 projSetTmp.remove(idxCatServers,true,true);
898 }
899 }
900
901
902 if (_indexCat.arg().isDerived() && !idxCompSliceSet->empty()) {
903 coutI(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") plot on " << frame->getPlotVar()->GetName()
904 << " represents a slice in index category components " << *idxCompSliceSet << std::endl ;
905
907 _indexCat.arg().getObservables(frame->getNormVars(), idxCompProjSet) ;
908 idxCompProjSet.remove(*idxCompSliceSet,true,true) ;
909 if (!idxCompProjSet.empty()) {
910 coutI(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") plot on " << frame->getPlotVar()->GetName()
911 << " averages with data index category components " << idxCompProjSet << std::endl ;
912 }
913 } else {
914 coutI(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") plot on " << frame->getPlotVar()->GetName()
915 << " averages with data index category (" << _indexCat.arg().GetName() << ")" << std::endl ;
916 }
917
918
919 // Override normalization and projection dataset
921
922 RooCmdArg tmp1 = RooFit::Normalization(scaleFactor*sumWeight,stype) ;
924 // WVE -- do not adjust normalization for asymmetry plots
925 if (!cmdList.find("Asymmetry")) {
927 }
929
930 RooPlot* frame2 ;
931 if (!projSetTmp.empty()) {
932 // Plot temporary function
935 frame2 = plotVar.plotOn(frame,cmdList2) ;
936 } else {
937 // Plot temporary function
938 frame2 = plotVar.plotOn(frame,cmdList2) ;
939 }
940
941 return frame2 ;
942}
943
944
945////////////////////////////////////////////////////////////////////////////////
946/// Build the component function of an asymmetry plot (see
947/// RooAbsReal::plotAsymOn()) for a fixed state of the asymmetry category.
948///
949/// When the asymmetry is requested in our own index category, the component for
950/// a given index state is simply the corresponding pdf. We return a clone of
951/// that pdf directly instead of a RooSimultaneous with a pinned index, because
952/// a RooSimultaneous compiles its per-category observables with a category
953/// prefix. That prefix makes it incompatible with the vectorized evaluation
954/// backend that averages the asymmetry over the projection data, and would
955/// otherwise silently yield a flat (zero) asymmetry (see issue #14255). For any
956/// other asymmetry category we fall back to the generic implementation.
957
958std::unique_ptr<RooAbsReal>
960{
961 if (&asymCat == &_indexCat.arg()) {
962 const std::string &label = _indexCat.arg().lookupName(asymCatState.getCurrentIndex());
963 if (RooAbsPdf *pdf = getPdf(label)) {
964 return RooHelpers::cloneTreeWithSameParameters(static_cast<RooAbsReal const &>(*pdf));
965 }
966 }
968}
969
970
971////////////////////////////////////////////////////////////////////////////////
972/// Interface function used by test statistics to freeze choice of observables
973/// for interpretation of fraction coefficients. Needed here because a RooSimultaneous
974/// works like a RooAddPdf when plotted
975
977{
979 if (normSet) {
980 // The index category must not be stored in the set: it is meaningless for
981 // the coefficient normalization, since it is never an observable of the
982 // component pdfs (RooAddPdf::selectNormalization() would filter it out
983 // again anyway). Worse, it is already registered as a value server via
984 // the index category proxy, and registering the same server a second
985 // time through this non-propagating set proxy corrupts the reference
986 // counts of the server's client lists when the set is cleared again.
988 filteredNormSet.remove(_indexCat.arg(), true, true);
990 }
991}
992
993
994////////////////////////////////////////////////////////////////////////////////
995/// Interface function used by test statistics to freeze choice of range
996/// for interpretation of fraction coefficients. Needed here because a RooSimultaneous
997/// works like a RooAddPdf when plotted
998
1003
1004
1005
1006
1007////////////////////////////////////////////////////////////////////////////////
1008
1010 const RooArgSet* auxProto, bool verbose, bool autoBinned, const char* binnedTag) const
1011{
1012 const char* idxCatName = _indexCat.arg().GetName() ;
1013
1014 if (vars.find(idxCatName) && prototype==nullptr
1015 && (auxProto==nullptr || auxProto->empty())
1016 && (autoBinned || (binnedTag && strlen(binnedTag)))) {
1017
1018 // Return special generator config that can also do binned generation for selected states
1019 return new RooSimSplitGenContext(*this,vars,verbose,autoBinned,binnedTag) ;
1020
1021 } else {
1022
1023 // Return regular generator config ;
1024 return genContext(vars,prototype,auxProto,verbose) ;
1025 }
1026}
1027
1028
1029
1030////////////////////////////////////////////////////////////////////////////////
1031/// Return specialized generator context for simultaneous p.d.f.s
1032
1034 const RooArgSet* auxProto, bool verbose) const
1035{
1036 RooArgSet allVars{vars};
1037 if(prototype) allVars.add(*prototype->get());
1038
1041
1042 // Not generating index cat: we better error out because it's not clear what
1043 // the user expects here. Does the user want to generate according to the
1044 // currently-selected pdf? Or does the user want to generate global
1045 // observable values according to the union of all category pdfs?
1046 // Print an error and tell the user what to do to explicitly.
1047 if(catsAmongAllVars.empty()) {
1048 coutE(InputArguments) << "RooSimultaneous::generateSimGlobal(" << GetName()
1049 << ") asking to generate without the index category!\n"
1050 << "It's not clear what to do. you probably want to either:\n"
1051 << "\n"
1052 << " 1. Generate according to the currently-selected pdf.\n"
1053 << " Please do this explicitly with:\n"
1054 << " simpdf->getPdf(simpdf->indexCat().getCurrentLabel())->generate(vars, ...)\n"
1055 << "\n"
1056 << " 1. Generate global observable values according to the union of all component pdfs.\n"
1057 << " For this, please use simpdf->generateSimGlobal(vars, ...)\n"
1058 << std::endl;
1059 return nullptr;
1060 }
1061
1063 if(prototype) {
1064 prototype->get()->selectCommon(flattenedCatList(), catsAmongProtoVars);
1065
1066 if(!catsAmongProtoVars.empty() && catsAmongProtoVars.size() != flattenedCatList().size()) {
1067 // Abort if we have only part of the servers
1068 coutE(Plotting) << "RooSimultaneous::genContext: ERROR: prototype must include either all "
1069 << " components of the RooSimultaneous index category or none " << std::endl;
1070 return nullptr;
1071 }
1072 }
1073
1074 return new RooSimGenContext(*this,vars,prototype,auxProto,verbose) ;
1075}
1076
1077
1078
1079
1080////////////////////////////////////////////////////////////////////////////////
1081
1083 const RooArgSet* nset,
1084 double scaleFactor,
1086 bool showProgress) const
1087{
1088 if (RooAbsReal::fillDataHist (hist, nset, scaleFactor,
1089 correctForBinVolume, showProgress) == nullptr)
1090 return nullptr;
1091
1092 const double sum = hist->sumEntries();
1093 if (sum != 0) {
1094 for (int i=0 ; i<hist->numEntries() ; i++) {
1095 hist->set(i, hist->weight(i) / sum, 0.);
1096 }
1097 }
1098
1099 return hist;
1100}
1101
1102
1103
1104
1105////////////////////////////////////////////////////////////////////////////////
1106/// Special generator interface for generation of 'global observables' -- for RooStats tools.
1107///
1108/// \note Why one can't just use RooAbsPdf::generate()? That's because when
1109/// using the regular generate() method, a specific component pdf is selected
1110/// for each generated entry according to the index category value. However,
1111/// global observable values are independent of the current index category,
1112/// which can best be illustrated with the case where a global observable
1113/// corresponds to a nuisance parameter that is relevant for multiple channels.
1114/// So the interpretation of what is an entry in the generated dataset is very
1115/// different, hence the separate function.
1116
1118{
1119 // Generating the index category together with the global observables doesn't make any sense.
1122 if(!catsAmongAllVars.empty()) {
1123 coutE(InputArguments) << "RooSimultaneous::generateSimGlobal(" << GetName()
1124 << ") asking to generate global obserables at the same time as the index category!\n"
1125 << "This doesn't make any sense: global observables are generally not related to a specific channel.\n"
1126 << std::endl;
1127 return nullptr;
1128 }
1129
1130 // Make set with clone of variables (placeholder for output)
1132 whatVars.snapshot(globClone);
1133
1134 auto data = std::make_unique<RooDataSet>("gensimglobal","gensimglobal",whatVars);
1135
1136 for (Int_t i=0 ; i<nEvents ; i++) {
1137 for (const auto& nameIdx : indexCat()) {
1138
1139 // Get pdf associated with state from simpdf
1140 RooAbsPdf* pdftmp = getPdf(nameIdx.first);
1141
1143 pdftmp->getObservables(&whatVars, globtmp) ;
1144
1145 // If there are any, generate only global variables defined by the pdf
1146 // associated with this state and transfer values to output placeholder.
1147 if (!globtmp.empty()) {
1148 globClone.assign(*std::unique_ptr<RooDataSet>{pdftmp->generate(globtmp,1)}->get(0)) ;
1149 }
1150 }
1151 data->add(globClone) ;
1152 }
1153
1154 return RooFit::makeOwningPtr(std::move(data));
1155}
1156
1157
1158/// Wraps the components of this RooSimultaneous in RooBinSamplingPdfs.
1159/// \param[in] data The dataset to be used in the eventual fit, used to figure
1160/// out the observables and whether the dataset is binned.
1161/// \param[in] precision Precision argument for all created RooBinSamplingPdfs.
1163
1164 if (precision < 0.) return;
1165
1167
1168 for (auto const &item : this->indexCat()) {
1169
1170 auto const &catName = item.first;
1171 auto &pdf = *this->getPdf(catName);
1172
1173 if (auto newSamplingPdf = RooBinSamplingPdf::create(pdf, data, precision)) {
1174 // Set the "ORIGNAME" attribute the indicate to
1175 // RooAbsArg::redirectServers() which pdf should be replaced by this
1176 // RooBinSamplingPdf in the RooSimultaneous.
1177 newSamplingPdf->setAttribute(
1178 (std::string("ORIGNAME:") + pdf.GetName()).c_str());
1179 newSamplingPdfs.addOwned(std::move(newSamplingPdf));
1180 }
1181 }
1182
1183 this->redirectServers(newSamplingPdfs, false, true);
1184 this->addOwnedComponents(std::move(newSamplingPdfs));
1185}
1186
1187
1188/// Wraps the components of this RooSimultaneous in RooBinSamplingPdfs, with a
1189/// different precision parameter for each component.
1190/// \param[in] data The dataset to be used in the eventual fit, used to figure
1191/// out the observables and whether the dataset is binned.
1192/// \param[in] precisions The map that gives the precision argument for each
1193/// component in the RooSimultaneous. The keys are the pdf names. If
1194/// there is no value for a given component, it will not use the bin
1195/// integration. Otherwise, the value has the same meaning than in
1196/// the IntegrateBins() command argument for RooAbsPdf::fitTo().
1197/// \param[in] useCategoryNames If this flag is set, the category names will be
1198/// used to look up the precision in the precisions map instead of
1199/// the pdf names.
1201 std::map<std::string, double> const& precisions,
1202 bool useCategoryNames /*=false*/) {
1203
1204 constexpr double defaultPrecision = -1.;
1205
1207
1208 for (auto const &item : this->indexCat()) {
1209
1210 auto const &catName = item.first;
1211 auto &pdf = *this->getPdf(catName);
1212 std::string pdfName = pdf.GetName();
1213
1214 auto found = precisions.find(useCategoryNames ? catName : pdfName);
1215 const double precision =
1216 found != precisions.end() ? found->second : defaultPrecision;
1217 if (precision < 0.)
1218 continue;
1219
1220 if (auto newSamplingPdf = RooBinSamplingPdf::create(pdf, data, precision)) {
1221 // Set the "ORIGNAME" attribute the indicate to
1222 // RooAbsArg::redirectServers() which pdf should be replaced by this
1223 // RooBinSamplingPdf in the RooSimultaneous.
1224 newSamplingPdf->setAttribute(
1225 (std::string("ORIGNAME:") + pdf.GetName()).c_str());
1226 newSamplingPdfs.addOwned(std::move(newSamplingPdf));
1227 }
1228 }
1229
1230 this->redirectServers(newSamplingPdfs, false, true);
1231 this->addOwnedComponents(std::move(newSamplingPdfs));
1232}
1233
1234/// Internal utility function to get a list of all category components for this
1235/// RooSimultaneous. The output contains only the index category if it is a
1236/// RooCategory, or the list of all category components if it is a
1237/// RooSuperCategory.
1239{
1240 // Note that the index category of a RooSimultaneous can only be of type
1241 // RooCategory or RooSuperCategory, because these are the only classes that
1242 // inherit from RooAbsCategoryLValue.
1243 if (auto superCat = dynamic_cast<RooSuperCategory const*>(&_indexCat.arg())) {
1244 return superCat->inputCatList();
1245 }
1246
1247 if(!_indexCatSet) {
1248 _indexCatSet = std::make_unique<RooArgSet>(_indexCat.arg());
1249 }
1250 return *_indexCatSet;
1251}
1252
1253namespace {
1254
1255void markObs(RooAbsArg *arg, std::string const &prefix, RooArgSet const &normSet)
1256{
1257 for (RooAbsArg *server : arg->servers()) {
1258 if (server->isFundamental() && normSet.find(*server)) {
1259 markObs(server, prefix, normSet);
1260 server->setAttribute("__obs__");
1261 } else if (!server->isFundamental()) {
1262 markObs(server, prefix, normSet);
1263 }
1264 }
1265}
1266
1267void prefixArgs(RooAbsArg *arg, std::string const &prefix, RooArgSet const &normSet)
1268{
1269 if (!arg->getStringAttribute("__prefix__")) {
1270 arg->SetName((prefix + arg->GetName()).c_str());
1271 arg->setStringAttribute("__prefix__", prefix.c_str());
1272 }
1273 for (RooAbsArg *server : arg->servers()) {
1274 if (server->isFundamental() && normSet.find(*server)) {
1275 prefixArgs(server, prefix, normSet);
1276 } else if (!server->isFundamental()) {
1277 prefixArgs(server, prefix, normSet);
1278 }
1279 }
1280}
1281
1282} // namespace
1283
1284std::unique_ptr<RooAbsArg>
1286{
1287 std::unique_ptr<RooSimultaneous> newSimPdf{static_cast<RooSimultaneous *>(this->Clone())};
1288
1289 const char *rangeName = this->getStringAttribute("RangeName");
1290 bool splitRange = this->getAttribute("SplitRange");
1291
1293 std::vector<std::string> catNames;
1294
1295 for (auto *proxy : static_range_cast<RooRealProxy *>(newSimPdf->_pdfProxyList)) {
1296 catNames.emplace_back(proxy->GetName());
1297 std::string const &catName = catNames.back();
1298 const std::string prefix = "_" + catName + "_";
1299
1300 const std::string origname = proxy->arg().GetName();
1301
1302 auto pdfClone = RooHelpers::cloneTreeWithSameParameters(static_cast<RooAbsPdf const &>(proxy->arg()), &normSet);
1303
1304 markObs(pdfClone.get(), prefix, normSet);
1305
1306 std::unique_ptr<RooArgSet> pdfNormSet{
1307 std::unique_ptr<RooArgSet>(pdfClone->getVariables())->selectByAttrib("__obs__", true)};
1308 std::unique_ptr<RooArgSet> condVarSet{
1309 std::unique_ptr<RooArgSet>(pdfClone->getVariables())->selectByAttrib("__conditional__", true)};
1310
1311 pdfNormSet->remove(*condVarSet, true, true);
1312
1313 if (rangeName) {
1315 }
1316
1318 pdfContext.setLikelihoodMode(ctx.likelihoodMode());
1319 auto *pdfFinal = pdfContext.compile(*pdfClone, *newSimPdf, *pdfNormSet);
1320
1321 // We can only prefix the observables after everything related the
1322 // compiling of the compute graph for the normalization set is done. This
1323 // is because of a subtlety in conditional RooProdPdfs, which stores the
1324 // normalization sets for the individual pdfs in RooArgSets that are
1325 // disconnected from the computation graph, so we have no control over
1326 // them. An alternative would be to use recursive server re-direction,
1327 // but this has more performance overhead.
1328 prefixArgs(pdfFinal, prefix, normSet);
1329
1330 pdfFinal->fixAddCoefNormalization(*pdfNormSet, false);
1331
1332 pdfClone->SetName((std::string("_") + pdfClone->GetName()).c_str());
1333 pdfFinal->addOwnedComponents(std::move(pdfClone));
1334
1335 pdfFinal->setAttribute(("ORIGNAME:" + origname).c_str());
1336 newPdfs.add(*pdfFinal);
1337
1338 // We will remove the old pdf server because we will fill the new ones by
1339 // hand via the creation of new proxies.
1340 newSimPdf->removeServer(const_cast<RooAbsReal &>(proxy->arg()), true);
1341 }
1342
1343 // Replace pdfs with compiled pdfs. Don't use RooAbsArg::redirectServers()
1344 // here, because it doesn't support replacing two servers with the same name
1345 // (it can happen in a RooSimultaneous that two pdfs have the same name).
1346
1347 // First delete old proxies (we have already removed the servers before).
1348 newSimPdf->_pdfProxyList.Delete();
1349
1350 // Recreate the _pdfProxyList with the compiled pdfs
1351 for (std::size_t i = 0; i < newPdfs.size(); ++i) {
1352 const char *label = catNames[i].c_str();
1353 newSimPdf->_pdfProxyList.Add(
1354 new RooRealProxy(label, label, newSimPdf.get(), *static_cast<RooAbsReal *>(newPdfs[i])));
1355 }
1356
1357 ctx.compileServers(*newSimPdf, normSet); // to trigger compiling also the index category
1358
1359 return newSimPdf;
1360}
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define coutI(a)
#define oocoutW(o, a)
#define oocxcoutD(o, a)
#define oocoutI(o, a)
#define coutE(a)
RooTemplateProxy< RooAbsReal > RooRealProxy
Compatibility typedef replacing the old RooRealProxy class.
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 data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:148
const_iterator begin() const
const_iterator end() const
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
bool dependsOn(const RooAbsCollection &serverList, const RooAbsArg *ignoreArg=nullptr, bool valueOnly=false) const
Test whether we depend on (ie, are served by) any object in the specified collection.
void setStringAttribute(const Text_t *key, const Text_t *value)
Associate string 'value' to this object under key 'key'.
void SetName(const char *name) override
Set the name of the TNamed.
bool addOwnedComponents(const RooAbsCollection &comps)
Take ownership of the contents of 'comps'.
const Text_t * getStringAttribute(const Text_t *key) const
Get string attribute mapped under key 'key'.
bool redirectServers(const RooAbsCollection &newServerList, bool mustReplaceAll=false, bool nameChange=false, bool isRecursionStep=false)
Replace all direct servers of this object with the new servers in newServerList.
bool getAttribute(const Text_t *name) const
Check if a named attribute is set. By default, all attributes are unset.
TObject * Clone(const char *newname=nullptr) const override
Make a clone of an object using the Streamer facility.
Definition RooAbsArg.h:88
Abstract base class for objects that represent a discrete value that can be set from the outside,...
A space to attach TBranches.
bool contains(const char *name) const
Check if collection contains an argument with a specific name.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
virtual bool addOwned(RooAbsArg &var, bool silent=false)
Add an argument and transfer the ownership to the collection.
RooAbsArg * find(const char *name) const
Find object with given name in list.
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:56
virtual const RooArgSet * get() const
Definition RooAbsData.h:100
virtual Roo1DTable * table(const RooArgSet &catSet, const char *cuts="", const char *opts="") const
Construct table for product of categories in catSet.
RooFit::OwningPtr< RooAbsData > reduce(const RooCmdArg &arg1, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}) const
Create a reduced copy of this dataset.
virtual Int_t numEntries() const
Return number of entries in dataset, i.e., count unweighted entries.
Abstract base class for generator contexts of RooAbsPdf objects.
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
RooArgSet const * _normSet
! Normalization set with for above integral
Definition RooAbsPdf.h:314
RooPlot * plotOn(RooPlot *frame, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}, const RooCmdArg &arg9={}, const RooCmdArg &arg10={}) const override
Helper calling plotOn(RooPlot*, RooLinkedList&) const.
Definition RooAbsPdf.h:116
bool canBeExtended() const
If true, PDF can provide extended likelihood term.
Definition RooAbsPdf.h:214
@ CanBeExtended
Definition RooAbsPdf.h:208
@ MustBeExtended
Definition RooAbsPdf.h:208
@ CanNotBeExtended
Definition RooAbsPdf.h:208
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
RooDataHist * fillDataHist(RooDataHist *hist, const RooArgSet *nset, double scaleFactor, bool correctForBinVolume=false, bool showProgress=false) const
Fill a RooDataHist with values sampled from this function at the bin centers.
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:107
bool plotSanityChecks(RooPlot *frame) const
Utility function for plotOn(), perform general sanity check on frame to ensure safe plotting operatio...
virtual std::unique_ptr< RooAbsReal > createAsymmetryComponent(const RooAbsCategoryLValue &asymCat, const RooAbsCategoryLValue &asymCatState) const
Build the component function of an asymmetry plot (see plotAsymOn()) that corresponds to a fixed stat...
virtual RooPlot * plotOn(RooPlot *frame, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}, const RooCmdArg &arg9={}, const RooCmdArg &arg10={}) const
Plot (project) PDF on specified frame.
void makeProjectionSet(const RooAbsArg *plotVar, const RooArgSet *allVars, RooArgSet &projectedVars, bool silent) const
Utility function for plotOn() that constructs the set of observables to project when plotting ourselv...
Efficient implementation of a sum of PDFs of the form.
Definition RooAddPdf.h:32
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
RooArgSet * snapshot(bool deepCopy=true) const
Use RooAbsCollection::snapshot(), but return as RooArgSet.
Definition RooArgSet.h:159
RooArgSet * selectCommon(const RooAbsCollection &refColl) const
Use RooAbsCollection::selecCommon(), but return as RooArgSet.
Definition RooArgSet.h:154
static std::unique_ptr< RooAbsPdf > create(RooAbsPdf &pdf, RooAbsData const &data, double precision)
Creates a wrapping RooBinSamplingPdf if appropriate.
Int_t setObj(const RooArgSet *nset, T *obj, const TNamed *isetRangeName=nullptr)
Setter function without integration set.
T * getObjByIndex(Int_t index) const
Retrieve payload object by slot index.
Int_t lastIndex() const
Return index of slot used in last get or set operation.
T * getObj(const RooArgSet *nset, Int_t *sterileIndex=nullptr, const TNamed *isetRangeName=nullptr)
Getter function without integration set.
Named container for two doubles, two integers two object points and three string pointers that can be...
Definition RooCmdArg.h:26
Configurable parser for RooCmdArg named arguments.
void defineMutex(const char *head, Args_t &&... tail)
Define arguments where any pair is mutually exclusive.
bool process(const RooCmdArg &arg)
Process given RooCmdArg.
double getDouble(const char *name, double defaultValue=0.0) const
Return double property registered with name 'name'.
bool defineDouble(const char *name, const char *argName, int doubleNum, double defValue=0.0)
Define double property name 'name' mapped to double in slot 'doubleNum' in RooCmdArg with name argNam...
RooArgSet * getSet(const char *name, RooArgSet *set=nullptr) const
Return RooArgSet property registered with name 'name'.
bool defineSet(const char *name, const char *argName, int setNum, const RooArgSet *set=nullptr)
Define TObject property name 'name' mapped to object in slot 'setNum' in RooCmdArg with name argName ...
bool ok(bool verbose) const
Return true of parsing was successful.
bool defineObject(const char *name, const char *argName, int setNum, const TObject *obj=nullptr, bool isArray=false)
Define TObject property name 'name' mapped to object in slot 'setNum' in RooCmdArg with name argName ...
const char * getString(const char *name, const char *defaultValue="", bool convEmptyToNull=false) const
Return string property registered with name 'name'.
bool defineString(const char *name, const char *argName, int stringNum, const char *defValue="", bool appendMode=false)
Define double property name 'name' mapped to double in slot 'stringNum' in RooCmdArg with name argNam...
const RooLinkedList & getObjectList(const char *name) const
Return list of objects registered with name 'name'.
bool defineInt(const char *name, const char *argName, int intNum, int defValue=0)
Define integer property name 'name' mapped to integer in slot 'intNum' in RooCmdArg with name argName...
void allowUndefined(bool flag=true)
If flag is true the processing of unrecognized RooCmdArgs is not considered an error.
int getInt(const char *name, int defaultValue=0) const
Return integer property registered with name 'name'.
TObject * getObject(const char *name, TObject *obj=nullptr) const
Return TObject property registered with name 'name'.
void removeAll() override
Remove all argument inset using remove(const RooAbsArg&).
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...
Combines several disjunct datasets into one.
Container class to hold N-dimensional binned data.
Definition RooDataHist.h:40
double weight(std::size_t i) const
Return weight of i-th bin.
void set(std::size_t binNumber, double weight, double wgtErr)
Set bin content of bin that was last loaded with get(std::size_t).
double sumEntries() const override
Sum the weights of all bins.
Container class to hold unbinned data.
Definition RooDataSet.h:32
Collection class for internal use, storing a collection of RooAbsArg pointers in a doubly linked list...
static const TNamed * ptr(const char *stringPtr)
Return a unique TNamed pointer for given C++ string.
Plot frame and a container for graphics objects within that frame.
Definition RooPlot.h:43
const RooArgSet * getNormVars() const
Definition RooPlot.h:146
RooAbsRealLValue * getPlotVar() const
Definition RooPlot.h:137
Facilitates simultaneous fitting of multiple PDFs to subsets of a given dataset.
void selectNormalization(const RooArgSet *depSet=nullptr, bool force=false) override
Interface function used by test statistics to freeze choice of observables for interpretation of frac...
double evaluate() const override
Return the current value: the value of the PDF associated with the current index category state.
Int_t _numPdf
Number of registered PDFs.
void selectNormalizationRange(const char *rangeName=nullptr, bool force=false) override
Interface function used by test statistics to freeze choice of range for interpretation of fraction c...
TList _pdfProxyList
List of PDF proxies (named after applicable category state)
std::unique_ptr< RooAbsReal > createAsymmetryComponent(const RooAbsCategoryLValue &asymCat, const RooAbsCategoryLValue &asymCatState) const override
Build the component function of an asymmetry plot (see RooAbsReal::plotAsymOn()) for a fixed state of...
RooObjCacheManager _partIntMgr
! Component normalization manager
~RooSimultaneous() override
Destructor.
RooFit::OwningPtr< RooDataSet > generateSimGlobal(const RooArgSet &whatVars, Int_t nEvents) override
Special generator interface for generation of 'global observables' – for RooStats tools.
RooArgSet const & flattenedCatList() const
Internal utility function to get a list of all category components for this RooSimultaneous.
RooPlot * plotOn(RooPlot *frame, const RooCmdArg &arg1, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}, const RooCmdArg &arg9={}, const RooCmdArg &arg10={}) const override
ExtendMode extendMode() const override
Examine the pdf components and check if one of them can be extended or must be extended.
RooCategoryProxy _indexCat
Index category.
double analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Return analytical integration defined by given code.
Int_t getAnalyticalIntegralWN(RooArgSet &allVars, RooArgSet &numVars, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Forward determination of analytical integration capabilities to component p.d.f.s A unique code is as...
double expectedEvents(const RooArgSet *nset) const override
Return the number of expected events: If the index is in nset, then return the sum of the expected ev...
friend class RooSimGenContext
RooAbsGenContext * autoGenContext(const RooArgSet &vars, const RooDataSet *prototype=nullptr, const RooArgSet *auxProto=nullptr, bool verbose=false, bool autoBinned=true, const char *binnedTag="") const override
RooAbsPdf * getPdf(RooStringView catName) const
Return the p.d.f associated with the given index category name.
std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const override
static std::unique_ptr< RooSimultaneous::InitializationOutput > initialize(std::string const &name, RooAbsCategoryLValue &inIndexCat, std::map< std::string, RooAbsPdf * > const &pdfMap)
void wrapPdfsInBinSamplingPdfs(RooAbsData const &data, double precision)
Wraps the components of this RooSimultaneous in RooBinSamplingPdfs.
const TNamed * _plotCoefNormRange
RooAbsGenContext * genContext(const RooArgSet &vars, const RooDataSet *prototype=nullptr, const RooArgSet *auxProto=nullptr, bool verbose=false) const override
Return specialized generator context for simultaneous p.d.f.s.
std::unique_ptr< RooArgSet > _indexCatSet
! Index category wrapped in a RooArgSet if needed internally
bool addPdf(const RooAbsPdf &pdf, const char *catLabel)
Associate given PDF with index category state label 'catLabel'.
RooSetProxy _plotCoefNormSet
const RooAbsCategoryLValue & indexCat() const
friend class RooSimSplitGenContext
virtual RooDataHist * fillDataHist(RooDataHist *hist, const RooArgSet *nset, double scaleFactor, bool correctForBinVolume=false, bool showProgress=false) const
The RooStringView is a wrapper around a C-style string that can also be constructed from a std::strin...
Joins several RooAbsCategoryLValue objects into a single category.
const char * label() const
Get the label of the current category state. This function only makes sense for category proxies.
const T & arg() const
Return reference to object held in proxy.
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
Definition TList.cxx:708
void Add(TObject *obj) override
Definition TList.h:81
void Delete(Option_t *option="") override
Remove all objects from the list AND delete all heap based objects.
Definition TList.cxx:600
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
Mother of all ROOT objects.
Definition TObject.h:42
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:461
virtual Int_t IndexOf(const TObject *obj) const
Return index of object in collection.
Basic string class.
Definition TString.h:138
RooCmdArg SelectVars(const RooArgSet &vars)
RooCmdArg Import(const char *state, TH1 &histo)
RooCmdArg ProjWData(const RooAbsData &projData, bool binData=false)
RooCmdArg Project(const RooArgSet &projSet)
RooCmdArg Normalization(double scaleFactor)
RooCmdArg Cut(const char *cutSpec)
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
std::string makeSliceCutString(RooArgSet const &sliceDataSet)
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
Definition CodegenImpl.h:72
T * OwningPtr
An alias for raw pointers for indicating that the return type of a RooFit function is an owning point...
Definition Config.h:35
OwningPtr< T > makeOwningPtr(std::unique_ptr< T > &&ptr)
Internal helper to turn a std::unique_ptr<T> into an OwningPtr.
Definition Config.h:40
std::unique_ptr< T > cloneTreeWithSameParameters(T const &arg, RooArgSet const *observables=nullptr)
Clone RooAbsArg object and reattach to original parameters.
std::string getRangeNameForSimComponent(std::string const &rangeName, bool splitRange, std::string const &catName)
Internal struct used for initialization.
std::vector< RooAbsPdf const * > finalPdfs
std::vector< std::string > finalCatLabels
void addPdf(const RooAbsPdf &pdf, std::string const &catLabel)
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2335