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. If the index category is among the normalization
31variables, the expected number of events by a RooSimultaneous is the sum over
32all components. Otherwise, it is that of the component p.d.f. selected by the
33index category. For a RooSuperCategory index, it counts as being among the
34normalization variables if all of its input categories are.
35
36The index category can be accessed using indexCategory().
37
38###Generating events
39When generating events from a RooSimultaneous, the index category has to be added to
40the dataset. Further, the PDF needs to know the relative probabilities of each category, i.e.,
41how many events are in which category. This can be achieved in two ways:
42- Generating with proto data that have category entries: An event from the same category as
43in the proto data is created for each event in the proto data.
44See RooAbsPdf::generate(const RooArgSet&,const RooDataSet&,Int_t,bool,bool,bool) const.
45- No proto data: A category is chosen randomly.
46\note This requires that the PDFs building the simultaneous are extended. In this way,
47the relative probability of each category can be calculated from the number of events
48in each category.
49
50###Switch mode
51If the index category is not an observable, but a parameter, the RooSimultaneous
52acts as a "switch" that evaluates to the component selected by the current index
53state, like a RooMultiPdf. Its expected number of events is then the one of the
54selected component.
55
56###Nesting simultaneous PDFs
57RooSimultaneous components are currently flattened into a RooSimultaneous over a
58RooSuperCategory of all index categories. This is deprecated: from ROOT 6.44,
59they are kept as they are and only supported if their index category is a
60parameter (switch mode). To combine channels, use one RooSimultaneous over a
61RooCategory with one state per channel.
62**/
63
64#include "RooSimultaneous.h"
65
66#include "Roo1DTable.h"
68#include "RooAbsData.h"
69#include "RooAddPdf.h"
70#include "RooArgSet.h"
71#include "RooBinSamplingPdf.h"
72#include "RooCategory.h"
73#include "RooCmdConfig.h"
75#include "RooDataHist.h"
76#include "RooDataSet.h"
77#include "RooFormulaVar.h"
78#include "RooGlobalFunc.h"
79#include "RooMsgService.h"
80#include "RooNameReg.h"
81#include "RooPlot.h"
82#include "RooRandom.h"
83#include "RooRealVar.h"
84#include "RooSimGenContext.h"
86#include "RooSuperCategory.h"
87
88#include "RooFitImplHelpers.h"
89
90#include <ROOT/StringUtils.hxx>
91
92#include <algorithm>
93#include <iostream>
94#include <map>
95
96namespace {
97
98std::map<std::string, RooAbsPdf *> createPdfMap(const RooArgList &inPdfList, RooAbsCategoryLValue &inIndexCat)
99{
100 std::map<std::string, RooAbsPdf *> pdfMap;
101 auto indexCatIt = inIndexCat.begin();
102 for (unsigned int i = 0; i < inPdfList.size(); ++i) {
103 auto pdf = static_cast<RooAbsPdf *>(&inPdfList[i]);
104 const auto &nameIdx = (*indexCatIt++);
105 pdfMap[nameIdx.first] = pdf;
106 }
107 return pdfMap;
108}
109
110void replaceOrAdd(RooLinkedList &lst, TObject &obj)
111{
112 TObject *old = lst.FindObject(obj.GetName());
113 if (old)
114 lst.Replace(old, &obj);
115 else
116 lst.Add(&obj);
117}
118
119} // namespace
120
122
123void RooSimultaneous::InitializationOutput::addPdf(const RooAbsPdf &pdf, std::string const &catLabel)
124{
125 finalPdfs.push_back(&pdf);
126 finalCatLabels.emplace_back(catLabel);
127}
128
129using std::string;
130
131
132
133
134////////////////////////////////////////////////////////////////////////////////
135/// Constructor with index category. PDFs associated with indexCat
136/// states can be added after construction with the addPdf() function.
137///
138/// RooSimultaneous can function without having a PDF associated
139/// with every single state. The normalization in such cases is taken
140/// from the number of registered PDFs, but getVal() will assert if
141/// when called for an unregistered index state.
142
143RooSimultaneous::RooSimultaneous(const char *name, const char *title,
144 RooAbsCategoryLValue& inIndexCat) :
145 RooSimultaneous{name, title, std::map<std::string, RooAbsPdf*>{}, inIndexCat}
146{
147}
148
149
150////////////////////////////////////////////////////////////////////////////////
151/// Constructor from index category and full list of PDFs.
152/// In this constructor form, a PDF must be supplied for each indexCat state
153/// to avoid ambiguities. The PDFs are associated with the states of the
154/// index category as they appear when iterating through the category states
155/// with RooAbsCategory::begin() and RooAbsCategory::end(). This usually means
156/// they are associated by ascending index numbers.
157///
158/// PDFs may not overlap (i.e. share any variables) with the index category (function)
159
160RooSimultaneous::RooSimultaneous(const char *name, const char *title,
161 const RooArgList& inPdfList, RooAbsCategoryLValue& inIndexCat) :
162 RooSimultaneous{name, title, createPdfMap(inPdfList, inIndexCat), inIndexCat}
163{
164 if (inPdfList.size() != inIndexCat.size()) {
165 std::stringstream errMsg;
166 errMsg << "RooSimultaneous::ctor(" << GetName()
167 << " ERROR: Number PDF list entries must match number of index category states, no PDFs added";
168 coutE(InputArguments) << errMsg.str() << std::endl;
169 throw std::invalid_argument(errMsg.str());
170 }
171}
172
173
174////////////////////////////////////////////////////////////////////////////////
175
176RooSimultaneous::RooSimultaneous(const char *name, const char *title, std::map<string, RooAbsPdf *> pdfMap,
177 RooAbsCategoryLValue &inIndexCat)
178 : RooSimultaneous(name, title, std::move(*initialize(name ? name : "", inIndexCat, pdfMap)))
179{
180}
181
182/// For internal use in RooFit.
183RooSimultaneous::RooSimultaneous(const char *name, const char *title,
185 RooAbsCategoryLValue &inIndexCat)
186 : RooSimultaneous(name, title, RooFit::Detail::flatMapToStdMap(pdfMap), inIndexCat)
187{
188}
189
191 : RooAbsPdf(name, title),
192 _plotCoefNormSet("!plotCoefNormSet", "plotCoefNormSet", this, false, false),
193 _partIntMgr(this, 10),
194 _indexCat("indexCat", "Index category", this, *initInfo.indexCat)
195{
196 for (std::size_t i = 0; i < initInfo.finalPdfs.size(); ++i) {
197 addPdf(*initInfo.finalPdfs[i], initInfo.finalCatLabels[i].c_str());
198 }
199
200 // Take ownership of eventual super category
201 if (initInfo.superIndex) {
202 addOwnedComponents(std::move(initInfo.superIndex));
203 }
204}
205
206/// \cond ROOFIT_INTERNAL
207
208// This class cannot be locally defined in initialize as it cannot be
209// used as a template argument in that case
210namespace RooSimultaneousAux {
211 struct CompInfo {
212 RooAbsPdf* pdf ;
213 RooSimultaneous* simPdf ;
214 const RooAbsCategoryLValue* subIndex ;
215 std::unique_ptr<RooArgSet> subIndexComps;
216 } ;
217}
218
219/// \endcond
220
221std::unique_ptr<RooSimultaneous::InitializationOutput>
223 std::map<std::string, RooAbsPdf *> const& pdfMap)
224
225{
226 auto out = std::make_unique<RooSimultaneous::InitializationOutput>();
227 out->indexCat = &inIndexCat;
228
229 // First see if there are any RooSimultaneous input components
230 bool simComps(false) ;
231 for (auto const& item : pdfMap) {
232 if (dynamic_cast<RooSimultaneous*>(item.second)) {
233 simComps = true ;
234 break ;
235 }
236 }
237
238 // If there are no simultaneous component p.d.f. do simple processing through addPdf()
239 if (!simComps) {
240 for (auto const& item : pdfMap) {
241 out->addPdf(*item.second,item.first);
242 }
243 return out;
244 }
245
246 std::string msgPrefix = "RooSimultaneous::initialize(" + name + ") ";
247
248 std::string nestedNames;
249 std::size_t nNested = 0;
250 for (auto const &item : pdfMap) {
251 if (dynamic_cast<RooSimultaneous *>(item.second)) {
252 nestedNames += (nNested++ ? ", \"" : "\"") + std::string(item.second->GetName()) + "\"";
253 }
254 }
255 oocoutW(nullptr, InputArguments)
256 << msgPrefix << (nNested > 1 ? "the components " : "the component ") << nestedNames
257 << (nNested > 1 ? " are RooSimultaneous themselves and get" : " is a RooSimultaneous itself and gets")
258 << " flattened into a\nRooSimultaneous over a RooSuperCategory. This is deprecated: from ROOT 6.44, nested "
259 "RooSimultaneous are only\nsupported if their index category is a parameter (switch mode), and until then the "
260 "flattening breaks such\nswitches. To combine channels, use one RooSimultaneous over a RooCategory with one "
261 "state per channel."
262 << std::endl;
263
264 // Replicating a component to several states of the flattened index category
265 // silently changes the model (GitHub issue #23342).
266 auto warnReplication = [&](RooAbsPdf const &pdf, std::string const &label, RooArgSet const &repliCats,
267 std::size_t nReplicas) {
268 oocoutW(nullptr, InputArguments)
269 << msgPrefix << "\"" << pdf.GetName() << "\" (state \"" << label << "\") doesn't depend on " << repliCats
270 << " and is copied into " << nReplicas << " states; if it is extended, its expected events are counted "
271 << nReplicas << " times (GitHub issue #23342)." << std::endl;
272 };
273
274 RooArgSet allAuxCats ;
275 std::map<string,RooSimultaneousAux::CompInfo> compMap ;
276 for (auto const& item : pdfMap) {
277 RooSimultaneousAux::CompInfo ci ;
278 ci.pdf = item.second ;
279 RooSimultaneous* simComp = dynamic_cast<RooSimultaneous*>(item.second) ;
280 if (simComp) {
281 ci.simPdf = simComp ;
282 ci.subIndex = &simComp->indexCat() ;
283 ci.subIndexComps = simComp->indexCat().isFundamental()
284 ? std::make_unique<RooArgSet>(simComp->indexCat())
285 : std::unique_ptr<RooArgSet>(simComp->indexCat().getVariables());
286 allAuxCats.add(*ci.subIndexComps,true) ;
287 } else {
288 ci.simPdf = nullptr;
289 ci.subIndex = nullptr;
290 }
291 compMap[item.first] = std::move(ci);
292 }
293
294 // Construct the 'superIndex' from the nominal index category and all auxiliary components
295 RooArgSet allCats(inIndexCat) ;
296 allCats.add(allAuxCats) ;
297 std::string siname = name + "_index";
298 out->superIndex = std::make_unique<RooSuperCategory>(siname.c_str(),siname.c_str(),allCats) ;
299 auto *superIndex = out->superIndex.get();
300 out->indexCat = superIndex;
301
302 // Now process each of original pdf/state map entries
303 for (auto const& citem : compMap) {
304
305 RooArgSet repliCats(allAuxCats) ;
306 if (citem.second.subIndexComps) {
307 repliCats.remove(*citem.second.subIndexComps) ;
308 }
309 inIndexCat.setLabel(citem.first.c_str()) ;
310
311 if (!citem.second.simPdf) {
312
313 // Entry is a plain p.d.f. assign it to every state permutation of the repliCats set
314 RooSuperCategory repliSuperCat("tmp","tmp",repliCats) ;
315 if (repliSuperCat.size() > 1) {
316 warnReplication(*citem.second.pdf, citem.first, repliCats, repliSuperCat.size());
317 }
318
319 // Iterator over all states of repliSuperCat
320 for (const auto& nameIdx : repliSuperCat) {
321 // Set value
322 repliSuperCat.setLabel(nameIdx.first) ;
323 // Retrieve corresponding label of superIndex
324 string superLabel = superIndex->getCurrentLabel() ;
325 out->addPdf(*citem.second.pdf,superLabel);
326 oocxcoutD(static_cast<RooAbsArg*>(nullptr), InputArguments) << msgPrefix
327 << "assigning pdf " << citem.second.pdf->GetName() << " to super label " << superLabel << std::endl ;
328 }
329 } else {
330
331 // Entry is a simultaneous p.d.f
332
333 if (repliCats.empty()) {
334
335 // Case 1 -- No replication of components of RooSim component are required
336
337 for (const auto& type : *citem.second.subIndex) {
338 const_cast<RooAbsCategoryLValue*>(citem.second.subIndex)->setLabel(type.first.c_str());
339 string superLabel = superIndex->getCurrentLabel() ;
340 RooAbsPdf* compPdf = citem.second.simPdf->getPdf(type.first);
341 if (compPdf) {
342 out->addPdf(*compPdf,superLabel);
343 oocxcoutD(static_cast<RooAbsArg*>(nullptr), InputArguments) << msgPrefix
344 << "assigning pdf " << compPdf->GetName() << "(member of " << citem.second.pdf->GetName()
345 << ") to super label " << superLabel << std::endl ;
346 } else {
347 oocoutW(nullptr, InputArguments) << msgPrefix << "WARNING: No p.d.f. associated with label "
348 << type.second << " for component RooSimultaneous p.d.f " << citem.second.pdf->GetName()
349 << "which is associated with master index label " << citem.first << std::endl ;
350 }
351 }
352
353 } else {
354
355 // Case 2 -- Replication of components of RooSim component are required
356
357 // Make replication supercat
358 RooSuperCategory repliSuperCat("tmp","tmp",repliCats) ;
359 if (repliSuperCat.size() > 1) {
360 warnReplication(*citem.second.pdf, citem.first, repliCats, repliSuperCat.size());
361 }
362
363 for (const auto& stype : *citem.second.subIndex) {
364 const_cast<RooAbsCategoryLValue*>(citem.second.subIndex)->setLabel(stype.first.c_str());
365
366 for (const auto& nameIdx : repliSuperCat) {
367 repliSuperCat.setLabel(nameIdx.first) ;
368 const string superLabel = superIndex->getCurrentLabel() ;
369 RooAbsPdf* compPdf = citem.second.simPdf->getPdf(stype.first);
370 if (compPdf) {
371 out->addPdf(*compPdf,superLabel);
372 oocxcoutD(static_cast<RooAbsArg*>(nullptr), InputArguments) << msgPrefix
373 << "assigning pdf " << compPdf->GetName() << "(member of " << citem.second.pdf->GetName()
374 << ") to super label " << superLabel << std::endl ;
375 } else {
376 oocoutW(nullptr, InputArguments) << msgPrefix << "WARNING: No p.d.f. associated with label "
377 << stype.second << " for component RooSimultaneous p.d.f " << citem.second.pdf->GetName()
378 << "which is associated with master index label " << citem.first << std::endl ;
379 }
380 }
381 }
382 }
383 }
384 }
385
386 return out;
387}
388
389
390////////////////////////////////////////////////////////////////////////////////
391/// Copy constructor
392
394 RooAbsPdf(other,name),
395 _plotCoefNormSet("!plotCoefNormSet",this,other._plotCoefNormSet),
396 _plotCoefNormRange(other._plotCoefNormRange),
397 _partIntMgr(other._partIntMgr,this),
398 _indexCat("indexCat",this,other._indexCat),
399 _numPdf(other._numPdf)
400{
401 // Copy proxy list
402 for(auto* proxy : static_range_cast<RooRealProxy*>(other._pdfProxyList)) {
403 _pdfProxyList.Add(new RooRealProxy(proxy->GetName(),this,*proxy)) ;
404 }
405}
406
407
408
409////////////////////////////////////////////////////////////////////////////////
410/// Destructor
411
416
417
418
419////////////////////////////////////////////////////////////////////////////////
420/// Return the p.d.f associated with the given index category name
421
423{
424 RooRealProxy* proxy = static_cast<RooRealProxy*>(_pdfProxyList.FindObject(catName.c_str()));
425 return proxy ? static_cast<RooAbsPdf*>(proxy->absArg()) : nullptr;
426}
427
428
429
430////////////////////////////////////////////////////////////////////////////////
431/// Associate given PDF with index category state label 'catLabel'.
432/// The name state must be already defined in the index category.
433///
434/// RooSimultaneous can function without having a PDF associated
435/// with every single state. The normalization in such cases is taken
436/// from the number of registered PDFs, but getVal() will fail if
437/// called for an unregistered index state.
438///
439/// PDFs may not overlap (i.e. share any variables) with the index category (function).
440/// \param[in] pdf PDF to be added.
441/// \param[in] catLabel Name of the category state to be associated to the PDF.
442/// \return `true` in case of failure.
443
444bool RooSimultaneous::addPdf(const RooAbsPdf& pdf, const char* catLabel)
445{
446 // PDFs cannot overlap with the index category
447 if (pdf.dependsOn(_indexCat.arg())) {
448 coutE(InputArguments) << "RooSimultaneous::addPdf(" << GetName() << "): PDF '" << pdf.GetName()
449 << "' overlaps with index category '" << _indexCat.arg().GetName() << "'."<< std::endl ;
450 return true ;
451 }
452
453 // Each index state can only have one PDF associated with it
454 if (_pdfProxyList.FindObject(catLabel)) {
455 coutE(InputArguments) << "RooSimultaneous::addPdf(" << GetName() << "): index state '"
456 << catLabel << "' has already an associated PDF." << std::endl ;
457 return true ;
458 }
459
460 const RooSimultaneous* simPdf = dynamic_cast<const RooSimultaneous*>(&pdf) ;
461 if (simPdf) {
462
463 coutE(InputArguments) << "RooSimultaneous::addPdf(" << GetName()
464 << ") ERROR: you cannot add a RooSimultaneous component to a RooSimultaneous using addPdf()."
465 << " Use the constructor with RooArgList if input p.d.f.s or the map<string,RooAbsPdf&> instead." << std::endl ;
466 return true ;
467
468 } else {
469
470 // Create a proxy named after the associated index state
471 TObject* proxy = new RooRealProxy(catLabel,catLabel,this,const_cast<RooAbsPdf&>(pdf));
472 _pdfProxyList.Add(proxy) ;
473 _numPdf += 1 ;
474 }
475
476 return false ;
477}
478
479////////////////////////////////////////////////////////////////////////////////
480/// Examine the pdf components and check if one of them can be extended or must be extended.
481/// It is enough to have one component that can be extended or must be extended to return the flag in
482/// the total simultaneous pdf.
483
485{
486 bool anyCanExtend = false;
487
488 for (auto *proxy : static_range_cast<RooRealProxy *>(_pdfProxyList)) {
489 auto &pdf = static_cast<RooAbsPdf const&>(proxy->arg());
490 if (pdf.mustBeExtended())
491 return MustBeExtended;
492 anyCanExtend |= pdf.canBeExtended();
493 }
494 return anyCanExtend ? CanBeExtended : CanNotBeExtended;
495}
496
497////////////////////////////////////////////////////////////////////////////////
498/// Return the current value:
499/// the value of the PDF associated with the current index category state
500
502{
503 // Retrieve the proxy by index name
505 if(!proxy) {
506 return 0;
507 }
508
509 double nEvtTot = 1.0;
510 double nEvtCat = 1.0;
511
512 // Relative yield weight only if normalized over the index states. In
513 // "switch mode", the value is the one of the selected component.
515
516 nEvtTot = 0;
517 nEvtCat = 0;
518
519 for (auto *proxy2 : static_range_cast<RooRealProxy *>(_pdfProxyList)) {
520 auto &pdf2 = static_cast<RooAbsPdf const &>(proxy2->arg());
521 if(!pdf2.canBeExtended()) {
522 // If one of the pdfs can't be expected, reset the normalization
523 // factor to one and break out of the loop.
524 nEvtTot = 1.0;
525 nEvtCat = 1.0;
526 break;
527 }
528 const double nEvt = pdf2.expectedEvents(_normSet);
529 nEvtTot += nEvt;
530 if (proxy == proxy2) {
531 // Matching by proxy by pointer rather than pdfs, because it's
532 // possible to have the same pdf used in different states.
533 nEvtCat += nEvt;
534 }
535 }
536 }
537 double catFrac = nEvtCat / nEvtTot;
538
539 // Return the selected PDF value, normalized by the relative number of
540 // expected events if applicable.
541 return *proxy * catFrac;
542}
543
544////////////////////////////////////////////////////////////////////////////////
545/// Return the number of expected events: If the index is in nset,
546/// then return the sum of the expected events of all components,
547/// otherwise return the number of expected events of the PDF
548/// associated with the current index category state
549
551{
552 if (indexCatIsInNormSet(nset)) {
553
554 double sum(0) ;
555
556 for(auto * proxy : static_range_cast<RooRealProxy*>(_pdfProxyList)) {
557 sum += (static_cast<RooAbsPdf*>(proxy->absArg()))->expectedEvents(nset) ;
558 }
559
560 return sum ;
561
562 } else {
563
564 // Retrieve the proxy by index name
566
567 //assert(proxy!=0) ;
568 if (proxy==nullptr) return 0 ;
569
570 // Return the selected PDF value, normalized by the number of index states
571 return (static_cast<RooAbsPdf*>(proxy->absArg()))->expectedEvents(nset);
572 }
573}
574
575
576
577////////////////////////////////////////////////////////////////////////////////
578/// Expected events function for the new evaluation backends: the sum over all
579/// components, or the selected component in "switch mode" (see expectedEvents()).
580
581std::unique_ptr<RooAbsReal> RooSimultaneous::createExpectedEventsFunc(const RooArgSet *nset) const
582{
583 const std::string name = std::string(GetName()) + "_expectedEvents";
584
585 // One function per distinct component, because the same pdf can be used in
586 // several states. Components that can't be extended contribute zero, like
587 // in expectedEvents().
588 RooArgList formulaArgs;
589 RooArgSet ownedFuncs;
590 std::map<RooAbsPdf const *, std::string> funcRefs;
591 bool failed = false;
592 auto ref = [&](RooAbsPdf const &pdf) -> std::string {
593 if (!pdf.canBeExtended()) {
594 return "0.0";
595 }
596 auto found = funcRefs.find(&pdf);
597 if (found != funcRefs.end()) {
598 return found->second;
599 }
600 std::unique_ptr<RooAbsReal> func = pdf.createExpectedEventsFunc(nset);
601 if (!func) {
602 failed = true;
603 return "0.0";
604 }
605 // Different components can have the same name
606 func->SetName((std::string(func->GetName()) + "_" + std::to_string(funcRefs.size())).c_str());
607 std::string const funcRef = "x[" + std::to_string(formulaArgs.size()) + "]";
608 formulaArgs.add(*func);
609 ownedFuncs.addOwned(std::move(func));
610 return funcRefs[&pdf] = funcRef;
611 };
612
613 std::string formula;
614 if (indexCatIsInNormSet(nset)) {
615 for (auto *proxy : static_range_cast<RooRealProxy *>(_pdfProxyList)) {
616 formula += (formula.empty() ? "" : " + ") + ref(static_cast<RooAbsPdf const &>(proxy->arg()));
617 }
618 if (formula.empty()) {
619 formula = "0.0";
620 }
621 } else {
622 // Nested ternary expression that selects the component matching the
623 // index state, keyed on the state index numbers.
624 formulaArgs.add(_indexCat.arg());
625 std::size_t numStates = 0;
626 for (auto const &nameIdx : _indexCat.arg()) {
627 auto *proxy = static_cast<RooRealProxy *>(_pdfProxyList.FindObject(nameIdx.first.c_str()));
628 if (!proxy) {
629 continue;
630 }
631 formula += "x[0] == " + std::to_string(nameIdx.second) + " ? " +
632 ref(static_cast<RooAbsPdf const &>(proxy->arg())) + " : (";
633 ++numStates;
634 }
635 formula += "0.0" + std::string(numStates, ')');
636 }
637
638 // Like the default implementation, return nullptr if a component can't
639 // create the function.
640 if (failed) {
641 return nullptr;
642 }
643
644 auto out = std::make_unique<RooFormulaVar>(name.c_str(), name.c_str(), formula.c_str(), formulaArgs);
645 out->addOwnedComponents(std::move(ownedFuncs));
646 return out;
647}
648
649////////////////////////////////////////////////////////////////////////////////
650/// Forward determination of analytical integration capabilities to component p.d.f.s
651/// A unique code is assigned to the combined integration capabilities of all associated
652/// p.d.f.s
653
655 const RooArgSet* normSet, const char* rangeName) const
656{
657 // Declare that we can analytically integrate all requested observables
658 analVars.add(allVars) ;
659
660 // Retrieve (or create) the required partial integral list
661 Int_t code ;
662
663 // Check if this configuration was created before
664 CacheElem* cache = static_cast<CacheElem*>(_partIntMgr.getObj(normSet,&analVars,nullptr,RooNameReg::ptr(rangeName))) ;
665 if (cache) {
666 code = _partIntMgr.lastIndex() ;
667 return code+1 ;
668 }
669 cache = new CacheElem ;
670
671 // Create the partial integral set for this request
672 for(auto * proxy : static_range_cast<RooRealProxy*>(_pdfProxyList)) {
673 cache->_partIntList.addOwned(std::unique_ptr<RooAbsReal>{proxy->arg().createIntegral(analVars,normSet,nullptr,rangeName)});
674 }
675
676 // Store the partial integral list and return the assigned code ;
677 code = _partIntMgr.setObj(normSet,&analVars,cache,RooNameReg::ptr(rangeName)) ;
678
679 return code+1 ;
680}
681
682
683
684////////////////////////////////////////////////////////////////////////////////
685/// Return analytical integration defined by given code
686
687double RooSimultaneous::analyticalIntegralWN(Int_t code, const RooArgSet* normSet, const char* /*rangeName*/) const
688{
689 // No integration scenario
690 if (code==0) {
691 return getVal(normSet) ;
692 }
693
694 // Partial integration scenarios, rangeName already encoded in 'code'
695 CacheElem* cache = static_cast<CacheElem*>(_partIntMgr.getObjByIndex(code-1)) ;
696
698 Int_t idx = _pdfProxyList.IndexOf(proxy) ;
699 return (static_cast<RooAbsReal*>(cache->_partIntList.at(idx)))->getVal(normSet) ;
700}
701
702
703
704
705
706
707////////////////////////////////////////////////////////////////////////////////
708/// Back-end for plotOn() implementation on RooSimultaneous which
709/// needs special handling because a RooSimultaneous PDF cannot
710/// project out its index category via integration. plotOn() will
711/// abort if this is requested without providing a projection dataset.
712
714{
715 // Sanity checks
716 if (plotSanityChecks(frame)) return frame ;
717
718 // Special case: if an asymmetry is requested with respect to our index
719 // category, we cannot reroute the plotting to the component pdfs. The
720 // component pdfs don't depend on the index category, so the asymmetry engine
721 // in the base class would not be able to split them by index state. Instead,
722 // we delegate directly to the base class implementation, which constructs the
723 // asymmetry from the two index-state component pdfs (see the overridden
724 // createAsymmetryComponent() and GitHub issue #14255).
725 if (auto *asymCmd = static_cast<RooCmdArg *>(cmdList.FindObject("Asymmetry"))) {
726 auto *asymCat = dynamic_cast<RooAbsCategory const *>(asymCmd->getObject(0));
727 if (asymCat && asymCat == &_indexCat.arg()) {
728
729 RooLinkedList cmdList2(cmdList);
730
731 // The base-class asymmetry-plotting engine averages the projection over
732 // the projection dataset. This is not supported for the composite data
733 // stores that back datasets with a category index, so we flatten such a
734 // projection dataset into a plain (vector-backed) copy first. Both the
735 // copy and the replacement command must outlive the plotOn() call below,
736 // because the command list only stores pointers to them.
737 std::unique_ptr<RooAbsData> flatProjData;
738 RooCmdArg newProjWData;
739 if (auto *projWData = static_cast<RooCmdArg *>(cmdList2.FindObject("ProjData"))) {
740 auto *projData = dynamic_cast<RooDataSet const *>(projWData->getObject(1));
741 if (projData && dynamic_cast<RooCompositeDataStore const *>(projData->store())) {
742 flatProjData = std::make_unique<RooDataSet>(projData->GetName(), projData->GetTitle(), *projData->get(),
743 RooFit::Import(*const_cast<RooDataSet *>(projData)));
744 const RooArgSet *projDataSet = projWData->getSet(0);
745 newProjWData = projDataSet ? RooFit::ProjWData(*projDataSet, *flatProjData)
746 : RooFit::ProjWData(*flatProjData);
747 replaceOrAdd(cmdList2, newProjWData);
748 }
749 }
750
751 return RooAbsReal::plotOn(frame, cmdList2);
752 }
753 }
754
755 // Extract projection configuration from command list
756 RooCmdConfig pc("RooSimultaneous::plotOn(" + std::string(GetName()) + ")");
757 pc.defineString("sliceCatState","SliceCat",0,"",true) ;
758 pc.defineDouble("scaleFactor","Normalization",0,1.0) ;
759 pc.defineInt("scaleType","Normalization",0,RooAbsPdf::Relative) ;
760 pc.defineObject("sliceCatList","SliceCat",0,nullptr,true) ;
761 // This dummy is needed for plotOn to recognize the "SliceCatMany" command.
762 // It is not used directly, but the "SliceCat" commands are nested in it.
763 // Removing this dummy definition results in "ERROR: unrecognized command: SliceCatMany".
764 pc.defineObject("dummy1","SliceCatMany",0) ;
765 pc.defineSet("projSet","Project",0) ;
766 pc.defineSet("sliceSet","SliceVars",0) ;
767 pc.defineSet("projDataSet","ProjData",0) ;
768 pc.defineObject("projData","ProjData",1) ;
769 pc.defineMutex("Project","SliceVars") ;
770 pc.allowUndefined() ; // there may be commands we don't handle here
771
772 // Process and check varargs
773 pc.process(cmdList) ;
774 if (!pc.ok(true)) {
775 return frame ;
776 }
777
778 RooAbsData* projData = static_cast<RooAbsData*>(pc.getObject("projData")) ;
779 const RooArgSet* projDataSet = pc.getSet("projDataSet");
780 const RooArgSet* sliceSetTmp = pc.getSet("sliceSet") ;
781 std::unique_ptr<RooArgSet> sliceSet( sliceSetTmp ? (static_cast<RooArgSet*>(sliceSetTmp->Clone())) : nullptr );
782 const RooArgSet* projSet = pc.getSet("projSet") ;
783 double scaleFactor = pc.getDouble("scaleFactor") ;
784 ScaleType stype = (ScaleType) pc.getInt("scaleType") ;
785
786
787 // Look for category slice arguments and add them to the master slice list if found
788 const char* sliceCatState = pc.getString("sliceCatState",nullptr,true) ;
789 const RooLinkedList& sliceCatList = pc.getObjectList("sliceCatList") ;
790 if (sliceCatState) {
791
792 // Make the master slice set if it doesnt exist
793 if (!sliceSet) {
794 sliceSet = std::make_unique<RooArgSet>();
795 }
796
797 // Prepare comma separated label list for parsing
798 auto catTokens = ROOT::Split(sliceCatState, ",");
799
800 // Loop over all categories provided by (multiple) Slice() arguments
801 unsigned int tokenIndex = 0;
802 for(auto * scat : static_range_cast<RooCategory*>(sliceCatList)) {
803 const char* slabel = tokenIndex >= catTokens.size() ? nullptr : catTokens[tokenIndex++].c_str();
804
805 if (slabel) {
806 // Set the slice position to the value indicated by slabel
807 scat->setLabel(slabel) ;
808 // Add the slice category to the master slice set
809 sliceSet->add(*scat,false) ;
810 }
811 }
812 }
813
814 // Check if we have a projection dataset
815 if (!projData) {
816 coutE(InputArguments) << "RooSimultaneous::plotOn(" << GetName() << ") ERROR: must have a projection dataset for index category" << std::endl ;
817 return frame ;
818 }
819
820 // Make list of variables to be projected
821 RooArgSet projectedVars ;
822 if (sliceSet) {
823 makeProjectionSet(frame->getPlotVar(),frame->getNormVars(),projectedVars,true) ;
824
825 // Take out the sliced variables
826 for (const auto sliceArg : *sliceSet) {
827 RooAbsArg* arg = projectedVars.find(sliceArg->GetName()) ;
828 if (arg) {
829 projectedVars.remove(*arg) ;
830 } else {
831 coutI(Plotting) << "RooAbsReal::plotOn(" << GetName() << ") slice variable "
832 << sliceArg->GetName() << " was not projected anyway" << std::endl ;
833 }
834 }
835 } else if (projSet) {
836 makeProjectionSet(frame->getPlotVar(),projSet,projectedVars,false) ;
837 } else {
838 makeProjectionSet(frame->getPlotVar(),frame->getNormVars(),projectedVars,true) ;
839 }
840
841 bool projIndex(false) ;
842
843 if (!_indexCat.arg().isDerived()) {
844 // *** Error checking for a fundamental index category ***
845 //cout << "RooSim::plotOn: index is fundamental" << std::endl ;
846
847 // Check that the provided projection dataset contains our index variable
848 if (!projData->get()->find(_indexCat.arg().GetName())) {
849 coutE(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") ERROR: Projection over index category "
850 << "requested, but projection data set doesn't contain index category" << std::endl ;
851 return frame ;
852 }
853
854 if (projectedVars.find(_indexCat.arg().GetName())) {
855 projIndex=true ;
856 }
857
858 } else {
859 // *** Error checking for a composite index category ***
860
861 // Determine if any servers of the index category are in the projectedVars
862 RooArgSet projIdxServers ;
863 bool anyServers(false) ;
864 for (const auto server : flattenedCatList()) {
865 if (projectedVars.find(server->GetName())) {
866 anyServers=true ;
867 projIdxServers.add(*server) ;
868 }
869 }
870
871 // Check that the projection dataset contains all the
872 // index category components we're projecting over
873
874 // Determine if all projected servers of the index category are in the projection dataset
875 bool allServers(true) ;
876 std::string missing;
877 for (const auto server : projIdxServers) {
878 if (!projData->get()->find(server->GetName())) {
879 allServers=false ;
880 missing = server->GetName();
881 }
882 }
883
884 if (!allServers) {
885 coutE(Plotting) << "RooSimultaneous::plotOn(" << GetName()
886 << ") ERROR: Projection dataset doesn't contain complete set of index categories to do projection."
887 << "\n\tcategory " << missing << " is missing." << std::endl ;
888 return frame ;
889 }
890
891 if (anyServers) {
892 projIndex = true ;
893 }
894 }
895
896 // Calculate relative weight fractions of components
897 std::unique_ptr<Roo1DTable> wTable( projData->table(_indexCat.arg()) );
898
899 // Clone the index category to be able to cycle through the category states for plotting without
900 // affecting the category state of our instance
901 RooArgSet idxCloneSet;
902 RooArgSet(*_indexCat).snapshot(idxCloneSet, true);
903 auto idxCatClone = static_cast<RooAbsCategoryLValue*>(idxCloneSet.find(_indexCat->GetName()) );
904 assert(idxCatClone);
905
906 // Make list of category columns to exclude from projection data
907 std::unique_ptr<RooArgSet> idxCompSliceSet( idxCatClone->getObservables(frame->getNormVars()) );
908
909 // If we don't project over the index, just do the regular plotOn
910 if (!projIndex) {
911
912 coutI(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") plot on " << frame->getPlotVar()->GetName()
913 << " represents a slice in the index category (" << _indexCat.arg().GetName() << ")" << std::endl ;
914
915 // Reduce projData: take out fitCat (component) columns and entries that don't match selected slice
916 // Construct cut string to only select projection data event that match the current slice
917
918 // Make cut string to exclude rows from projection data
919 if (sliceSet) {
920 for (auto *idxComp : static_range_cast<RooCategory *>(*idxCompSliceSet)) {
921 if (auto* slicedComponent = static_cast<const RooAbsCategory*>(sliceSet->find(*idxComp))) {
922 idxComp->setIndex(slicedComponent->getCurrentIndex(), false);
923 }
924 }
925 }
926 std::string cutString = RooFit::Detail::makeSliceCutString(*idxCompSliceSet);
927
928 // Make temporary projData without RooSim index category components
929 RooArgSet projDataVars(*projData->get()) ;
930 projDataVars.remove(*idxCompSliceSet,true,true) ;
931
932 std::unique_ptr<RooAbsData>
933 projDataTmp(projData->reduce(RooFit::SelectVars(projDataVars), RooFit::Cut(cutString.c_str())));
934
935 // Override normalization and projection dataset
936 RooCmdArg tmp1 =
937 RooFit::Normalization(scaleFactor * wTable->get(idxCatClone->getCurrentLabel()), RooAbsReal::NumEvent);
938 RooCmdArg tmp2 = RooFit::ProjWData(*projDataSet,*projDataTmp) ;
939
940 // WVE -- do not adjust normalization for asymmetry plots
941 RooLinkedList cmdList2(cmdList) ;
942 if (!cmdList.find("Asymmetry")) {
943 replaceOrAdd(cmdList2, tmp1);
944 }
945 replaceOrAdd(cmdList2, tmp2);
946
947 // Plot single component
948 RooPlot* retFrame = getPdf(idxCatClone->getCurrentLabel())->plotOn(frame,cmdList2);
949 return retFrame ;
950 }
951
952 // If we project over the index, plot using a temporary RooAddPdf
953 // using the weights from the data as coefficients
954
955 // Build the list of indexCat components that are sliced
956 idxCompSliceSet->remove(projectedVars,true,true) ;
957
958 // Make a new expression that is the weighted sum of requested components
959 RooArgList pdfCompList ;
960 RooArgList wgtCompList ;
961//RooAbsPdf* pdf ;
962 double sumWeight(0) ;
963 for(auto * proxy : static_range_cast<RooRealProxy*>(_pdfProxyList)) {
964
965 idxCatClone->setLabel(proxy->name()) ;
966
967 // Determine if this component is the current slice (if we slice)
968 bool skip(false) ;
969 for (const auto idxSliceCompArg : *idxCompSliceSet) {
970 const auto idxSliceComp = static_cast<RooAbsCategory*>(idxSliceCompArg);
971 RooAbsCategory* idxComp = static_cast<RooAbsCategory*>(idxCloneSet.find(idxSliceComp->GetName())) ;
972 if (idxComp->getCurrentIndex()!=idxSliceComp->getCurrentIndex()) {
973 skip=true ;
974 break ;
975 }
976 }
977 if (skip) continue ;
978
979 // Instantiate a RRV holding this pdfs weight
980 wgtCompList.addOwned(std::make_unique<RooRealVar>(proxy->name(),"coef",wTable->get(proxy->name())));
981 sumWeight += wTable->getFrac(proxy->name()) ;
982
983 // Add the PDF to list list
984 pdfCompList.add(proxy->arg()) ;
985 }
986
987 TString plotVarName(GetName()) ;
988 RooAddPdf plotVar{plotVarName,"weighted sum of RS components",pdfCompList,wgtCompList};
989
990 // Fix appropriate coefficient normalization in plot function
991 if (!_plotCoefNormSet.empty()) {
992 plotVar.fixAddCoefNormalization(_plotCoefNormSet) ;
993 }
994
995 std::unique_ptr<RooAbsData> projDataTmp;
996 RooArgSet projSetTmp ;
997 if (projData) {
998
999 // Construct cut string to only select projection data event that match the current slice
1000 std::string cutString = RooFit::Detail::makeSliceCutString(*idxCompSliceSet);
1001
1002 // Make temporary projData without RooSim index category components
1003 RooArgSet projDataVars(*projData->get()) ;
1004 RooArgSet idxCatServers;
1005 _indexCat.arg().getObservables(frame->getNormVars(), idxCatServers) ;
1006
1007 projDataVars.remove(idxCatServers,true,true) ;
1008
1009 projDataTmp = std::unique_ptr<RooAbsData>{projData->reduce(RooFit::SelectVars(projDataVars), RooFit::Cut(cutString.c_str()))};
1010
1011
1012
1013 if (projSet) {
1014 projSetTmp.add(*projSet) ;
1015 projSetTmp.remove(idxCatServers,true,true);
1016 }
1017 }
1018
1019
1020 if (_indexCat.arg().isDerived() && !idxCompSliceSet->empty()) {
1021 coutI(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") plot on " << frame->getPlotVar()->GetName()
1022 << " represents a slice in index category components " << *idxCompSliceSet << std::endl ;
1023
1024 RooArgSet idxCompProjSet;
1025 _indexCat.arg().getObservables(frame->getNormVars(), idxCompProjSet) ;
1026 idxCompProjSet.remove(*idxCompSliceSet,true,true) ;
1027 if (!idxCompProjSet.empty()) {
1028 coutI(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") plot on " << frame->getPlotVar()->GetName()
1029 << " averages with data index category components " << idxCompProjSet << std::endl ;
1030 }
1031 } else {
1032 coutI(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") plot on " << frame->getPlotVar()->GetName()
1033 << " averages with data index category (" << _indexCat.arg().GetName() << ")" << std::endl ;
1034 }
1035
1036
1037 // Override normalization and projection dataset
1038 RooLinkedList cmdList2(cmdList) ;
1039
1040 RooCmdArg tmp1 = RooFit::Normalization(scaleFactor*sumWeight,stype) ;
1041 RooCmdArg tmp2 = RooFit::ProjWData(*projDataSet,*projDataTmp) ;
1042 // WVE -- do not adjust normalization for asymmetry plots
1043 if (!cmdList.find("Asymmetry")) {
1044 replaceOrAdd(cmdList2, tmp1);
1045 }
1046 replaceOrAdd(cmdList2, tmp2);
1047
1048 RooPlot* frame2 ;
1049 if (!projSetTmp.empty()) {
1050 // Plot temporary function
1051 RooCmdArg tmp3 = RooFit::Project(projSetTmp) ;
1052 replaceOrAdd(cmdList2, tmp3);
1053 frame2 = plotVar.plotOn(frame,cmdList2) ;
1054 } else {
1055 // Plot temporary function
1056 frame2 = plotVar.plotOn(frame,cmdList2) ;
1057 }
1058
1059 return frame2 ;
1060}
1061
1062
1063////////////////////////////////////////////////////////////////////////////////
1064/// Build the component function of an asymmetry plot (see
1065/// RooAbsReal::plotAsymOn()) for a fixed state of the asymmetry category.
1066///
1067/// When the asymmetry is requested in our own index category, the component for
1068/// a given index state is simply the corresponding pdf. We return a clone of
1069/// that pdf directly instead of a RooSimultaneous with a pinned index, because
1070/// a RooSimultaneous compiles its per-category observables with a category
1071/// prefix. That prefix makes it incompatible with the vectorized evaluation
1072/// backend that averages the asymmetry over the projection data, and would
1073/// otherwise silently yield a flat (zero) asymmetry (see issue #14255). For any
1074/// other asymmetry category we fall back to the generic implementation.
1075
1076std::unique_ptr<RooAbsReal>
1078{
1079 if (&asymCat == &_indexCat.arg()) {
1080 const std::string &label = _indexCat.arg().lookupName(asymCatState.getCurrentIndex());
1081 if (RooAbsPdf *pdf = getPdf(label)) {
1082 return RooHelpers::cloneTreeWithSameParameters(static_cast<RooAbsReal const &>(*pdf));
1083 }
1084 }
1085 return RooAbsReal::createAsymmetryComponent(asymCat, asymCatState);
1086}
1087
1088
1089////////////////////////////////////////////////////////////////////////////////
1090/// Interface function used by test statistics to freeze choice of observables
1091/// for interpretation of fraction coefficients. Needed here because a RooSimultaneous
1092/// works like a RooAddPdf when plotted
1093
1094void RooSimultaneous::selectNormalization(const RooArgSet* normSet, bool /*force*/)
1095{
1097 if (normSet) {
1098 // The index category must not be stored in the set: it is meaningless for
1099 // the coefficient normalization, since it is never an observable of the
1100 // component pdfs (RooAddPdf::selectNormalization() would filter it out
1101 // again anyway). Worse, it is already registered as a value server via
1102 // the index category proxy, and registering the same server a second
1103 // time through this non-propagating set proxy corrupts the reference
1104 // counts of the server's client lists when the set is cleared again.
1105 RooArgSet filteredNormSet{*normSet};
1106 filteredNormSet.remove(_indexCat.arg(), true, true);
1107 _plotCoefNormSet.add(filteredNormSet);
1108 }
1109}
1110
1111
1112////////////////////////////////////////////////////////////////////////////////
1113/// Interface function used by test statistics to freeze choice of range
1114/// for interpretation of fraction coefficients. Needed here because a RooSimultaneous
1115/// works like a RooAddPdf when plotted
1116
1117void RooSimultaneous::selectNormalizationRange(const char* normRange2, bool /*force*/)
1118{
1119 _plotCoefNormRange = RooNameReg::ptr(normRange2) ;
1120}
1121
1122
1123
1124
1125////////////////////////////////////////////////////////////////////////////////
1126
1128 const RooArgSet* auxProto, bool verbose, bool autoBinned, const char* binnedTag) const
1129{
1130 const char* idxCatName = _indexCat.arg().GetName() ;
1131
1132 if (vars.find(idxCatName) && prototype==nullptr
1133 && (auxProto==nullptr || auxProto->empty())
1134 && (autoBinned || (binnedTag && strlen(binnedTag)))) {
1135
1136 // Return special generator config that can also do binned generation for selected states
1137 return new RooSimSplitGenContext(*this,vars,verbose,autoBinned,binnedTag) ;
1138
1139 } else {
1140
1141 // Return regular generator config ;
1142 return genContext(vars,prototype,auxProto,verbose) ;
1143 }
1144}
1145
1146
1147
1148////////////////////////////////////////////////////////////////////////////////
1149/// Return specialized generator context for simultaneous p.d.f.s
1150
1152 const RooArgSet* auxProto, bool verbose) const
1153{
1154 RooArgSet allVars{vars};
1155 if(prototype) allVars.add(*prototype->get());
1156
1157 RooArgSet catsAmongAllVars;
1158 allVars.selectCommon(flattenedCatList(), catsAmongAllVars);
1159
1160 // Not generating index cat: we better error out because it's not clear what
1161 // the user expects here. Does the user want to generate according to the
1162 // currently-selected pdf? Or does the user want to generate global
1163 // observable values according to the union of all category pdfs?
1164 // Print an error and tell the user what to do to explicitly.
1165 if(catsAmongAllVars.empty()) {
1166 coutE(InputArguments) << "RooSimultaneous::generateSimGlobal(" << GetName()
1167 << ") asking to generate without the index category!\n"
1168 << "It's not clear what to do. you probably want to either:\n"
1169 << "\n"
1170 << " 1. Generate according to the currently-selected pdf.\n"
1171 << " Please do this explicitly with:\n"
1172 << " simpdf->getPdf(simpdf->indexCat().getCurrentLabel())->generate(vars, ...)\n"
1173 << "\n"
1174 << " 1. Generate global observable values according to the union of all component pdfs.\n"
1175 << " For this, please use simpdf->generateSimGlobal(vars, ...)\n"
1176 << std::endl;
1177 return nullptr;
1178 }
1179
1180 RooArgSet catsAmongProtoVars;
1181 if(prototype) {
1182 prototype->get()->selectCommon(flattenedCatList(), catsAmongProtoVars);
1183
1184 if(!catsAmongProtoVars.empty() && catsAmongProtoVars.size() != flattenedCatList().size()) {
1185 // Abort if we have only part of the servers
1186 coutE(Plotting) << "RooSimultaneous::genContext: ERROR: prototype must include either all "
1187 << " components of the RooSimultaneous index category or none " << std::endl;
1188 return nullptr;
1189 }
1190 }
1191
1192 return new RooSimGenContext(*this,vars,prototype,auxProto,verbose) ;
1193}
1194
1195
1196
1197
1198////////////////////////////////////////////////////////////////////////////////
1199
1201 const RooArgSet* nset,
1202 double scaleFactor,
1203 bool correctForBinVolume,
1204 bool showProgress) const
1205{
1206 if (RooAbsReal::fillDataHist (hist, nset, scaleFactor,
1207 correctForBinVolume, showProgress) == nullptr)
1208 return nullptr;
1209
1210 const double sum = hist->sumEntries();
1211 if (sum != 0) {
1212 for (int i=0 ; i<hist->numEntries() ; i++) {
1213 hist->set(i, hist->weight(i) / sum, 0.);
1214 }
1215 }
1216
1217 return hist;
1218}
1219
1220
1221
1222
1223////////////////////////////////////////////////////////////////////////////////
1224/// Special generator interface for generation of 'global observables' -- for RooStats tools.
1225///
1226/// \note Why one can't just use RooAbsPdf::generate()? That's because when
1227/// using the regular generate() method, a specific component pdf is selected
1228/// for each generated entry according to the index category value. However,
1229/// global observable values are independent of the current index category,
1230/// which can best be illustrated with the case where a global observable
1231/// corresponds to a nuisance parameter that is relevant for multiple channels.
1232/// So the interpretation of what is an entry in the generated dataset is very
1233/// different, hence the separate function.
1234
1236{
1237 // Generating the index category together with the global observables doesn't make any sense.
1238 RooArgSet catsAmongAllVars;
1239 whatVars.selectCommon(flattenedCatList(), catsAmongAllVars);
1240 if(!catsAmongAllVars.empty()) {
1241 coutE(InputArguments) << "RooSimultaneous::generateSimGlobal(" << GetName()
1242 << ") asking to generate global obserables at the same time as the index category!\n"
1243 << "This doesn't make any sense: global observables are generally not related to a specific channel.\n"
1244 << std::endl;
1245 return nullptr;
1246 }
1247
1248 // Make set with clone of variables (placeholder for output)
1249 RooArgSet globClone;
1250 whatVars.snapshot(globClone);
1251
1252 auto data = std::make_unique<RooDataSet>("gensimglobal","gensimglobal",whatVars);
1253
1254 for (Int_t i=0 ; i<nEvents ; i++) {
1255 for (const auto& nameIdx : indexCat()) {
1256
1257 // Get pdf associated with state from simpdf
1258 RooAbsPdf* pdftmp = getPdf(nameIdx.first);
1259
1260 RooArgSet globtmp;
1261 pdftmp->getObservables(&whatVars, globtmp) ;
1262
1263 // If there are any, generate only global variables defined by the pdf
1264 // associated with this state and transfer values to output placeholder.
1265 if (!globtmp.empty()) {
1266 globClone.assign(*std::unique_ptr<RooDataSet>{pdftmp->generate(globtmp,1)}->get(0)) ;
1267 }
1268 }
1269 data->add(globClone) ;
1270 }
1271
1272 return RooFit::makeOwningPtr(std::move(data));
1273}
1274
1275
1276/// Wraps the components of this RooSimultaneous in RooBinSamplingPdfs.
1277/// \param[in] data The dataset to be used in the eventual fit, used to figure
1278/// out the observables and whether the dataset is binned.
1279/// \param[in] precision Precision argument for all created RooBinSamplingPdfs.
1281
1282 if (precision < 0.) return;
1283
1284 RooArgSet newSamplingPdfs;
1285
1286 for (auto const &item : this->indexCat()) {
1287
1288 auto const &catName = item.first;
1289 auto &pdf = *this->getPdf(catName);
1290
1291 if (auto newSamplingPdf = RooBinSamplingPdf::create(pdf, data, precision)) {
1292 // Set the "ORIGNAME" attribute the indicate to
1293 // RooAbsArg::redirectServers() which pdf should be replaced by this
1294 // RooBinSamplingPdf in the RooSimultaneous.
1295 newSamplingPdf->setAttribute(
1296 (std::string("ORIGNAME:") + pdf.GetName()).c_str());
1297 newSamplingPdfs.addOwned(std::move(newSamplingPdf));
1298 }
1299 }
1300
1301 this->redirectServers(newSamplingPdfs, false, true);
1302 this->addOwnedComponents(std::move(newSamplingPdfs));
1303}
1304
1305
1306/// Wraps the components of this RooSimultaneous in RooBinSamplingPdfs, with a
1307/// different precision parameter for each component.
1308/// \param[in] data The dataset to be used in the eventual fit, used to figure
1309/// out the observables and whether the dataset is binned.
1310/// \param[in] precisions The map that gives the precision argument for each
1311/// component in the RooSimultaneous. The keys are the pdf names. If
1312/// there is no value for a given component, it will not use the bin
1313/// integration. Otherwise, the value has the same meaning than in
1314/// the IntegrateBins() command argument for RooAbsPdf::fitTo().
1315/// \param[in] useCategoryNames If this flag is set, the category names will be
1316/// used to look up the precision in the precisions map instead of
1317/// the pdf names.
1319 std::map<std::string, double> const& precisions,
1320 bool useCategoryNames /*=false*/) {
1321
1322 constexpr double defaultPrecision = -1.;
1323
1324 RooArgSet newSamplingPdfs;
1325
1326 for (auto const &item : this->indexCat()) {
1327
1328 auto const &catName = item.first;
1329 auto &pdf = *this->getPdf(catName);
1330 std::string pdfName = pdf.GetName();
1331
1332 auto found = precisions.find(useCategoryNames ? catName : pdfName);
1333 const double precision =
1334 found != precisions.end() ? found->second : defaultPrecision;
1335 if (precision < 0.)
1336 continue;
1337
1338 if (auto newSamplingPdf = RooBinSamplingPdf::create(pdf, data, precision)) {
1339 // Set the "ORIGNAME" attribute the indicate to
1340 // RooAbsArg::redirectServers() which pdf should be replaced by this
1341 // RooBinSamplingPdf in the RooSimultaneous.
1342 newSamplingPdf->setAttribute(
1343 (std::string("ORIGNAME:") + pdf.GetName()).c_str());
1344 newSamplingPdfs.addOwned(std::move(newSamplingPdf));
1345 }
1346 }
1347
1348 this->redirectServers(newSamplingPdfs, false, true);
1349 this->addOwnedComponents(std::move(newSamplingPdfs));
1350}
1351
1352/// Internal utility function to get a list of all category components for this
1353/// RooSimultaneous. The output contains only the index category if it is a
1354/// RooCategory, or the list of all category components if it is a
1355/// RooSuperCategory.
1357{
1358 // Note that the index category of a RooSimultaneous can only be of type
1359 // RooCategory or RooSuperCategory, because these are the only classes that
1360 // inherit from RooAbsCategoryLValue.
1361 if (auto superCat = dynamic_cast<RooSuperCategory const*>(&_indexCat.arg())) {
1362 return superCat->inputCatList();
1363 }
1364
1365 if(!_indexCatSet) {
1366 _indexCatSet = std::make_unique<RooArgSet>(_indexCat.arg());
1367 }
1368 return *_indexCatSet;
1369}
1370
1371////////////////////////////////////////////////////////////////////////////////
1372/// Check if the index category is in the normalization set `nset`, matching by
1373/// name. For a RooSuperCategory index, it's enough if all its input categories
1374/// are in `nset`, which is the case for the variables of a dataset.
1376{
1377 if (!nset) {
1378 return false;
1379 }
1380 if (nset->contains(_indexCat.arg())) {
1381 return true;
1382 }
1383 RooArgSet const &cats = flattenedCatList();
1384 return std::all_of(cats.begin(), cats.end(), [&](RooAbsArg const *cat) { return nset->contains(*cat); });
1385}
1386
1387////////////////////////////////////////////////////////////////////////////////
1388/// Check if the index category is among the variables `vars`, matching by
1389/// name. For a RooSuperCategory index, any of its input categories counts.
1390///
1391/// If the index category is not among the observables of a fit, this
1392/// RooSimultaneous does not split the data into channels: it acts as a
1393/// "switch" that evaluates to the component selected by the current index
1394/// state, analogous to RooMultiPdf. Fitting infrastructure uses this check to
1395/// decide between the two modes.
1397{
1398 RooArgSet catsAmongVars;
1399 vars.selectCommon(flattenedCatList(), catsAmongVars);
1400 return !catsAmongVars.empty();
1401}
1402
1403namespace {
1404
1405void markObs(RooAbsArg *arg, std::string const &prefix, RooArgSet const &normSet)
1406{
1407 for (RooAbsArg *server : arg->servers()) {
1408 if (server->isFundamental() && normSet.find(*server)) {
1409 markObs(server, prefix, normSet);
1410 server->setAttribute("__obs__");
1411 } else if (!server->isFundamental()) {
1412 markObs(server, prefix, normSet);
1413 }
1414 }
1415}
1416
1417void prefixArgs(RooAbsArg *arg, std::string const &prefix, RooArgSet const &normSet)
1418{
1419 if (!arg->getStringAttribute("__prefix__")) {
1420 arg->SetName((prefix + arg->GetName()).c_str());
1421 arg->setStringAttribute("__prefix__", prefix.c_str());
1422 }
1423 for (RooAbsArg *server : arg->servers()) {
1424 if (server->isFundamental() && normSet.find(*server)) {
1425 prefixArgs(server, prefix, normSet);
1426 } else if (!server->isFundamental()) {
1427 prefixArgs(server, prefix, normSet);
1428 }
1429 }
1430}
1431
1432} // namespace
1433
1434std::unique_ptr<RooAbsArg>
1436{
1437 if (!indexCatIsObservable(normSet)) {
1438 // The index category is not an observable here: the RooSimultaneous
1439 // acts as a plain "switch" that evaluates to the component selected by
1440 // the current index state, analogous to RooMultiPdf. The channel
1441 // observables are then the same as the ones of this pdf, so the
1442 // channel-splitting compilation below (which renames the per-channel
1443 // observables so they can be filled from split datasets) must not be
1444 // used. Compile like an ordinary self-normalized pdf instead.
1445 return RooAbsPdf::compileForNormSet(normSet, ctx);
1446 }
1447
1448 std::unique_ptr<RooSimultaneous> newSimPdf{static_cast<RooSimultaneous *>(this->Clone())};
1449
1450 const char *rangeName = this->getStringAttribute("RangeName");
1451 bool splitRange = this->getAttribute("SplitRange");
1452
1453 RooArgSet newPdfs;
1454 std::vector<std::string> catNames;
1455
1456 for (auto *proxy : static_range_cast<RooRealProxy *>(newSimPdf->_pdfProxyList)) {
1457 catNames.emplace_back(proxy->GetName());
1458 std::string const &catName = catNames.back();
1459 const std::string prefix = "_" + catName + "_";
1460
1461 const std::string origname = proxy->arg().GetName();
1462
1463 auto pdfClone = RooHelpers::cloneTreeWithSameParameters(static_cast<RooAbsPdf const &>(proxy->arg()), &normSet);
1464
1465 markObs(pdfClone.get(), prefix, normSet);
1466
1467 std::unique_ptr<RooArgSet> pdfNormSet{
1468 std::unique_ptr<RooArgSet>(pdfClone->getVariables())->selectByAttrib("__obs__", true)};
1469 std::unique_ptr<RooArgSet> condVarSet{
1470 std::unique_ptr<RooArgSet>(pdfClone->getVariables())->selectByAttrib("__conditional__", true)};
1471
1472 pdfNormSet->remove(*condVarSet, true, true);
1473
1474 if (rangeName) {
1475 pdfClone->setNormRange(RooHelpers::getRangeNameForSimComponent(rangeName, splitRange, catName).c_str());
1476 }
1477
1478 RooFit::Detail::CompileContext pdfContext{*pdfNormSet};
1479 pdfContext.setLikelihoodMode(ctx.likelihoodMode());
1480 auto *pdfFinal = pdfContext.compile(*pdfClone, *newSimPdf, *pdfNormSet);
1481
1482 // The observables of the compiled computation graph are clones of the
1483 // ones in `pdfNormSet`, and only the clones are prefixed below. That's
1484 // why we have to translate the normalization set to the compiled args
1485 // before using it any further.
1486 RooArgSet compiledPdfNormSet = pdfContext.mapToCompiled(*pdfNormSet);
1487
1488 // We can only prefix the observables after everything related the
1489 // compiling of the compute graph for the normalization set is done. This
1490 // is because of a subtlety in conditional RooProdPdfs, which stores the
1491 // normalization sets for the individual pdfs in RooArgSets that are
1492 // disconnected from the computation graph, so we have no control over
1493 // them. An alternative would be to use recursive server re-direction,
1494 // but this has more performance overhead.
1495 prefixArgs(pdfFinal, prefix, normSet);
1496
1497 // This has to be done with the observables of the compiled graph, which
1498 // are prefixed at this point. Otherwise, the RooAddPdf components don't
1499 // find their coefficient normalization observables and silently keep the
1500 // default "automatic" interpretation of the coefficients, which results
1501 // in wrong yields in ranged fits (GitHub issue #23444).
1502 pdfFinal->fixAddCoefNormalization(compiledPdfNormSet, false);
1503
1504 pdfClone->SetName((std::string("_") + pdfClone->GetName()).c_str());
1505 pdfFinal->addOwnedComponents(std::move(pdfClone));
1506
1507 pdfFinal->setAttribute(("ORIGNAME:" + origname).c_str());
1508 newPdfs.add(*pdfFinal);
1509
1510 // We will remove the old pdf server because we will fill the new ones by
1511 // hand via the creation of new proxies.
1512 newSimPdf->removeServer(const_cast<RooAbsReal &>(proxy->arg()), true);
1513 }
1514
1515 // Replace pdfs with compiled pdfs. Don't use RooAbsArg::redirectServers()
1516 // here, because it doesn't support replacing two servers with the same name
1517 // (it can happen in a RooSimultaneous that two pdfs have the same name).
1518
1519 // First delete old proxies (we have already removed the servers before).
1520 newSimPdf->_pdfProxyList.Delete();
1521
1522 // Recreate the _pdfProxyList with the compiled pdfs
1523 for (std::size_t i = 0; i < newPdfs.size(); ++i) {
1524 const char *label = catNames[i].c_str();
1525 newSimPdf->_pdfProxyList.Add(
1526 new RooRealProxy(label, label, newSimPdf.get(), *static_cast<RooAbsReal *>(newPdfs[i])));
1527 }
1528
1529 ctx.compileServers(*newSimPdf, normSet); // to trigger compiling also the index category
1530
1531 return newSimPdf;
1532}
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 coutE(a)
RooTemplateProxy< RooAbsReal > RooRealProxy
Compatibility typedef replacing the old RooRealProxy class.
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:142
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'.
RooFit::OwningPtr< RooArgSet > getObservables(const RooArgSet &set, bool valueOnly=true) const
Given a set of possible observables, return the observables that this PDF depends on.
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.
virtual bool isDerived() const
Does value or shape of this arg depend on any other arg?
Definition RooAbsArg.h:97
bool getAttribute(const Text_t *name) const
Check if a named attribute is set. By default, all attributes are unset.
RooFit::OwningPtr< RooArgSet > getVariables(bool stripDisconnected=true) const
Return RooArgSet with all variables (tree leaf nodes of expression tree)
TObject * Clone(const char *newname=nullptr) const override
Make a clone of an object using the Streamer facility.
Definition RooAbsArg.h:88
virtual bool isFundamental() const
Is this object a fundamental type that can be added to a dataset? Fundamental-type subclasses overrid...
Definition RooAbsArg.h:175
Abstract base class for objects that represent a discrete value that can be set from the outside,...
virtual bool setLabel(const char *label, bool printError=true)=0
Change category state by specifying a state name.
A space to attach TBranches.
virtual value_type getCurrentIndex() const
Return index number of current state.
virtual const char * getCurrentLabel() const
Return label string of current state.
const std::string & lookupName(value_type index) const
Get the name corresponding to the given index.
std::map< std::string, value_type >::const_iterator begin() const
Iterator for category state names. Points to pairs of index and name.
std::size_t size() const
Number of states defined.
bool contains(const char *name) const
Check if collection contains an argument with a specific name.
virtual bool remove(const RooAbsArg &var, bool silent=false, bool matchByNameOnly=false)
Remove the specified argument from our list.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
TObject * Clone(const char *newname=nullptr) const override
Make a clone of an object using the Streamer facility.
const_iterator end() const
void assign(const RooAbsCollection &other) const
Sets the value, cache and constant attribute of any argument in our set that also appears in the othe...
Storage_t::size_type size() const
RooAbsArg * first() const
virtual bool addOwned(RooAbsArg &var, bool silent=false)
Add an argument and transfer the ownership to the collection.
const_iterator begin() const
RooAbsArg * find(const char *name) const
Find object with given name in list.
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:55
virtual const RooArgSet * get() const
Definition RooAbsData.h:99
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
std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const override
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
RooFit::OwningPtr< RooDataSet > generate(const RooArgSet &whatVars, Int_t nEvents, const RooCmdArg &arg1, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={})
See RooAbsPdf::generate(const RooArgSet&,const RooCmdArg&,const RooCmdArg&,const RooCmdArg&,...
Definition RooAbsPdf.h:49
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
const RooArgSet * get(Int_t index) const override
Return RooArgSet with coordinates of event 'index'.
void compileServers(RooAbsArg &arg, RooArgSet const &normSet)
Collection class for internal use, storing a collection of RooAbsArg pointers in a doubly linked list...
bool Replace(const TObject *oldArg, const TObject *newArg)
Replace object 'oldArg' in collection with new object 'newArg'.
TObject * find(const char *name) const
Return pointer to object with given name in collection.
virtual void Add(TObject *arg)
TObject * FindObject(const char *name) const override
Return pointer to object with given name.
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...
bool indexCatIsInNormSet(RooArgSet const *nset) const
Check if the index category is in the normalization set nset, matching by name.
std::unique_ptr< RooAbsReal > createExpectedEventsFunc(const RooArgSet *nset) const override
Expected events function for the new evaluation backends: the sum over all components,...
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.
bool indexCatIsObservable(RooArgSet const &vars) const
Check if the index category is among the variables vars, matching by name.
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...
const char * c_str() const
Joins several RooAbsCategoryLValue objects into a single category.
bool setLabel(const char *label, bool printError=true) override
Set the value of the super category by specifying the state name.
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:137
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:73
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