Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooAbsOptTestStatistic.cxx
Go to the documentation of this file.
1/// \cond ROOFIT_INTERNAL
2
3/*****************************************************************************
4 * Project: RooFit *
5 * Package: RooFitCore *
6 * @(#)root/roofitcore:$Id$
7 * Authors: *
8 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
9 * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
10 * *
11 * Copyright (c) 2000-2005, Regents of the University of California *
12 * and Stanford University. All rights reserved. *
13 * *
14 * Redistribution and use in source and binary forms, *
15 * with or without modification, are permitted according to the terms *
16 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
17 *****************************************************************************/
18
19/**
20\file RooAbsOptTestStatistic.cxx
21\class RooAbsOptTestStatistic
22\ingroup Roofitcore
23
24Abstract base class for test
25statistics objects that evaluate a function or PDF at each point of a given
26dataset. This class provides generic optimizations, such as
27caching and precalculation of constant terms that can be made for
28all such quantities.
29
30Implementations should define evaluatePartition(), which calculates the
31value of a (sub)range of the dataset and optionally combinedValue(),
32which combines the values calculated for each partition. If combinedValue()
33is not overloaded, the default implementation will add the partition results
34to obtain the combined result.
35
36Support for calculation in partitions is needed to allow multi-core
37parallelized calculation of test statistics.
38**/
39
41
42#include "Riostream.h"
43#include "TClass.h"
44#include <cstring>
45
46#include "RooAbsData.h"
47#include "RooAbsDataStore.h"
48#include "RooAbsPdf.h"
49#include "RooAddPdf.h"
50#include "RooArgSet.h"
51#include "RooBinSamplingPdf.h"
52#include "RooBinning.h"
53#include "RooCategory.h"
54#include "RooDataHist.h"
55#include "RooDataSet.h"
56#include "RooErrorHandler.h"
57#include "RooFitImplHelpers.h"
58#include "RooGlobalFunc.h"
59#include "RooMsgService.h"
60#include "RooProdPdf.h"
61#include "RooProduct.h"
62#include "RooRealSumPdf.h"
63#include "RooRealVar.h"
64#include "RooTrace.h"
65#include "RooVectorDataStore.h"
66
67#include "ROOT/StringUtils.hxx"
68
69using std::ostream;
70
71////////////////////////////////////////////////////////////////////////////////
72/// Create a test statistic, and optimise its calculation.
73/// \param[in] name Name of the instance.
74/// \param[in] title Title (for e.g. plotting).
75/// \param[in] real Function to evaluate.
76/// \param[in] indata Dataset for which to compute test statistic.
77/// \param[in] projDeps A set of projected observables.
78/// \param[in] cfg the statistic configuration
79///
80/// cfg contains:
81/// - rangeName If not null, only events in the dataset inside the range will be used in the test
82/// statistic calculation.
83/// - addCoefRangeName If not null, all RooAddPdf components of `real` will be
84/// instructed to fix their fraction definitions to the given named range.
85/// - nCPU If > 1, the test statistic calculation will be parallelised over multiple processes. By default, the data
86/// is split with 'bulk' partitioning (each process calculates a contiguous block of fraction 1/nCPU
87/// of the data). For binned data, this approach may be suboptimal as the number of bins with >0 entries
88/// in each processing block may vary greatly; thereby distributing the workload rather unevenly.
89/// - interleave Strategy how to distribute events among workers. If an interleave partitioning strategy is used where each partition
90/// i takes all bins for which (ibin % ncpu == i), an even distribution of work is more likely.
91/// - splitCutRange If true, a different rangeName constructed as `rangeName_{catName}` will be used
92/// as range definition for each index state of a RooSimultaneous.
93/// - cloneInputData Not used. Data is always cloned.
94/// - integrateOverBinsPrecision If > 0, PDF in binned fits are integrated over the bins. This sets the precision. If = 0,
95/// only unbinned PDFs fit to RooDataHist are integrated. If < 0, PDFs are never integrated.
96RooAbsOptTestStatistic::RooAbsOptTestStatistic(const char *name, const char *title, RooAbsReal &real,
97 RooAbsData &indata, const RooArgSet &projDeps,
98 RooAbsTestStatistic::Configuration const &cfg)
99 : RooAbsTestStatistic(name, title, real, indata, projDeps, cfg),
101{
102 // Don't do a thing in master mode
103 if (operMode() != Slave) {
104 return;
105 }
106
107 initSlave(real, indata, projDeps, _rangeName.c_str(), _addCoefRangeName.c_str());
108}
109
110////////////////////////////////////////////////////////////////////////////////
111/// Copy constructor
112
113RooAbsOptTestStatistic::RooAbsOptTestStatistic(const RooAbsOptTestStatistic &other, const char *name)
119{
120 // Don't do a thing in master mode
121 if (operMode() != Slave) {
122
123 if (other._normSet) {
124 _normSet = new RooArgSet;
125 other._normSet->snapshot(*_normSet);
126 }
127 return;
128 }
129
130 initSlave(*other._funcClone, *other._dataClone, other._projDeps ? *other._projDeps : RooArgSet(),
131 other._rangeName.c_str(), other._addCoefRangeName.c_str());
132}
133
134
135
136////////////////////////////////////////////////////////////////////////////////
137
138void RooAbsOptTestStatistic::initSlave(RooAbsReal& real, RooAbsData& indata, const RooArgSet& projDeps, const char* rangeName,
139 const char* addCoefRangeName) {
140 // ******************************************************************
141 // *** PART 1 *** Clone incoming pdf, attach to each other *
142 // ******************************************************************
143
144 // Clone FUNC
146 _funcCloneSet = nullptr ;
147
148 // Attach FUNC to data set
149 _funcObsSet = std::unique_ptr<RooArgSet>{_funcClone->getObservables(indata)}.release();
150
151 if (_funcClone->getAttribute("BinnedLikelihood")) {
152 _funcClone->setAttribute("BinnedLikelihoodActive") ;
153 }
154
155 // Mark all projected dependents as such
156 if (!projDeps.empty()) {
157 std::unique_ptr<RooArgSet> projDataDeps{_funcObsSet->selectCommon(projDeps)};
158 projDataDeps->setAttribAll("projectedDependent") ;
159 }
160
161 // If PDF is a RooProdPdf (with possible constraint terms)
162 // analyze pdf for actual parameters (i.e those in unconnected constraint terms should be
163 // ignored as here so that the test statistic will not be recalculated if those
164 // are changed
165 RooProdPdf* pdfWithCons = dynamic_cast<RooProdPdf*>(_funcClone) ;
166 if (pdfWithCons) {
167
168 std::unique_ptr<RooArgSet> connPars{pdfWithCons->getConnectedParameters(*indata.get())};
169 // Add connected parameters as servers
170 _paramSet.add(*connPars) ;
171
172 } else {
173 // Add parameters as servers
174 _funcClone->getParameters(indata.get(), _paramSet);
175 }
176
177 // Store normalization set
178 _normSet = new RooArgSet;
179 indata.get()->snapshot(*_normSet, false);
180
181 // Expand list of observables with any observables used in parameterized ranges.
182 // This NEEDS to be a counting loop since we are inserting during the loop.
183 for (std::size_t i = 0; i < _funcObsSet->size(); ++i) {
184 auto realDepRLV = dynamic_cast<const RooAbsRealLValue*>((*_funcObsSet)[i]);
185 if (realDepRLV && realDepRLV->isDerived()) {
187 realDepRLV->leafNodeServerList(&tmp2, nullptr, true);
188 _funcObsSet->add(tmp2,true);
189 }
190 }
191
192
193
194 // ******************************************************************
195 // *** PART 2 *** Clone and adjust incoming data, attach to PDF *
196 // ******************************************************************
197
198 // Check if the fit ranges of the dependents in the data and in the FUNC are consistent
199 const RooArgSet* dataDepSet = indata.get() ;
200 for (const auto arg : *_funcObsSet) {
201
202 // Check that both dataset and function argument are of type RooRealVar
203 RooRealVar* realReal = dynamic_cast<RooRealVar*>(arg) ;
204 if (!realReal) continue ;
205 RooRealVar* datReal = dynamic_cast<RooRealVar*>(dataDepSet->find(realReal->GetName())) ;
206 if (!datReal) continue ;
207
208 // Check that range of observables in pdf is equal or contained in range of observables in data
209
210 if (!realReal->getBinning().lowBoundFunc() && realReal->getMin()<(datReal->getMin()-1e-6)) {
211 coutE(InputArguments) << "RooAbsOptTestStatistic: ERROR minimum of FUNC observable " << arg->GetName()
212 << "(" << realReal->getMin() << ") is smaller than that of "
213 << arg->GetName() << " in the dataset (" << datReal->getMin() << ")" << std::endl ;
215 return ;
216 }
217
218 if (!realReal->getBinning().highBoundFunc() && realReal->getMax()>(datReal->getMax()+1e-6)) {
219 coutE(InputArguments) << "RooAbsOptTestStatistic: ERROR maximum of FUNC observable " << arg->GetName()
220 << " is larger than that of " << arg->GetName() << " in the dataset" << std::endl ;
222 return ;
223 }
224 }
225
226 // Copy data and strip entries lost by adjusted fit range, _dataClone ranges will be copied from realDepSet ranges
227 if (rangeName && strlen(rangeName)) {
228 _dataClone = std::unique_ptr<RooAbsData>{indata.reduce(RooFit::SelectVars(*_funcObsSet),RooFit::CutRange(rangeName))}.release();
229 // std::cout << "RooAbsOptTestStatistic: reducing dataset to fit in range named " << rangeName << " resulting dataset has " << _dataClone->sumEntries() << " events" << std::endl ;
230 } else {
231 _dataClone = static_cast<RooAbsData*>(indata.Clone()) ;
232 }
233 _ownData = true ;
234
235
236 // ******************************************************************
237 // *** PART 3 *** Make adjustments for fit ranges, if specified *
238 // ******************************************************************
239
240 std::unique_ptr<RooArgSet> origObsSet( real.getObservables(indata) );
241 if (rangeName && strlen(rangeName)) {
242 cxcoutI(Fitting) << "RooAbsOptTestStatistic::ctor(" << GetName() << ") constructing test statistic for sub-range named " << rangeName << std::endl ;
243
244 if(auto pdfClone = dynamic_cast<RooAbsPdf*>(_funcClone)) {
245 pdfClone->setNormRange(rangeName);
246 }
247
248 // Print warnings if the requested ranges are not available for the observable
249 for (const auto arg : *_funcObsSet) {
250
251 if (auto realObs = dynamic_cast<RooRealVar*>(arg)) {
252
253 auto tokens = ROOT::Split(rangeName, ",");
254 for(std::string const& token : tokens) {
255 if(!realObs->hasRange(token.c_str())) {
256 std::stringstream errMsg;
257 errMsg << "The observable \"" << realObs->GetName() << "\" doesn't define the requested range \""
258 << token << "\". Replacing it with the default range." << std::endl;
259 coutI(Fitting) << errMsg.str() << std::endl;
260 }
261 }
262 }
263 }
264 }
265
266
267 // ******************************************************************
268 // *** PART 3.2 *** Binned fits *
269 // ******************************************************************
270
272
273
274 // Fix RooAddPdf coefficients to original normalization range
275 if (rangeName && strlen(rangeName)) {
276
277 // WVE Remove projected dependents from normalization
278 _funcClone->fixAddCoefNormalization(*_dataClone->get(),false) ;
279
281 cxcoutI(Fitting) << "RooAbsOptTestStatistic::ctor(" << GetName()
282 << ") fixing interpretation of coefficients of any RooAddPdf component to range " << addCoefRangeName << std::endl ;
283 _funcClone->fixAddCoefRange(addCoefRangeName,false) ;
284 }
285 }
286
287
288 // This is deferred from part 2 - but must happen after part 3 - otherwise invalid bins cannot be properly marked in cacheValidEntries
289 _dataClone->attachBuffers(*_funcObsSet) ;
290 setEventCount(_dataClone->numEntries()) ;
291
292
293
294
295 // *********************************************************************
296 // *** PART 4 *** Adjust normalization range for projected observables *
297 // *********************************************************************
298
299 // Remove projected dependents from normalization set
300 if (!projDeps.empty()) {
301
302 _projDeps = new RooArgSet;
303 projDeps.snapshot(*_projDeps, false) ;
304
305 //RooArgSet* tobedel = (RooArgSet*) _normSet->selectCommon(*_projDeps) ;
306 _normSet->remove(*_projDeps,true,true) ;
307
308 // Mark all projected dependents as such
310 _funcObsSet->selectCommon(*_projDeps, projDataDeps);
311 projDataDeps.setAttribAll("projectedDependent") ;
312 }
313
314
315 coutI(Optimization) << "RooAbsOptTestStatistic::ctor(" << GetName() << ") optimizing internal clone of p.d.f for likelihood evaluation."
316 << "Lazy evaluation and associated change tracking will disabled for all nodes that depend on observables" << std::endl ;
317
318
319 // *********************************************************************
320 // *** PART 4 *** Finalization and activation of optimization *
321 // *********************************************************************
322
323 // Redirect pointers of base class to clone
324 _func = _funcClone ;
325 _data = _dataClone ;
326
327 _funcClone->getVal(_normSet) ;
328
329 optimizeCaching() ;
330
331 // It would be unusual if the global observables are used in the likelihood
332 // outside of the constraint terms, but if they are we have to be consistent
333 // and also redirect them to the snapshots in the dataset if appropriate.
334 if(_takeGlobalObservablesFromData && _data->getGlobalObservables()) {
335 recursiveRedirectServers(*_data->getGlobalObservables()) ;
336 }
337
338}
339
340
341////////////////////////////////////////////////////////////////////////////////
342/// Destructor
343
344RooAbsOptTestStatistic::~RooAbsOptTestStatistic()
345{
346 if (operMode()==Slave) {
347 delete _funcClone ;
348 delete _funcObsSet ;
349 if (_projDeps) {
350 delete _projDeps ;
351 }
352 if (_ownData) {
353 delete _dataClone ;
354 }
355 }
356 delete _normSet ;
357}
358
359
360
361////////////////////////////////////////////////////////////////////////////////
362/// Method to combined test statistic results calculated into partitions into
363/// the global result. This default implementation adds the partition return
364/// values
365
366double RooAbsOptTestStatistic::combinedValue(RooAbsReal** array, Int_t n) const
367{
368 // Default implementation returns sum of components
369 double sum(0);
370 double carry(0);
371 for (Int_t i = 0; i < n; ++i) {
372 double y = array[i]->getValV();
373 carry += reinterpret_cast<RooAbsOptTestStatistic*>(array[i])->getCarry();
374 y -= carry;
375 const double t = sum + y;
376 carry = (t - sum) - y;
377 sum = t;
378 }
379 _evalCarry = carry;
380 return sum ;
381}
382
383
384
385////////////////////////////////////////////////////////////////////////////////
386/// Catch server redirect calls and forward to internal clone of function
387
388bool RooAbsOptTestStatistic::redirectServersHook(const RooAbsCollection& newServerList, bool mustReplaceAll, bool nameChange, bool isRecursive)
389{
390 RooAbsTestStatistic::redirectServersHook(newServerList,mustReplaceAll,nameChange,isRecursive) ;
391 if (operMode()!=Slave) return false ;
392 bool ret = _funcClone->recursiveRedirectServers(newServerList,false,nameChange) ;
394}
395
396
397
398////////////////////////////////////////////////////////////////////////////////
399/// Catch print hook function and forward to function clone
400
401void RooAbsOptTestStatistic::printCompactTreeHook(ostream& os, const char* indent)
402{
403 RooAbsTestStatistic::printCompactTreeHook(os,indent) ;
404 if (operMode()!=Slave) return ;
406 indent2 += "opt >>" ;
407 _funcClone->printCompactTree(os,indent2.Data()) ;
408 os << indent2 << " dataset clone = " << _dataClone << " first obs = " << _dataClone->get()->first() << std::endl ;
409}
410
411
412
413////////////////////////////////////////////////////////////////////////////////
414/// Driver function to propagate constant term optimizations in test statistic.
415/// If code Activate is sent, constant term optimization will be executed.
416/// If code Deactivate is sent, any existing constant term optimizations will
417/// be abandoned. If codes ConfigChange or ValueChange are sent, any existing
418/// constant term optimizations will be redone.
419
420void RooAbsOptTestStatistic::constOptimizeTestStatistic(ConstOpCode opcode, bool doAlsoTrackingOpt)
421{
422 // std::cout << "ROATS::constOpt(" << GetName() << ") funcClone structure dump BEFORE const-opt" << std::endl ;
423 // _funcClone->Print("t") ;
424
425 RooAbsTestStatistic::constOptimizeTestStatistic(opcode,doAlsoTrackingOpt);
426 if (operMode()!=Slave) return ;
427
428 if (_dataClone->hasFilledCache() && _dataClone->store()->cacheOwner()!=this) {
429 if (opcode==Activate) {
430 cxcoutW(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
431 << ") dataset cache is owned by another object, no constant term optimization can be applied" << std::endl ;
432 }
433 return ;
434 }
435
436 if (!allowFunctionCache()) {
437 if (opcode==Activate) {
438 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
439 << ") function caching prohibited by test statistic, no constant term optimization is applied" << std::endl ;
440 }
441 return ;
442 }
443
444 if (_dataClone->hasFilledCache() && opcode==Activate) {
445 opcode=ValueChange ;
446 }
447
448 switch(opcode) {
449 case Activate:
450 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
451 << ") optimizing evaluation of test statistic by finding all nodes in p.d.f that depend exclusively"
452 << " on observables and constant parameters and precalculating their values" << std::endl ;
454 break ;
455
456 case DeActivate:
457 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
458 << ") deactivating optimization of constant terms in test statistic" << std::endl ;
459 optimizeConstantTerms(false) ;
460 break ;
461
462 case ConfigChange:
463 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
464 << ") one ore more parameter were changed from constant to floating or vice versa, "
465 << "re-evaluating constant term optimization" << std::endl ;
466 optimizeConstantTerms(false) ;
468 break ;
469
470 case ValueChange:
471 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
472 << ") the value of one ore more constant parameter were changed re-evaluating constant term optimization" << std::endl ;
473 // Request a forcible cache update of all cached nodes
474 _dataClone->store()->forceCacheUpdate() ;
475
476 break ;
477 }
478
479// std::cout << "ROATS::constOpt(" << GetName() << ") funcClone structure dump AFTER const-opt" << std::endl ;
480// _funcClone->Print("t") ;
481}
482
483
484
485////////////////////////////////////////////////////////////////////////////////
486/// This method changes the value caching logic for all nodes that depends on any of the observables
487/// as defined by the given dataset. When evaluating a test statistic constructed from the RooAbsReal
488/// with a dataset the observables are guaranteed to change with every call, thus there is no point
489/// in tracking these changes which result in a net overhead. Thus for observable-dependent nodes,
490/// the evaluation mechanism is changed from being dependent on a 'valueDirty' flag to guaranteed evaluation.
491/// On the dataset side, the observables objects are modified to no longer send valueDirty messages
492/// to their client
493
494void RooAbsOptTestStatistic::optimizeCaching()
495{
496// std::cout << "RooAbsOptTestStatistic::optimizeCaching(" << GetName() << "," << this << ")" << std::endl ;
497
498 // Trigger create of all object caches now in nodes that have deferred object creation
499 // so that cache contents can be processed immediately
500 _funcClone->getVal(_normSet) ;
501
502 // Set value caching mode for all nodes that depend on any of the observables to ADirty
503 _funcClone->optimizeCacheMode(*_funcObsSet) ;
504
505 // Disable propagation of dirty state flags for observables
506 _dataClone->setDirtyProp(false) ;
507
508 // Disable reading of observables that are not used
509 _dataClone->optimizeReadingWithCaching(*_funcClone, RooArgSet(),requiredExtraObservables()) ;
510}
511
512
513
514////////////////////////////////////////////////////////////////////////////////
515/// Driver function to activate global constant term optimization.
516/// If activated, constant terms are found and cached with the dataset.
517/// The operation mode of cached nodes is set to AClean meaning that
518/// their getVal() call will never result in an evaluate call.
519/// Finally the branches in the dataset that correspond to observables
520/// that are exclusively used in constant terms are disabled as
521/// they serve no more purpose
522
523void RooAbsOptTestStatistic::optimizeConstantTerms(bool activate, bool applyTrackingOpt)
524{
525 if(activate) {
526
527 if (_optimized) {
528 return ;
529 }
530
531 // Trigger create of all object caches now in nodes that have deferred object creation
532 // so that cache contents can be processed immediately
533 _funcClone->getVal(_normSet) ;
534
535
536 // WVE - Patch to allow customization of optimization level per component pdf
537 if (_funcClone->getAttribute("NoOptimizeLevel1")) {
538 coutI(Minimization) << " Optimization customization: Level-1 constant-term optimization prohibited by attribute NoOptimizeLevel1 set on top-level pdf "
539 << _funcClone->ClassName() << "::" << _funcClone->GetName() << std::endl ;
540 return ;
541 }
542 if (_funcClone->getAttribute("NoOptimizeLevel2")) {
543 coutI(Minimization) << " Optimization customization: Level-2 constant-term optimization prohibited by attribute NoOptimizeLevel2 set on top-level pdf "
544 << _funcClone->ClassName() << "::" << _funcClone->GetName() << std::endl ;
546 }
547
548 // Apply tracking optimization here. Default strategy is to track components
549 // of RooAddPdfs and RooRealSumPdfs. If these components are a RooProdPdf
550 // or a RooProduct respectively, track the components of these products instead
551 // of the product term
553
554
555 // Add safety check here - applyTrackingOpt will only be applied if present
556 // dataset is constructed in terms of a RooVectorDataStore
557 if (applyTrackingOpt) {
558 if (!dynamic_cast<RooVectorDataStore*>(_dataClone->store())) {
559 coutW(Optimization) << "RooAbsOptTestStatistic::optimizeConstantTerms(" << GetName()
560 << ") WARNING Cache-and-track optimization (Optimize level 2) is only available for datasets"
561 << " implement in terms of RooVectorDataStore - ignoring this option for current dataset" << std::endl ;
563 }
564 }
565
566 if (applyTrackingOpt) {
568 _funcClone->branchNodeServerList(&branches) ;
569 for (auto arg : branches) {
570 arg->setCacheAndTrackHints(trackNodes);
571 }
572 // Do not set CacheAndTrack on constant expressions
573 trackNodes.remove(*std::unique_ptr<RooAbsCollection>{trackNodes.selectByAttrib("Constant",true)});
574
575 // Set CacheAndTrack flag on all remaining nodes
576 trackNodes.setAttribAll("CacheAndTrack",true) ;
577 }
578
579 // Find all nodes that depend exclusively on constant parameters
580 _cachedNodes.removeAll() ;
581
582 _funcClone->findConstantNodes(*_dataClone->get(),_cachedNodes) ;
583
584 // Cache constant nodes with dataset - also cache entries corresponding to zero-weights in data when using BinnedLikelihood
585 _dataClone->cacheArgs(this,_cachedNodes,_normSet, _skipZeroWeights);
586
587 // Put all cached nodes in AClean value caching mode so that their evaluate() is never called
588 for (auto cacheArg : _cachedNodes) {
589 cacheArg->setOperMode(RooAbsArg::AClean) ;
590 }
591
592 std::unique_ptr<RooAbsCollection> constNodes{_cachedNodes.selectByAttrib("ConstantExpressionCached",true)};
595 if (!constNodes->empty()) {
596 if (constNodes->size()<20) {
597 coutI(Minimization) << " The following expressions have been identified as constant and will be precalculated and cached: " << *constNodes << std::endl ;
598 } else {
599 coutI(Minimization) << " A total of " << constNodes->size() << " expressions have been identified as constant and will be precalculated and cached." << std::endl ;
600 }
601 }
602 if (!actualTrackNodes.empty()) {
603 if (actualTrackNodes.size()<20) {
604 coutI(Minimization) << " The following expressions will be evaluated in cache-and-track mode: " << actualTrackNodes << std::endl ;
605 } else {
606 coutI(Minimization) << " A total of " << constNodes->size() << " expressions will be evaluated in cache-and-track-mode." << std::endl ;
607 }
608 }
609
610 // Disable reading of observables that are no longer used
611 _dataClone->optimizeReadingWithCaching(*_funcClone, _cachedNodes,requiredExtraObservables()) ;
612
613 _optimized = true ;
614
615 } else {
616
617 // Delete the cache
618 _dataClone->resetCache() ;
619
620 // Reactivate all tree branches
621 _dataClone->setArgStatus(*_dataClone->get(),true) ;
622
623 // Reset all nodes to ADirty
624 optimizeCaching() ;
625
626 // Disable propagation of dirty state flags for observables
627 _dataClone->setDirtyProp(false) ;
628
629 _cachedNodes.removeAll() ;
630
631
632 _optimized = false ;
633 }
634}
635
636
637
638////////////////////////////////////////////////////////////////////////////////
639/// Change dataset that is used to given one. If cloneData is true, a clone of
640/// in the input dataset is made. If the test statistic was constructed with
641/// a range specification on the data, the cloneData argument is ignored and
642/// the data is always cloned.
643bool RooAbsOptTestStatistic::setDataSlave(RooAbsData& indata, bool cloneData, bool ownNewData)
644{
645
646 if (operMode()==SimMaster) {
647 //cout << "ROATS::setDataSlave() ERROR this is SimMaster _funcClone = " << _funcClone << std::endl ;
648 return false ;
649 }
650
651 //cout << "ROATS::setDataSlave() new dataset size = " << indata.numEntries() << std::endl ;
652 //indata.Print("v") ;
653
654
655 // If the current dataset is owned, transfer the ownership to unique pointer
656 // that will get out of scope at the end of this function. We can't delete it
657 // right now, because there might be global observables in the model that
658 // first need to be redirected to the new dataset with a later call to
659 // RooAbsArg::recursiveRedirectServers.
660 std::unique_ptr<RooAbsData> oldOwnedData;
661 if (_ownData) {
663 _dataClone = nullptr ;
664 }
665
666 if (!cloneData && !_rangeName.empty()) {
667 coutW(InputArguments) << "RooAbsOptTestStatistic::setData(" << GetName() << ") WARNING: test statistic was constructed with range selection on data, "
668 << "ignoring request to _not_ clone the input dataset" << std::endl ;
669 cloneData = true ;
670 }
671
672 if (cloneData) {
673 // Cloning input dataset
674 _dataClone = std::unique_ptr<RooAbsData>{indata.reduce(RooFit::SelectVars(*indata.get()),RooFit::CutRange(_rangeName.c_str()))}.release();
675 _ownData = true ;
676
677 } else {
678
679 // Taking input dataset
680 _dataClone = &indata ;
682
683 }
684
685 // Attach function clone to dataset
686 _dataClone->attachBuffers(*_funcObsSet) ;
687 _dataClone->setDirtyProp(false) ;
688 _data = _dataClone ;
689
690 // ReCache constant nodes with dataset
691 if (!_cachedNodes.empty()) {
692 _dataClone->cacheArgs(this,_cachedNodes,_normSet, _skipZeroWeights);
693 }
694
695 // Adjust internal event count
696 setEventCount(indata.numEntries()) ;
697
698 setValueDirty() ;
699
700 // It would be unusual if the global observables are used in the likelihood
701 // outside of the constraint terms, but if they are we have to be consistent
702 // and also redirect them to the snapshots in the dataset if appropriate.
703 if(_takeGlobalObservablesFromData && _data->getGlobalObservables()) {
704 recursiveRedirectServers(*_data->getGlobalObservables()) ;
705 }
706
707 return true ;
708}
709
710
711
712
713////////////////////////////////////////////////////////////////////////////////
714
715RooAbsData& RooAbsOptTestStatistic::data()
716{
717 if (_sealed) {
718 bool notice = (sealNotice() && strlen(sealNotice())) ;
719 coutW(ObjectHandling) << "RooAbsOptTestStatistic::data(" << GetName()
720 << ") WARNING: object sealed by creator - access to data is not permitted: "
721 << (notice?sealNotice():"<no user notice>") << std::endl ;
722 static RooDataSet dummy ("dummy","dummy",RooArgSet()) ;
723 return dummy ;
724 }
725 return *_dataClone ;
726}
727
728
729////////////////////////////////////////////////////////////////////////////////
730
731const RooAbsData& RooAbsOptTestStatistic::data() const
732{
733 if (_sealed) {
734 bool notice = (sealNotice() && strlen(sealNotice())) ;
735 coutW(ObjectHandling) << "RooAbsOptTestStatistic::data(" << GetName()
736 << ") WARNING: object sealed by creator - access to data is not permitted: "
737 << (notice?sealNotice():"<no user notice>") << std::endl ;
738 static RooDataSet dummy ("dummy","dummy",RooArgSet()) ;
739 return dummy ;
740 }
741 return *_dataClone ;
742}
743
744
745////////////////////////////////////////////////////////////////////////////////
746/// Inspect PDF to find out if we are doing a binned fit to a 1-dimensional unbinned PDF.
747/// If this is the case, enable finer sampling of bins by wrapping PDF into a RooBinSamplingPdf.
748/// The member _integrateBinsPrecision decides how we act:
749/// - < 0: Don't do anything.
750/// - = 0: Only enable feature if fitting unbinned PDF to RooDataHist.
751/// - > 0: Enable as requested.
752void RooAbsOptTestStatistic::setUpBinSampling() {
753
754 auto& pdf = static_cast<RooAbsPdf&>(*_funcClone);
756 newPdf->addOwnedComponents(*_funcClone);
757 _funcClone = newPdf.release();
758 }
759
760}
761
762
763/// Returns a suffix string that is unique for RooAbsOptTestStatistic
764/// instances that don't share the same cloned input data object.
765const char* RooAbsOptTestStatistic::cacheUniqueSuffix() const {
766 return Form("_%lx", _dataClone->uniqueId().value()) ;
767}
768
769
770void RooAbsOptTestStatistic::runRecalculateCache(std::size_t firstEvent, std::size_t lastEvent, std::size_t stepSize) const
771{
772 _dataClone->store()->recalculateCache(_projDeps, firstEvent, lastEvent, stepSize, _skipZeroWeights);
773}
774
775/// \endcond
#define e(i)
Definition RSha256.hxx:103
#define coutI(a)
#define cxcoutI(a)
#define coutW(a)
#define cxcoutW(a)
#define coutE(a)
int Int_t
Definition RtypesCore.h:45
static void indent(ostringstream &buf, int indent_level)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
char name[80]
Definition TGX11.cxx:110
void Activate(TList *slaves=0)
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2489
Abstract container object that can hold multiple RooAbsArg objects.
virtual bool remove(const RooAbsArg &var, bool silent=false, bool matchByNameOnly=false)
Remove the specified argument from our list.
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:57
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:40
Abstract base class for objects that represent a real value that may appear on the left hand side of ...
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:59
virtual double getValV(const RooArgSet *normalisationSet=nullptr) const
Return value of object.
bool redirectServersHook(const RooAbsCollection &newServerList, bool mustReplaceAll, bool nameChange, bool isRecursiveStep) override
Function that is called at the end of redirectServers().
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
static std::unique_ptr< RooAbsPdf > create(RooAbsPdf &pdf, RooAbsData const &data, double precision)
Creates a wrapping RooBinSamplingPdf if appropriate.
Container class to hold unbinned data.
Definition RooDataSet.h:32
static void softAbort()
Soft abort function that interrupts macro execution but doesn't kill ROOT.
Efficient implementation of a product of PDFs of the form.
Definition RooProdPdf.h:36
Variable that can be changed from the outside.
Definition RooRealVar.h:37
Uses std::vector to store data columns.
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
Basic string class.
Definition TString.h:139
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
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::unique_ptr< T > cloneTreeWithSameParameters(T const &arg, RooArgSet const *observables=nullptr)
Clone RooAbsArg object and reattach to original parameters.
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2345