Logo ROOT  
Reference Guide
RooAbsOptTestStatistic.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 RooAbsOptTestStatistic.cxx
19\class RooAbsOptTestStatistic
20\ingroup Roofitcore
21
22RooAbsOptTestStatistic is the abstract base class for test
23statistics objects that evaluate a function or PDF at each point of a given
24dataset. This class provides generic optimizations, such as
25caching and precalculation of constant terms that can be made for
26all such quantities.
27
28Implementations should define evaluatePartition(), which calculates the
29value of a (sub)range of the dataset and optionally combinedValue(),
30which combines the values calculated for each partition. If combinedValue()
31is not overloaded, the default implementation will add the partition results
32to obtain the combined result.
33
34Support for calculation in partitions is needed to allow multi-core
35parallelized calculation of test statistics.
36**/
37
38#include "Riostream.h"
39#include "TClass.h"
40#include <string.h>
41
42
44#include "RooMsgService.h"
45#include "RooAbsPdf.h"
46#include "RooAbsData.h"
47#include "RooDataHist.h"
48#include "RooArgSet.h"
49#include "RooRealVar.h"
50#include "RooErrorHandler.h"
51#include "RooGlobalFunc.h"
52#include "RooBinning.h"
53#include "RooAbsDataStore.h"
54#include "RooCategory.h"
55#include "RooDataSet.h"
56#include "RooProdPdf.h"
57#include "RooAddPdf.h"
58#include "RooProduct.h"
59#include "RooRealSumPdf.h"
60#include "RooTrace.h"
61#include "RooVectorDataStore.h"
62#include "RooBinSamplingPdf.h"
63
64using namespace std;
65
67;
68
69
70////////////////////////////////////////////////////////////////////////////////
71/// Default Constructor
72
74{
75 // Initialize all non-persisted data members
76
77 _funcObsSet = 0 ;
78 _funcCloneSet = 0 ;
79 _funcClone = 0 ;
80
81 _normSet = 0 ;
82 _projDeps = 0 ;
83
84 _origFunc = 0 ;
85 _origData = 0 ;
86
87 _ownData = true ;
88 _sealed = false ;
89 _optimized = false ;
90}
91
92
93
94////////////////////////////////////////////////////////////////////////////////
95/// Create a test statistic, and optimise its calculation.
96/// \param[in] name Name of the instance.
97/// \param[in] title Title (for e.g. plotting).
98/// \param[in] real Function to evaluate.
99/// \param[in] indata Dataset for which to compute test statistic.
100/// \param[in] projDeps A set of projected observables.
101/// \param[in] cfg the statistic configuration
102///
103/// cfg contains:
104/// - rangeName If not null, only events in the dataset inside the range will be used in the test
105/// statistic calculation.
106/// - addCoefRangeName If not null, all RooAddPdf components of `real` will be
107/// instructed to fix their fraction definitions to the given named range.
108/// - nCPU If > 1, the test statistic calculation will be parallelised over multiple processes. By default, the data
109/// is split with 'bulk' partitioning (each process calculates a contiguous block of fraction 1/nCPU
110/// of the data). For binned data, this approach may be suboptimal as the number of bins with >0 entries
111/// in each processing block may vary greatly; thereby distributing the workload rather unevenly.
112/// - interleave Strategy how to distribute events among workers. If an interleave partitioning strategy is used where each partition
113/// i takes all bins for which (ibin % ncpu == i), an even distribution of work is more likely.
114/// - splitCutRange If true, a different rangeName constructed as `rangeName_{catName}` will be used
115/// as range definition for each index state of a RooSimultaneous.
116/// - cloneInputData Not used. Data is always cloned.
117/// - integrateOverBinsPrecision If > 0, PDF in binned fits are integrated over the bins. This sets the precision. If = 0,
118/// only unbinned PDFs fit to RooDataHist are integrated. If < 0, PDFs are never integrated.
120 RooAbsData& indata, const RooArgSet& projDeps,
122 RooAbsTestStatistic(name,title,real,indata,projDeps,cfg),
123 _projDeps(0),
124 _sealed(false),
125 _optimized(false),
126 _integrateBinsPrecision(cfg.integrateOverBinsPrecision)
127{
128 // Don't do a thing in master mode
129
130 if (operMode()!=Slave) {
131 _funcObsSet = 0 ;
132 _funcCloneSet = 0 ;
133 _funcClone = 0 ;
134 _normSet = 0 ;
135 _projDeps = 0 ;
136 _origFunc = 0 ;
137 _origData = 0 ;
138 _ownData = false ;
139 _sealed = false ;
140 return ;
141 }
142
143 _origFunc = 0 ; //other._origFunc ;
144 _origData = 0 ; // other._origData ;
145
146 initSlave(real, indata, projDeps, _rangeName.c_str(), _addCoefRangeName.c_str()) ;
147}
148
149////////////////////////////////////////////////////////////////////////////////
150/// Copy constructor
151
153 RooAbsTestStatistic(other,name), _sealed(other._sealed), _sealNotice(other._sealNotice), _optimized(false),
154 _integrateBinsPrecision(other._integrateBinsPrecision)
155{
156 // Don't do a thing in master mode
157 if (operMode()!=Slave) {
158
159 _funcObsSet = 0 ;
160 _funcCloneSet = 0 ;
161 _funcClone = 0 ;
162 _normSet = other._normSet ? ((RooArgSet*) other._normSet->snapshot()) : 0 ;
163 _projDeps = 0 ;
164 _origFunc = 0 ;
165 _origData = 0 ;
166 _ownData = false ;
167 return ;
168 }
169
170 _origFunc = 0 ; //other._origFunc ;
171 _origData = 0 ; // other._origData ;
172 _projDeps = 0 ;
173
174 initSlave(*other._funcClone,*other._dataClone,other._projDeps?*other._projDeps:RooArgSet(),other._rangeName.c_str(),other._addCoefRangeName.c_str()) ;
175}
176
177
178
179////////////////////////////////////////////////////////////////////////////////
180
181void RooAbsOptTestStatistic::initSlave(RooAbsReal& real, RooAbsData& indata, const RooArgSet& projDeps, const char* rangeName,
182 const char* addCoefRangeName) {
183 // ******************************************************************
184 // *** PART 1 *** Clone incoming pdf, attach to each other *
185 // ******************************************************************
186
187 // Clone FUNC
188 _funcClone = static_cast<RooAbsReal*>(real.cloneTree());
189 _funcCloneSet = 0 ;
190
191 // Attach FUNC to data set
193
194 if (_funcClone->getAttribute("BinnedLikelihood")) {
195 _funcClone->setAttribute("BinnedLikelihoodActive") ;
196 }
197
198 // Reattach FUNC to original parameters
199 RooArgSet* origParams = (RooArgSet*) real.getParameters(indata) ;
201
202 // Mark all projected dependents as such
203 if (projDeps.getSize()>0) {
204 RooArgSet *projDataDeps = (RooArgSet*) _funcObsSet->selectCommon(projDeps) ;
205 projDataDeps->setAttribAll("projectedDependent") ;
206 delete projDataDeps ;
207 }
208
209 // If PDF is a RooProdPdf (with possible constraint terms)
210 // analyze pdf for actual parameters (i.e those in unconnected constraint terms should be
211 // ignored as here so that the test statistic will not be recalculated if those
212 // are changed
213 RooProdPdf* pdfWithCons = dynamic_cast<RooProdPdf*>(_funcClone) ;
214 if (pdfWithCons) {
215
216 RooArgSet* connPars = pdfWithCons->getConnectedParameters(*indata.get()) ;
217 // Add connected parameters as servers
219 _paramSet.add(*connPars) ;
220 delete connPars ;
221
222 } else {
223 // Add parameters as servers
224 _paramSet.add(*origParams) ;
225 }
226
227
228 delete origParams ;
229
230 // Store normalization set
231 _normSet = (RooArgSet*) indata.get()->snapshot(false) ;
232
233 // Expand list of observables with any observables used in parameterized ranges.
234 // This NEEDS to be a counting loop since we are inserting during the loop.
235 for (std::size_t i = 0; i < _funcObsSet->size(); ++i) {
236 auto realDepRLV = dynamic_cast<const RooAbsRealLValue*>((*_funcObsSet)[i]);
237 if (realDepRLV && realDepRLV->isDerived()) {
238 RooArgSet tmp2;
239 realDepRLV->leafNodeServerList(&tmp2, 0, true);
240 _funcObsSet->add(tmp2,true);
241 }
242 }
243
244
245
246 // ******************************************************************
247 // *** PART 2 *** Clone and adjust incoming data, attach to PDF *
248 // ******************************************************************
249
250 // Check if the fit ranges of the dependents in the data and in the FUNC are consistent
251 const RooArgSet* dataDepSet = indata.get() ;
252 for (const auto arg : *_funcObsSet) {
253
254 // Check that both dataset and function argument are of type RooRealVar
255 RooRealVar* realReal = dynamic_cast<RooRealVar*>(arg) ;
256 if (!realReal) continue ;
257 RooRealVar* datReal = dynamic_cast<RooRealVar*>(dataDepSet->find(realReal->GetName())) ;
258 if (!datReal) continue ;
259
260 // Check that range of observables in pdf is equal or contained in range of observables in data
261
262 if (!realReal->getBinning().lowBoundFunc() && realReal->getMin()<(datReal->getMin()-1e-6)) {
263 coutE(InputArguments) << "RooAbsOptTestStatistic: ERROR minimum of FUNC observable " << arg->GetName()
264 << "(" << realReal->getMin() << ") is smaller than that of "
265 << arg->GetName() << " in the dataset (" << datReal->getMin() << ")" << endl ;
267 return ;
268 }
269
270 if (!realReal->getBinning().highBoundFunc() && realReal->getMax()>(datReal->getMax()+1e-6)) {
271 coutE(InputArguments) << "RooAbsOptTestStatistic: ERROR maximum of FUNC observable " << arg->GetName()
272 << " is larger than that of " << arg->GetName() << " in the dataset" << endl ;
274 return ;
275 }
276 }
277
278 // Copy data and strip entries lost by adjusted fit range, _dataClone ranges will be copied from realDepSet ranges
279 if (rangeName && strlen(rangeName)) {
281 // cout << "RooAbsOptTestStatistic: reducing dataset to fit in range named " << rangeName << " resulting dataset has " << _dataClone->sumEntries() << " events" << endl ;
282 } else {
283 _dataClone = (RooAbsData*) indata.Clone() ;
284 }
285 _ownData = true ;
286
287
288 // ******************************************************************
289 // *** PART 3 *** Make adjustments for fit ranges, if specified *
290 // ******************************************************************
291
292 std::unique_ptr<RooArgSet> origObsSet( real.getObservables(indata) );
293 RooArgSet* dataObsSet = (RooArgSet*) _dataClone->get() ;
294 if (rangeName && strlen(rangeName)) {
295 cxcoutI(Fitting) << "RooAbsOptTestStatistic::ctor(" << GetName() << ") constructing test statistic for sub-range named " << rangeName << endl ;
296
297 bool observablesKnowRange = false;
298 // Adjust FUNC normalization ranges to requested fitRange, store original ranges for RooAddPdf coefficient interpretation
299 for (const auto arg : *_funcObsSet) {
300
301 RooRealVar* realObs = dynamic_cast<RooRealVar*>(arg) ;
302 if (realObs) {
303
304 auto transferRangeAndBinning = [&](RooRealVar & toVar, const char* toName, const char* fromName) {
305 toVar.setRange(toName, realObs->getMin(fromName),realObs->getMax(fromName));
306 // If the realObs also has a binning with a name matching the
307 // rangeName, it will be set as the default binning. If `fromName` is
308 // a nullptr to signify taking the default binning from `realObs`,
309 // don't check if it exists as there is always a default binning.
310 if(!fromName || realObs->hasBinning(fromName)) {
311 toVar.setBinning(realObs->getBinning(fromName), toName);
312 }
313 };
314
315 observablesKnowRange |= realObs->hasRange(rangeName);
316
317 // If no explicit range is given for RooAddPdf coefficients, create explicit named range equivalent to original observables range
318 if (!(addCoefRangeName && strlen(addCoefRangeName))) {
319 transferRangeAndBinning(*realObs, Form("NormalizationRangeFor%s",rangeName), nullptr);
320 }
321
322 // Adjust range of function observable to those of given named range
323 transferRangeAndBinning(*realObs, nullptr, rangeName);
324
325 // Adjust range of data observable to those of given named range
326 RooRealVar* dataObs = (RooRealVar*) dataObsSet->find(realObs->GetName()) ;
327 transferRangeAndBinning(*dataObs, nullptr, rangeName);
328
329 // Keep track of list of fit ranges in string attribute fit range of original p.d.f.
330 if (!_splitRange) {
331 const std::string fitRangeName = std::string("fit_") + GetName();
332 const char* origAttrib = real.getStringAttribute("fitrange") ;
333 std::string newAttr = origAttrib ? origAttrib : "";
334
335 if (newAttr.find(fitRangeName) == std::string::npos) {
336 newAttr += (newAttr.empty() ? "" : ",") + fitRangeName;
337 }
338 real.setStringAttribute("fitrange", newAttr.c_str());
339 RooRealVar* origObs = (RooRealVar*) origObsSet->find(arg->GetName()) ;
340 if (origObs) {
341 transferRangeAndBinning(*origObs, fitRangeName.c_str(), rangeName);
342 }
343 }
344 }
345 }
346
347 if (!observablesKnowRange)
348 coutW(Fitting) << "None of the fit observables seem to know the range '" << rangeName << "'. This means that the full range will be used." << std::endl;
349 }
350
351
352 // ******************************************************************
353 // *** PART 3.2 *** Binned fits *
354 // ******************************************************************
355
357
358
359 // Fix RooAddPdf coefficients to original normalization range
360 if (rangeName && strlen(rangeName)) {
361
362 // WVE Remove projected dependents from normalization
364
365 if (addCoefRangeName && strlen(addCoefRangeName)) {
366 cxcoutI(Fitting) << "RooAbsOptTestStatistic::ctor(" << GetName()
367 << ") fixing interpretation of coefficients of any RooAddPdf component to range " << addCoefRangeName << endl ;
368 _funcClone->fixAddCoefRange(addCoefRangeName,false) ;
369 } else {
370 cxcoutI(Fitting) << "RooAbsOptTestStatistic::ctor(" << GetName()
371 << ") fixing interpretation of coefficients of any RooAddPdf to full domain of observables " << endl ;
372 _funcClone->fixAddCoefRange(Form("NormalizationRangeFor%s",rangeName),false) ;
373 }
374 }
375
376
377 // This is deferred from part 2 - but must happen after part 3 - otherwise invalid bins cannot be properly marked in cacheValidEntries
380
381
382
383
384 // *********************************************************************
385 // *** PART 4 *** Adjust normalization range for projected observables *
386 // *********************************************************************
387
388 // Remove projected dependents from normalization set
389 if (projDeps.getSize()>0) {
390
391 _projDeps = (RooArgSet*) projDeps.snapshot(false) ;
392
393 //RooArgSet* tobedel = (RooArgSet*) _normSet->selectCommon(*_projDeps) ;
394 _normSet->remove(*_projDeps,true,true) ;
395
396 // Mark all projected dependents as such
398 projDataDeps->setAttribAll("projectedDependent") ;
399 delete projDataDeps ;
400 }
401
402
403 coutI(Optimization) << "RooAbsOptTestStatistic::ctor(" << GetName() << ") optimizing internal clone of p.d.f for likelihood evaluation."
404 << "Lazy evaluation and associated change tracking will disabled for all nodes that depend on observables" << endl ;
405
406
407 // *********************************************************************
408 // *** PART 4 *** Finalization and activation of optimization *
409 // *********************************************************************
410
411 // Redirect pointers of base class to clone
412 _func = _funcClone ;
413 _data = _dataClone ;
414
416
418
419 // It would be unusual if the global observables are used in the likelihood
420 // outside of the constraint terms, but if they are we have to be consistent
421 // and also redirect them to the snapshots in the dataset if appropriate.
424 }
425
426}
427
428
429////////////////////////////////////////////////////////////////////////////////
430/// Destructor
431
433{
434 if (operMode()==Slave) {
435 delete _funcClone ;
436 delete _funcObsSet ;
437 if (_projDeps) {
438 delete _projDeps ;
439 }
440 if (_ownData) {
441 delete _dataClone ;
442 }
443 }
444 delete _normSet ;
445}
446
447
448
449////////////////////////////////////////////////////////////////////////////////
450/// Method to combined test statistic results calculated into partitions into
451/// the global result. This default implementation adds the partition return
452/// values
453
455{
456 // Default implementation returns sum of components
457 double sum(0), carry(0);
458 for (Int_t i = 0; i < n; ++i) {
459 double y = array[i]->getValV();
460 carry += reinterpret_cast<RooAbsOptTestStatistic*>(array[i])->getCarry();
461 y -= carry;
462 const double t = sum + y;
463 carry = (t - sum) - y;
464 sum = t;
465 }
466 _evalCarry = carry;
467 return sum ;
468}
469
470
471
472////////////////////////////////////////////////////////////////////////////////
473/// Catch server redirect calls and forward to internal clone of function
474
475bool RooAbsOptTestStatistic::redirectServersHook(const RooAbsCollection& newServerList, bool mustReplaceAll, bool nameChange, bool isRecursive)
476{
477 RooAbsTestStatistic::redirectServersHook(newServerList,mustReplaceAll,nameChange,isRecursive) ;
478 if (operMode()!=Slave) return false ;
479 bool ret = _funcClone->recursiveRedirectServers(newServerList,false,nameChange) ;
480 return ret ;
481}
482
483
484
485////////////////////////////////////////////////////////////////////////////////
486/// Catch print hook function and forward to function clone
487
489{
491 if (operMode()!=Slave) return ;
492 TString indent2(indent) ;
493 indent2 += "opt >>" ;
494 _funcClone->printCompactTree(os,indent2.Data()) ;
495 os << indent2 << " dataset clone = " << _dataClone << " first obs = " << _dataClone->get()->first() << endl ;
496}
497
498
499
500////////////////////////////////////////////////////////////////////////////////
501/// Driver function to propagate constant term optimizations in test statistic.
502/// If code Activate is sent, constant term optimization will be executed.
503/// If code Deactivate is sent, any existing constant term optimizations will
504/// be abandoned. If codes ConfigChange or ValueChange are sent, any existing
505/// constant term optimizations will be redone.
506
508{
509 // cout << "ROATS::constOpt(" << GetName() << ") funcClone structure dump BEFORE const-opt" << endl ;
510 // _funcClone->Print("t") ;
511
512 RooAbsTestStatistic::constOptimizeTestStatistic(opcode,doAlsoTrackingOpt);
513 if (operMode()!=Slave) return ;
514
515 if (_dataClone->hasFilledCache() && _dataClone->store()->cacheOwner()!=this) {
516 if (opcode==Activate) {
517 cxcoutW(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
518 << ") dataset cache is owned by another object, no constant term optimization can be applied" << endl ;
519 }
520 return ;
521 }
522
523 if (!allowFunctionCache()) {
524 if (opcode==Activate) {
525 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
526 << ") function caching prohibited by test statistic, no constant term optimization is applied" << endl ;
527 }
528 return ;
529 }
530
531 if (_dataClone->hasFilledCache() && opcode==Activate) {
532 opcode=ValueChange ;
533 }
534
535 switch(opcode) {
536 case Activate:
537 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
538 << ") optimizing evaluation of test statistic by finding all nodes in p.d.f that depend exclusively"
539 << " on observables and constant parameters and precalculating their values" << endl ;
540 optimizeConstantTerms(true,doAlsoTrackingOpt) ;
541 break ;
542
543 case DeActivate:
544 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
545 << ") deactivating optimization of constant terms in test statistic" << endl ;
546 optimizeConstantTerms(false) ;
547 break ;
548
549 case ConfigChange:
550 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
551 << ") one ore more parameter were changed from constant to floating or vice versa, "
552 << "re-evaluating constant term optimization" << endl ;
553 optimizeConstantTerms(false) ;
554 optimizeConstantTerms(true,doAlsoTrackingOpt) ;
555 break ;
556
557 case ValueChange:
558 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
559 << ") the value of one ore more constant parameter were changed re-evaluating constant term optimization" << endl ;
560 // Request a forcible cache update of all cached nodes
562
563 break ;
564 }
565
566// cout << "ROATS::constOpt(" << GetName() << ") funcClone structure dump AFTER const-opt" << endl ;
567// _funcClone->Print("t") ;
568}
569
570
571
572////////////////////////////////////////////////////////////////////////////////
573/// This method changes the value caching logic for all nodes that depends on any of the observables
574/// as defined by the given dataset. When evaluating a test statistic constructed from the RooAbsReal
575/// with a dataset the observables are guaranteed to change with every call, thus there is no point
576/// in tracking these changes which result in a net overhead. Thus for observable-dependent nodes,
577/// the evaluation mechanism is changed from being dependent on a 'valueDirty' flag to guaranteed evaluation.
578/// On the dataset side, the observables objects are modified to no longer send valueDirty messages
579/// to their client
580
582{
583// cout << "RooAbsOptTestStatistic::optimizeCaching(" << GetName() << "," << this << ")" << endl ;
584
585 // Trigger create of all object caches now in nodes that have deferred object creation
586 // so that cache contents can be processed immediately
588
589 // Set value caching mode for all nodes that depend on any of the observables to ADirty
591
592 // Disable propagation of dirty state flags for observables
593 _dataClone->setDirtyProp(false) ;
594
595 // Disable reading of observables that are not used
597}
598
599
600
601////////////////////////////////////////////////////////////////////////////////
602/// Driver function to activate global constant term optimization.
603/// If activated, constant terms are found and cached with the dataset.
604/// The operation mode of cached nodes is set to AClean meaning that
605/// their getVal() call will never result in an evaluate call.
606/// Finally the branches in the dataset that correspond to observables
607/// that are exclusively used in constant terms are disabled as
608/// they serve no more purpose
609
610void RooAbsOptTestStatistic::optimizeConstantTerms(bool activate, bool applyTrackingOpt)
611{
612 if(activate) {
613
614 if (_optimized) {
615 return ;
616 }
617
618 // Trigger create of all object caches now in nodes that have deferred object creation
619 // so that cache contents can be processed immediately
621
622
623 // WVE - Patch to allow customization of optimization level per component pdf
624 if (_funcClone->getAttribute("NoOptimizeLevel1")) {
625 coutI(Minimization) << " Optimization customization: Level-1 constant-term optimization prohibited by attribute NoOptimizeLevel1 set on top-level pdf "
626 << _funcClone->ClassName() << "::" << _funcClone->GetName() << endl ;
627 return ;
628 }
629 if (_funcClone->getAttribute("NoOptimizeLevel2")) {
630 coutI(Minimization) << " Optimization customization: Level-2 constant-term optimization prohibited by attribute NoOptimizeLevel2 set on top-level pdf "
631 << _funcClone->ClassName() << "::" << _funcClone->GetName() << endl ;
632 applyTrackingOpt=false ;
633 }
634
635 // Apply tracking optimization here. Default strategy is to track components
636 // of RooAddPdfs and RooRealSumPdfs. If these components are a RooProdPdf
637 // or a RooProduct respectively, track the components of these products instead
638 // of the product term
639 RooArgSet trackNodes ;
640
641
642 // Add safety check here - applyTrackingOpt will only be applied if present
643 // dataset is constructed in terms of a RooVectorDataStore
644 if (applyTrackingOpt) {
645 if (!dynamic_cast<RooVectorDataStore*>(_dataClone->store())) {
646 coutW(Optimization) << "RooAbsOptTestStatistic::optimizeConstantTerms(" << GetName()
647 << ") WARNING Cache-and-track optimization (Optimize level 2) is only available for datasets"
648 << " implement in terms of RooVectorDataStore - ignoring this option for current dataset" << endl ;
649 applyTrackingOpt = false ;
650 }
651 }
652
653 if (applyTrackingOpt) {
654 RooArgSet branches ;
655 _funcClone->branchNodeServerList(&branches) ;
656 for (auto arg : branches) {
657 arg->setCacheAndTrackHints(trackNodes);
658 }
659 // Do not set CacheAndTrack on constant expressions
660 RooArgSet* constNodes = (RooArgSet*) trackNodes.selectByAttrib("Constant",true) ;
661 trackNodes.remove(*constNodes) ;
662 delete constNodes ;
663
664 // Set CacheAndTrack flag on all remaining nodes
665 trackNodes.setAttribAll("CacheAndTrack",true) ;
666 }
667
668 // Find all nodes that depend exclusively on constant parameters
670
672
673 // Cache constant nodes with dataset - also cache entries corresponding to zero-weights in data when using BinnedLikelihood
674 _dataClone->cacheArgs(this,_cachedNodes,_normSet,!_funcClone->getAttribute("BinnedLikelihood")) ;
675
676 // Put all cached nodes in AClean value caching mode so that their evaluate() is never called
677 for (auto cacheArg : _cachedNodes) {
678 cacheArg->setOperMode(RooAbsArg::AClean) ;
679 }
680
681 RooArgSet* constNodes = (RooArgSet*) _cachedNodes.selectByAttrib("ConstantExpressionCached",true) ;
682 RooArgSet actualTrackNodes(_cachedNodes) ;
683 actualTrackNodes.remove(*constNodes) ;
684 if (constNodes->getSize()>0) {
685 if (constNodes->getSize()<20) {
686 coutI(Minimization) << " The following expressions have been identified as constant and will be precalculated and cached: " << *constNodes << endl ;
687 } else {
688 coutI(Minimization) << " A total of " << constNodes->getSize() << " expressions have been identified as constant and will be precalculated and cached." << endl ;
689 }
690 }
691 if (actualTrackNodes.getSize()>0) {
692 if (actualTrackNodes.getSize()<20) {
693 coutI(Minimization) << " The following expressions will be evaluated in cache-and-track mode: " << actualTrackNodes << endl ;
694 } else {
695 coutI(Minimization) << " A total of " << constNodes->getSize() << " expressions will be evaluated in cache-and-track-mode." << endl ;
696 }
697 }
698 delete constNodes ;
699
700 // Disable reading of observables that are no longer used
702
703 _optimized = true ;
704
705 } else {
706
707 // Delete the cache
709
710 // Reactivate all tree branches
712
713 // Reset all nodes to ADirty
715
716 // Disable propagation of dirty state flags for observables
717 _dataClone->setDirtyProp(false) ;
718
720
721
722 _optimized = false ;
723 }
724}
725
726
727
728////////////////////////////////////////////////////////////////////////////////
729/// Change dataset that is used to given one. If cloneData is true, a clone of
730/// in the input dataset is made. If the test statistic was constructed with
731/// a range specification on the data, the cloneData argument is ignored and
732/// the data is always cloned.
733bool RooAbsOptTestStatistic::setDataSlave(RooAbsData& indata, bool cloneData, bool ownNewData)
734{
735
736 if (operMode()==SimMaster) {
737 //cout << "ROATS::setDataSlave() ERROR this is SimMaster _funcClone = " << _funcClone << endl ;
738 return false ;
739 }
740
741 //cout << "ROATS::setDataSlave() new dataset size = " << indata.numEntries() << endl ;
742 //indata.Print("v") ;
743
744
745 // If the current dataset is owned, transfer the ownership to unique pointer
746 // that will get out of scope at the end of this function. We can't delete it
747 // right now, because there might be global observables in the model that
748 // first need to be redirected to the new dataset with a later call to
749 // RooAbsArg::recursiveRedirectServers.
750 std::unique_ptr<RooAbsData> oldOwnedData;
751 if (_ownData) {
752 oldOwnedData.reset(_dataClone);
753 _dataClone = nullptr ;
754 }
755
756 if (!cloneData && _rangeName.size()>0) {
757 coutW(InputArguments) << "RooAbsOptTestStatistic::setData(" << GetName() << ") WARNING: test statistic was constructed with range selection on data, "
758 << "ignoring request to _not_ clone the input dataset" << endl ;
759 cloneData = true ;
760 }
761
762 if (cloneData) {
763 // Cloning input dataset
764 if (_rangeName.empty()) {
765 _dataClone = (RooAbsData*) indata.reduce(*indata.get()) ;
766 } else {
768 }
769 _ownData = true ;
770
771 } else {
772
773 // Taking input dataset
774 _dataClone = &indata ;
775 _ownData = ownNewData ;
776
777 }
778
779 // Attach function clone to dataset
781 _dataClone->setDirtyProp(false) ;
782 _data = _dataClone ;
783
784 // ReCache constant nodes with dataset
785 if (_cachedNodes.getSize()>0) {
787 }
788
789 // Adjust internal event count
790 setEventCount(indata.numEntries()) ;
791
792 setValueDirty() ;
793
794 // It would be unusual if the global observables are used in the likelihood
795 // outside of the constraint terms, but if they are we have to be consistent
796 // and also redirect them to the snapshots in the dataset if appropriate.
799 }
800
801 return true ;
802}
803
804
805
806
807////////////////////////////////////////////////////////////////////////////////
808
810{
811 if (_sealed) {
812 bool notice = (sealNotice() && strlen(sealNotice())) ;
813 coutW(ObjectHandling) << "RooAbsOptTestStatistic::data(" << GetName()
814 << ") WARNING: object sealed by creator - access to data is not permitted: "
815 << (notice?sealNotice():"<no user notice>") << endl ;
816 static RooDataSet dummy ("dummy","dummy",RooArgSet()) ;
817 return dummy ;
818 }
819 return *_dataClone ;
820}
821
822
823////////////////////////////////////////////////////////////////////////////////
824
826{
827 if (_sealed) {
828 bool notice = (sealNotice() && strlen(sealNotice())) ;
829 coutW(ObjectHandling) << "RooAbsOptTestStatistic::data(" << GetName()
830 << ") WARNING: object sealed by creator - access to data is not permitted: "
831 << (notice?sealNotice():"<no user notice>") << endl ;
832 static RooDataSet dummy ("dummy","dummy",RooArgSet()) ;
833 return dummy ;
834 }
835 return *_dataClone ;
836}
837
838
839////////////////////////////////////////////////////////////////////////////////
840/// Inspect PDF to find out if we are doing a binned fit to a 1-dimensional unbinned PDF.
841/// If this is the case, enable finer sampling of bins by wrapping PDF into a RooBinSamplingPdf.
842/// The member _integrateBinsPrecision decides how we act:
843/// - < 0: Don't do anything.
844/// - = 0: Only enable feature if fitting unbinned PDF to RooDataHist.
845/// - > 0: Enable as requested.
847
848 auto& pdf = static_cast<RooAbsPdf&>(*_funcClone);
851 _funcClone = newPdf.release();
852 }
853
854}
855
856
857/// Returns a suffix string that is unique for RooAbsOptTestStatistic
858/// instances that don't share the same cloned input data object.
860 return Form("_%lx", _dataClone->uniqueId().value()) ;
861}
#define e(i)
Definition: RSha256.hxx:103
#define coutI(a)
Definition: RooMsgService.h:34
#define cxcoutI(a)
Definition: RooMsgService.h:89
#define coutW(a)
Definition: RooMsgService.h:36
#define cxcoutW(a)
Definition: RooMsgService.h:97
#define coutE(a)
Definition: RooMsgService.h:37
#define ClassImp(name)
Definition: Rtypes.h:375
static void indent(ostringstream &buf, int indent_level)
char name[80]
Definition: TGX11.cxx:110
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition: TString.cxx:2447
virtual RooAbsArg * cloneTree(const char *newname=0) const
Clone tree expression of objects.
Definition: RooAbsArg.cxx:2220
bool recursiveRedirectServers(const RooAbsCollection &newServerList, bool mustReplaceAll=false, bool nameChange=false, bool recurseInNewSet=true)
Recursively replace all servers with the new servers in newSet.
Definition: RooAbsArg.cxx:1191
void printCompactTree(const char *indent="", const char *fileName=0, const char *namePat=0, RooAbsArg *client=0)
Print tree structure of expression tree on stdout, or to file if filename is specified.
Definition: RooAbsArg.cxx:1893
void setStringAttribute(const Text_t *key, const Text_t *value)
Associate string 'value' to this object under key 'key'.
Definition: RooAbsArg.cxx:310
RooArgSet * getObservables(const RooArgSet &set, bool valueOnly=true) const
Given a set of possible observables, return the observables that this PDF depends on.
Definition: RooAbsArg.h:312
friend class RooArgSet
Definition: RooAbsArg.h:645
bool addOwnedComponents(const RooAbsCollection &comps)
Take ownership of the contents of 'comps'.
Definition: RooAbsArg.cxx:2185
const Text_t * getStringAttribute(const Text_t *key) const
Get string attribute mapped under key 'key'.
Definition: RooAbsArg.cxx:323
bool findConstantNodes(const RooArgSet &observables, RooArgSet &cacheList)
Find branch nodes with all-constant parameters, and add them to the list of nodes that can be cached ...
Definition: RooAbsArg.cxx:1762
void setValueDirty()
Mark the element dirty. This forces a re-evaluation when a value is requested.
Definition: RooAbsArg.h:508
bool getAttribute(const Text_t *name) const
Check if a named attribute is set. By default, all attributes are unset.
Definition: RooAbsArg.cxx:301
virtual void optimizeCacheMode(const RooArgSet &observables)
Activate cache mode optimization with given definition of observables.
Definition: RooAbsArg.cxx:1686
@ DeActivate
Definition: RooAbsArg.h:406
@ ValueChange
Definition: RooAbsArg.h:406
@ ConfigChange
Definition: RooAbsArg.h:406
void setAttribute(const Text_t *name, bool value=true)
Set (default) or clear a named boolean attribute of this object.
Definition: RooAbsArg.cxx:278
RooArgSet * getParameters(const RooAbsData *data, bool stripDisconnected=true) const
Create a list of leaf nodes in the arg tree starting with ourself as top node that don't match any of...
Definition: RooAbsArg.cxx:565
void branchNodeServerList(RooAbsCollection *list, const RooAbsArg *arg=0, bool recurseNonDerived=false) const
Fill supplied list with all branch nodes of the arg tree starting with ourself as top node.
Definition: RooAbsArg.cxx:507
virtual RooAbsReal * highBoundFunc() const
Return pointer to RooAbsReal parameterized upper bound, if any.
Definition: RooAbsBinning.h:88
virtual RooAbsReal * lowBoundFunc() const
Return pointer to RooAbsReal parameterized lower bound, if any.
Definition: RooAbsBinning.h:84
RooAbsCollection is an abstract container object that can hold multiple RooAbsArg objects.
RooAbsCollection * selectByAttrib(const char *name, bool value) const
Create a subset of the current collection, consisting only of those elements with the specified attri...
virtual void removeAll()
Remove all arguments from our set, deleting them if we own them.
virtual bool remove(const RooAbsArg &var, bool silent=false, bool matchByNameOnly=false)
Remove the specified argument from our list.
Int_t getSize() const
Return the number of elements in the collection.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
void setAttribAll(const Text_t *name, bool value=true)
Set given attribute in each element of the collection by calling each elements setAttribute() functio...
Storage_t::size_type size() const
RooAbsArg * first() const
bool selectCommon(const RooAbsCollection &refColl, RooAbsCollection &outColl) const
Create a subset of the current collection, consisting only of those elements that are contained as we...
RooAbsArg * find(const char *name) const
Find object with given name in list.
virtual const RooAbsArg * cacheOwner()=0
virtual void forceCacheUpdate()
RooAbsData is the common abstract base class for binned and unbinned datasets.
Definition: RooAbsData.h:62
virtual const RooArgSet * get() const
Definition: RooAbsData.h:106
RooAbsDataStore * store()
Definition: RooAbsData.h:82
RooFit::UniqueId< RooAbsData > const & uniqueId() const
Returns a unique ID that is different for every instantiated RooAbsData object.
Definition: RooAbsData.h:324
void setDirtyProp(bool flag)
Control propagation of dirty flags from observables in dataset.
Definition: RooAbsData.cxx:434
virtual void setArgStatus(const RooArgSet &set, bool active)
Definition: RooAbsData.cxx:426
virtual void optimizeReadingWithCaching(RooAbsArg &arg, const RooArgSet &cacheList, const RooArgSet &keepObsList)
Prepare dataset for use with cached constant terms listed in 'cacheList' of expression 'arg'.
bool hasFilledCache() const
virtual Int_t numEntries() const
Return number of entries in dataset, i.e., count unweighted entries.
Definition: RooAbsData.cxx:379
RooArgSet const * getGlobalObservables() const
Returns snapshot of global observables stored in this data.
Definition: RooAbsData.h:304
virtual void resetCache()
Internal method – Remove cached function values.
Definition: RooAbsData.cxx:410
RooAbsData * reduce(const RooCmdArg &arg1, const RooCmdArg &arg2=RooCmdArg(), const RooCmdArg &arg3=RooCmdArg(), const RooCmdArg &arg4=RooCmdArg(), const RooCmdArg &arg5=RooCmdArg(), const RooCmdArg &arg6=RooCmdArg(), const RooCmdArg &arg7=RooCmdArg(), const RooCmdArg &arg8=RooCmdArg())
Create a reduced copy of this dataset.
Definition: RooAbsData.cxx:454
void attachBuffers(const RooArgSet &extObs)
virtual void cacheArgs(const RooAbsArg *owner, RooArgSet &varSet, const RooArgSet *nset=0, bool skipZeroWeights=false)
Internal method – Cache given set of functions with data.
Definition: RooAbsData.cxx:402
RooAbsOptTestStatistic is the abstract base class for test statistics objects that evaluate a functio...
bool setDataSlave(RooAbsData &data, bool cloneData=true, bool ownNewDataAnyway=false) override
Change dataset that is used to given one.
~RooAbsOptTestStatistic() override
Destructor.
RooAbsReal * _funcClone
Pointer to internal clone of input function.
bool _sealed
Is test statistic sealed – i.e. no access to data.
void optimizeConstantTerms(bool, bool=true)
Driver function to activate global constant term optimization.
double combinedValue(RooAbsReal **gofArray, Int_t nVal) const override
Method to combined test statistic results calculated into partitions into the global result.
RooAbsReal * _origFunc
Original function.
bool _ownData
Do we own the dataset.
void optimizeCaching()
This method changes the value caching logic for all nodes that depends on any of the observables as d...
const char * sealNotice() const
RooAbsData * _origData
Original data.
RooArgSet * _funcObsSet
List of observables in the pdf expression.
void constOptimizeTestStatistic(ConstOpCode opcode, bool doAlsoTrackingOpt=true) override
Driver function to propagate constant term optimizations in test statistic.
void setUpBinSampling()
Inspect PDF to find out if we are doing a binned fit to a 1-dimensional unbinned PDF.
bool redirectServersHook(const RooAbsCollection &newServerList, bool mustReplaceAll, bool nameChange, bool isRecursive) override
Catch server redirect calls and forward to internal clone of function.
RooArgSet _cachedNodes
! List of nodes that are cached as constant expressions
void initSlave(RooAbsReal &real, RooAbsData &indata, const RooArgSet &projDeps, const char *rangeName, const char *addCoefRangeName)
void printCompactTreeHook(std::ostream &os, const char *indent="") override
Catch print hook function and forward to function clone.
RooArgSet * _normSet
Pointer to set with observables used for normalization.
const char * cacheUniqueSuffix() const override
Returns a suffix string that is unique for RooAbsOptTestStatistic instances that don't share the same...
RooArgSet * _funcCloneSet
Set owning all components of internal clone of input function.
RooAbsData * _dataClone
Pointer to internal clone if input data.
virtual RooArgSet requiredExtraObservables() const
RooAbsOptTestStatistic()
Default Constructor.
RooArgSet * _projDeps
Set of projected observable.
RooAbsRealLValue is the common abstract base class for objects that represent a real value that may a...
virtual double getMax(const char *name=0) const
Get maximum of currently defined range.
virtual double getMin(const char *name=0) const
Get minimum of currently defined range.
bool hasRange(const char *name) const override
Check if variable has a binning with given name.
RooAbsReal is the common abstract base class for objects that represent a real value and implements f...
Definition: RooAbsReal.h:64
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition: RooAbsReal.h:94
virtual double getValV(const RooArgSet *normalisationSet=nullptr) const
Return value of object.
Definition: RooAbsReal.cxx:275
virtual void fixAddCoefNormalization(const RooArgSet &addNormSet=RooArgSet(), bool force=true)
Fix the interpretation of the coefficient of any RooAddPdf component in the expression tree headed by...
virtual void fixAddCoefRange(const char *rangeName=0, bool force=true)
Fix the interpretation of the coefficient of any RooAddPdf component in the expression tree headed by...
RooAbsTestStatistic is the abstract base class for all test statistics.
double _evalCarry
! carry of Kahan sum in evaluatePartition
std::string _addCoefRangeName
Name of reference to be used for RooAddPdf components.
GOFOpMode operMode() const
RooSetProxy _paramSet
Parameters of the test statistic (=parameters of the input function)
RooAbsReal * _func
Pointer to original input function.
void printCompactTreeHook(std::ostream &os, const char *indent="") override
Add extra information on component test statistics when printing itself as part of a tree structure.
std::string _rangeName
Name of range in which to calculate test statistic.
void constOptimizeTestStatistic(ConstOpCode opcode, bool doAlsoTrackingOpt=true) override
Forward constant term optimization management calls to component test statistics.
void setEventCount(Int_t nEvents)
virtual double getCarry() const
bool _splitRange
Split rangeName in RooSimultaneous index labels if true.
RooAbsData * _data
Pointer to original input dataset.
const bool _takeGlobalObservablesFromData
If the global observable values are taken from data.
bool redirectServersHook(const RooAbsCollection &newServerList, bool mustReplaceAll, bool nameChange, bool isRecursive) override
Forward server redirect calls to component test statistics.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition: RooArgSet.h:57
RooArgSet * snapshot(bool deepCopy=true) const
Use RooAbsCollection::snapshot(), but return as RooArgSet.
Definition: RooArgSet.h:180
static std::unique_ptr< RooAbsPdf > create(RooAbsPdf &pdf, RooAbsData const &data, double precision)
Creates a wrapping RooBinSamplingPdf if appropriate.
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...
RooDataSet is a container class to hold unbinned data.
Definition: RooDataSet.h:55
static void softAbort()
Soft abort function that interrupts macro execution but doesn't kill ROOT.
RooProdPdf is an efficient implementation of a product of PDFs of the form.
Definition: RooProdPdf.h:33
RooArgSet * getConnectedParameters(const RooArgSet &observables) const
Return all parameter constraint p.d.f.s on parameters listed in constrainedParams.
RooRealVar represents a variable that can be changed from the outside.
Definition: RooRealVar.h:40
bool hasBinning(const char *name) const override
Returns true if variable has a binning named 'name'.
Definition: RooRealVar.cxx:331
const RooAbsBinning & getBinning(const char *name=0, bool verbose=true, bool createOnTheFly=false) const override
Return binning definition with name.
Definition: RooRealVar.cxx:344
void setRange(const char *name, double min, double max)
Set a fit or plotting range.
Definition: RooRealVar.cxx:552
void setBinning(const RooAbsBinning &binning, const char *name=0)
Add given binning under name 'name' with this variable.
Definition: RooRealVar.cxx:441
RooVectorDataStore uses std::vectors to store data columns.
TObject * Clone(const char *newname="") const override
Make a clone of an object using the Streamer facility.
Definition: TNamed.cxx:74
const char * GetName() const override
Returns name of object.
Definition: TNamed.h:47
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:130
Basic string class.
Definition: TString.h:136
const char * Data() const
Definition: TString.h:369
RooCmdArg SelectVars(const RooArgSet &vars)
RooCmdArg CutRange(const char *rangeName)
Double_t y[n]
Definition: legend1.C:17
const Int_t n
Definition: legend1.C:16
@ Minimization
Definition: RooGlobalFunc.h:63
@ Optimization
Definition: RooGlobalFunc.h:64
@ InputArguments
Definition: RooGlobalFunc.h:64
@ ObjectHandling
Definition: RooGlobalFunc.h:64
constexpr Value_t value() const
Return numerical value of ID.
Definition: UniqueId.h:59
static uint64_t sum(uint64_t i)
Definition: Factory.cxx:2345