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 "RooVectorDataStore.h"
65
66#include "ROOT/StringUtils.hxx"
67
68using std::ostream;
69
70////////////////////////////////////////////////////////////////////////////////
71/// Create a test statistic, and optimise its calculation.
72/// \param[in] name Name of the instance.
73/// \param[in] title Title (for e.g. plotting).
74/// \param[in] real Function to evaluate.
75/// \param[in] indata Dataset for which to compute test statistic.
76/// \param[in] projDeps A set of projected observables.
77/// \param[in] cfg the statistic configuration
78///
79/// cfg contains:
80/// - rangeName If not null, only events in the dataset inside the range will be used in the test
81/// statistic calculation.
82/// - addCoefRangeName If not null, all RooAddPdf components of `real` will be
83/// instructed to fix their fraction definitions to the given named range.
84/// - nCPU If > 1, the test statistic calculation will be parallelised over multiple processes. By default, the data
85/// is split with 'bulk' partitioning (each process calculates a contiguous block of fraction 1/nCPU
86/// of the data). For binned data, this approach may be suboptimal as the number of bins with >0 entries
87/// in each processing block may vary greatly; thereby distributing the workload rather unevenly.
88/// - interleave Strategy how to distribute events among workers. If an interleave partitioning strategy is used where each partition
89/// i takes all bins for which (ibin % ncpu == i), an even distribution of work is more likely.
90/// - splitCutRange If true, a different rangeName constructed as `rangeName_{catName}` will be used
91/// as range definition for each index state of a RooSimultaneous.
92/// - cloneInputData Not used. Data is always cloned.
93/// - integrateOverBinsPrecision If > 0, PDF in binned fits are integrated over the bins. This sets the precision. If = 0,
94/// only unbinned PDFs fit to RooDataHist are integrated. If < 0, PDFs are never integrated.
95RooAbsOptTestStatistic::RooAbsOptTestStatistic(const char *name, const char *title, RooAbsReal &real,
96 RooAbsData &indata, const RooArgSet &projDeps,
97 RooAbsTestStatistic::Configuration const &cfg)
98 : RooAbsTestStatistic(name, title, real, indata, projDeps, cfg),
100{
101 // Don't do a thing in master mode
102 if (operMode() != Slave) {
103 return;
104 }
105
106 initSlave(real, indata, projDeps, _rangeName.c_str(), _addCoefRangeName.c_str());
107}
108
109////////////////////////////////////////////////////////////////////////////////
110/// Copy constructor
111
112RooAbsOptTestStatistic::RooAbsOptTestStatistic(const RooAbsOptTestStatistic &other, const char *name)
118{
119 // Don't do a thing in master mode
120 if (operMode() != Slave) {
121
122 if (other._normSet) {
123 _normSet = new RooArgSet;
124 other._normSet->snapshot(*_normSet);
125 }
126 return;
127 }
128
129 initSlave(*other._funcClone, *other._dataClone, other._projDeps ? *other._projDeps : RooArgSet(),
130 other._rangeName.c_str(), other._addCoefRangeName.c_str());
131}
132
133
134
135////////////////////////////////////////////////////////////////////////////////
136
137void RooAbsOptTestStatistic::initSlave(RooAbsReal& real, RooAbsData& indata, const RooArgSet& projDeps, const char* rangeName,
138 const char* addCoefRangeName) {
139 // ******************************************************************
140 // *** PART 1 *** Clone incoming pdf, attach to each other *
141 // ******************************************************************
142
143 // Clone FUNC
145 _funcCloneSet = nullptr ;
146
147 // Attach FUNC to data set
148 _funcObsSet = std::unique_ptr<RooArgSet>{_funcClone->getObservables(indata)}.release();
149
150 if (_funcClone->getAttribute("BinnedLikelihood")) {
151 _funcClone->setAttribute("BinnedLikelihoodActive") ;
152 }
153
154 // Mark all projected dependents as such
155 if (!projDeps.empty()) {
156 std::unique_ptr<RooArgSet> projDataDeps{_funcObsSet->selectCommon(projDeps)};
157 projDataDeps->setAttribAll("projectedDependent") ;
158 }
159
160 // If PDF is a RooProdPdf (with possible constraint terms)
161 // analyze pdf for actual parameters (i.e those in unconnected constraint terms should be
162 // ignored as here so that the test statistic will not be recalculated if those
163 // are changed
164 RooProdPdf* pdfWithCons = dynamic_cast<RooProdPdf*>(_funcClone) ;
165 if (pdfWithCons) {
166
167 std::unique_ptr<RooArgSet> connPars{pdfWithCons->getConnectedParameters(*indata.get())};
168 // Add connected parameters as servers
169 _paramSet.add(*connPars) ;
170
171 } else {
172 // Add parameters as servers
173 _funcClone->getParameters(indata.get(), _paramSet);
174 }
175
176 // Store normalization set
177 _normSet = new RooArgSet;
178 indata.get()->snapshot(*_normSet, false);
179
180 // Expand list of observables with any observables used in parameterized ranges.
181 // This NEEDS to be a counting loop since we are inserting during the loop.
182 for (std::size_t i = 0; i < _funcObsSet->size(); ++i) {
183 auto realDepRLV = dynamic_cast<const RooAbsRealLValue*>((*_funcObsSet)[i]);
184 if (realDepRLV && realDepRLV->isDerived()) {
186 realDepRLV->leafNodeServerList(&tmp2, nullptr, true);
187 _funcObsSet->add(tmp2,true);
188 }
189 }
190
191
192
193 // ******************************************************************
194 // *** PART 2 *** Clone and adjust incoming data, attach to PDF *
195 // ******************************************************************
196
197 // Check if the fit ranges of the dependents in the data and in the FUNC are consistent
198 const RooArgSet* dataDepSet = indata.get() ;
199 for (const auto arg : *_funcObsSet) {
200
201 // Check that both dataset and function argument are of type RooRealVar
202 RooRealVar* realReal = dynamic_cast<RooRealVar*>(arg) ;
203 if (!realReal) continue ;
204 RooRealVar* datReal = dynamic_cast<RooRealVar*>(dataDepSet->find(realReal->GetName())) ;
205 if (!datReal) continue ;
206
207 // Check that range of observables in pdf is equal or contained in range of observables in data
208
209 if (!realReal->getBinning().lowBoundFunc() && realReal->getMin()<(datReal->getMin()-1e-6)) {
210 coutE(InputArguments) << "RooAbsOptTestStatistic: ERROR minimum of FUNC observable " << arg->GetName()
211 << "(" << realReal->getMin() << ") is smaller than that of "
212 << arg->GetName() << " in the dataset (" << datReal->getMin() << ")" << std::endl ;
214 return ;
215 }
216
217 if (!realReal->getBinning().highBoundFunc() && realReal->getMax()>(datReal->getMax()+1e-6)) {
218 coutE(InputArguments) << "RooAbsOptTestStatistic: ERROR maximum of FUNC observable " << arg->GetName()
219 << " is larger than that of " << arg->GetName() << " in the dataset" << std::endl ;
221 return ;
222 }
223 }
224
225 // Copy data and strip entries lost by adjusted fit range, _dataClone ranges will be copied from realDepSet ranges
226 if (rangeName && strlen(rangeName)) {
227 _dataClone = std::unique_ptr<RooAbsData>{indata.reduce(RooFit::SelectVars(*_funcObsSet),RooFit::CutRange(rangeName))}.release();
228 } else {
229 _dataClone = static_cast<RooAbsData*>(indata.Clone()) ;
230 }
231 _ownData = true ;
232
233
234 // ******************************************************************
235 // *** PART 3 *** Make adjustments for fit ranges, if specified *
236 // ******************************************************************
237
238 std::unique_ptr<RooArgSet> origObsSet( real.getObservables(indata) );
239 if (rangeName && strlen(rangeName)) {
240 cxcoutI(Fitting) << "RooAbsOptTestStatistic::ctor(" << GetName() << ") constructing test statistic for sub-range named " << rangeName << std::endl ;
241
242 if(auto pdfClone = dynamic_cast<RooAbsPdf*>(_funcClone)) {
243 pdfClone->setNormRange(rangeName);
244 }
245
246 // Print warnings if the requested ranges are not available for the observable
247 for (const auto arg : *_funcObsSet) {
248
249 if (auto realObs = dynamic_cast<RooRealVar*>(arg)) {
250
251 auto tokens = ROOT::Split(rangeName, ",");
252 for(std::string const& token : tokens) {
253 if(!realObs->hasRange(token.c_str())) {
254 std::stringstream errMsg;
255 errMsg << "The observable \"" << realObs->GetName() << "\" doesn't define the requested range \""
256 << token << "\". Replacing it with the default range." << std::endl;
257 coutI(Fitting) << errMsg.str() << std::endl;
258 }
259 }
260 }
261 }
262 }
263
264
265 // ******************************************************************
266 // *** PART 3.2 *** Binned fits *
267 // ******************************************************************
268
270
271
272 // Fix RooAddPdf coefficients to original normalization range
273 if (rangeName && strlen(rangeName)) {
274
275 // WVE Remove projected dependents from normalization
276 _funcClone->fixAddCoefNormalization(*_dataClone->get(),false) ;
277
279 cxcoutI(Fitting) << "RooAbsOptTestStatistic::ctor(" << GetName()
280 << ") fixing interpretation of coefficients of any RooAddPdf component to range " << addCoefRangeName << std::endl ;
281 _funcClone->fixAddCoefRange(addCoefRangeName,false) ;
282 }
283 }
284
285
286 // This is deferred from part 2 - but must happen after part 3 - otherwise invalid bins cannot be properly marked in cacheValidEntries
287 _dataClone->attachBuffers(*_funcObsSet) ;
288 setEventCount(_dataClone->numEntries()) ;
289
290
291
292
293 // *********************************************************************
294 // *** PART 4 *** Adjust normalization range for projected observables *
295 // *********************************************************************
296
297 // Remove projected dependents from normalization set
298 if (!projDeps.empty()) {
299
300 _projDeps = new RooArgSet;
301 projDeps.snapshot(*_projDeps, false) ;
302
303 //RooArgSet* tobedel = (RooArgSet*) _normSet->selectCommon(*_projDeps) ;
304 _normSet->remove(*_projDeps,true,true) ;
305
306 // Mark all projected dependents as such
308 _funcObsSet->selectCommon(*_projDeps, projDataDeps);
309 projDataDeps.setAttribAll("projectedDependent") ;
310 }
311
312
313 coutI(Optimization) << "RooAbsOptTestStatistic::ctor(" << GetName() << ") optimizing internal clone of p.d.f for likelihood evaluation."
314 << "Lazy evaluation and associated change tracking will disabled for all nodes that depend on observables" << std::endl ;
315
316
317 // *********************************************************************
318 // *** PART 4 *** Finalization and activation of optimization *
319 // *********************************************************************
320
321 // Redirect pointers of base class to clone
322 _func = _funcClone ;
323 _data = _dataClone ;
324
325 _funcClone->getVal(_normSet) ;
326
327 optimizeCaching() ;
328
329 // It would be unusual if the global observables are used in the likelihood
330 // outside of the constraint terms, but if they are we have to be consistent
331 // and also redirect them to the snapshots in the dataset if appropriate.
332 if(_takeGlobalObservablesFromData && _data->getGlobalObservables()) {
333 recursiveRedirectServers(*_data->getGlobalObservables()) ;
334 }
335
336}
337
338
339////////////////////////////////////////////////////////////////////////////////
340/// Destructor
341
342RooAbsOptTestStatistic::~RooAbsOptTestStatistic()
343{
344 if (operMode()==Slave) {
345 delete _funcClone ;
346 delete _funcObsSet ;
347 if (_projDeps) {
348 delete _projDeps ;
349 }
350 if (_ownData) {
351 delete _dataClone ;
352 }
353 }
354 delete _normSet ;
355}
356
357
358
359////////////////////////////////////////////////////////////////////////////////
360/// Method to combined test statistic results calculated into partitions into
361/// the global result. This default implementation adds the partition return
362/// values
363
364double RooAbsOptTestStatistic::combinedValue(RooAbsReal** array, Int_t n) const
365{
366 // Default implementation returns sum of components
367 double sum(0);
368 double carry(0);
369 for (Int_t i = 0; i < n; ++i) {
370 double y = array[i]->getValV();
371 carry += reinterpret_cast<RooAbsOptTestStatistic*>(array[i])->getCarry();
372 y -= carry;
373 const double t = sum + y;
374 carry = (t - sum) - y;
375 sum = t;
376 }
377 _evalCarry = carry;
378 return sum ;
379}
380
381
382
383////////////////////////////////////////////////////////////////////////////////
384/// Catch server redirect calls and forward to internal clone of function
385
386bool RooAbsOptTestStatistic::redirectServersHook(const RooAbsCollection& newServerList, bool mustReplaceAll, bool nameChange, bool isRecursive)
387{
388 RooAbsTestStatistic::redirectServersHook(newServerList,mustReplaceAll,nameChange,isRecursive) ;
389 if (operMode()!=Slave) return false ;
390 bool ret = _funcClone->recursiveRedirectServers(newServerList,false,nameChange) ;
392}
393
394
395
396////////////////////////////////////////////////////////////////////////////////
397/// Catch print hook function and forward to function clone
398
399void RooAbsOptTestStatistic::printCompactTreeHook(ostream& os, const char* indent)
400{
401 RooAbsTestStatistic::printCompactTreeHook(os,indent) ;
402 if (operMode()!=Slave) return ;
404 indent2 += "opt >>" ;
405 _funcClone->printCompactTree(os,indent2.Data()) ;
406 os << indent2 << " dataset clone = " << _dataClone << " first obs = " << _dataClone->get()->first() << std::endl ;
407}
408
409
410
411////////////////////////////////////////////////////////////////////////////////
412/// Driver function to propagate constant term optimizations in test statistic.
413/// If code Activate is sent, constant term optimization will be executed.
414/// If code Deactivate is sent, any existing constant term optimizations will
415/// be abandoned. If codes ConfigChange or ValueChange are sent, any existing
416/// constant term optimizations will be redone.
417
418void RooAbsOptTestStatistic::constOptimizeTestStatistic(ConstOpCode opcode, bool doAlsoTrackingOpt)
419{
420 static bool hasWarned = false;
421 if (!hasWarned) {
422 std::stringstream ss;
423 ss << "Deprecated constant term optimization detected,\n"
424 << "enabled via RooFit::Optimize() or RooMinimizer::optimizeConst():\n"
425 << " This functionality only affects the legacy evaluation backend.\n"
426 << " The vectorized CPU backend performs const term optimization automatically.\n"
427 << " The option is ignored and will be removed in ROOT 6.42.\n"
428 << " Should your fit not be possible without the legacy backend, please open a GitHub issue.\n";
429 oocoutW(static_cast<RooAbsArg *>(nullptr), InputArguments) << ss.str() << std::endl;
430 hasWarned = true;
431 }
432
433 RooAbsTestStatistic::constOptimizeTestStatistic(opcode,doAlsoTrackingOpt);
434 if (operMode()!=Slave) return ;
435
436 if (_dataClone->hasFilledCache() && _dataClone->store()->cacheOwner()!=this) {
437 if (opcode==Activate) {
438 cxcoutW(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
439 << ") dataset cache is owned by another object, no constant term optimization can be applied" << std::endl ;
440 }
441 return ;
442 }
443
444 if (!allowFunctionCache()) {
445 if (opcode==Activate) {
446 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
447 << ") function caching prohibited by test statistic, no constant term optimization is applied" << std::endl ;
448 }
449 return ;
450 }
451
452 if (_dataClone->hasFilledCache() && opcode==Activate) {
453 opcode=ValueChange ;
454 }
455
456 switch(opcode) {
457 case Activate:
458 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
459 << ") optimizing evaluation of test statistic by finding all nodes in p.d.f that depend exclusively"
460 << " on observables and constant parameters and precalculating their values" << std::endl ;
462 break ;
463
464 case DeActivate:
465 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
466 << ") deactivating optimization of constant terms in test statistic" << std::endl ;
467 optimizeConstantTerms(false) ;
468 break ;
469
470 case ConfigChange:
471 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
472 << ") one ore more parameter were changed from constant to floating or vice versa, "
473 << "re-evaluating constant term optimization" << std::endl ;
474 optimizeConstantTerms(false) ;
476 break ;
477
478 case ValueChange:
479 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
480 << ") the value of one ore more constant parameter were changed re-evaluating constant term optimization" << std::endl ;
481 // Request a forcible cache update of all cached nodes
482 _dataClone->store()->forceCacheUpdate() ;
483
484 break ;
485 }
486
487}
488
489
490
491////////////////////////////////////////////////////////////////////////////////
492/// This method changes the value caching logic for all nodes that depends on any of the observables
493/// as defined by the given dataset. When evaluating a test statistic constructed from the RooAbsReal
494/// with a dataset the observables are guaranteed to change with every call, thus there is no point
495/// in tracking these changes which result in a net overhead. Thus for observable-dependent nodes,
496/// the evaluation mechanism is changed from being dependent on a 'valueDirty' flag to guaranteed evaluation.
497/// On the dataset side, the observables objects are modified to no longer send valueDirty messages
498/// to their client
499
500void RooAbsOptTestStatistic::optimizeCaching()
501{
502 // Trigger create of all object caches now in nodes that have deferred object creation
503 // so that cache contents can be processed immediately
504 _funcClone->getVal(_normSet) ;
505
506 // Set value caching mode for all nodes that depend on any of the observables to ADirty
507 _funcClone->optimizeCacheMode(*_funcObsSet) ;
508
509 // Disable propagation of dirty state flags for observables
510 _dataClone->setDirtyProp(false) ;
511
512 // Disable reading of observables that are not used
513 _dataClone->optimizeReadingWithCaching(*_funcClone, RooArgSet(),requiredExtraObservables()) ;
514}
515
516
517
518////////////////////////////////////////////////////////////////////////////////
519/// Driver function to activate global constant term optimization.
520/// If activated, constant terms are found and cached with the dataset.
521/// The operation mode of cached nodes is set to AClean meaning that
522/// their getVal() call will never result in an evaluate call.
523/// Finally the branches in the dataset that correspond to observables
524/// that are exclusively used in constant terms are disabled as
525/// they serve no more purpose
526
527void RooAbsOptTestStatistic::optimizeConstantTerms(bool activate, bool applyTrackingOpt)
528{
529 if(activate) {
530
531 if (_optimized) {
532 return ;
533 }
534
535 // Trigger create of all object caches now in nodes that have deferred object creation
536 // so that cache contents can be processed immediately
537 _funcClone->getVal(_normSet) ;
538
539
540 // WVE - Patch to allow customization of optimization level per component pdf
541 if (_funcClone->getAttribute("NoOptimizeLevel1")) {
542 coutI(Minimization) << " Optimization customization: Level-1 constant-term optimization prohibited by attribute NoOptimizeLevel1 set on top-level pdf "
543 << _funcClone->ClassName() << "::" << _funcClone->GetName() << std::endl ;
544 return ;
545 }
546 if (_funcClone->getAttribute("NoOptimizeLevel2")) {
547 coutI(Minimization) << " Optimization customization: Level-2 constant-term optimization prohibited by attribute NoOptimizeLevel2 set on top-level pdf "
548 << _funcClone->ClassName() << "::" << _funcClone->GetName() << std::endl ;
550 }
551
552 // Apply tracking optimization here. Default strategy is to track components
553 // of RooAddPdfs and RooRealSumPdfs. If these components are a RooProdPdf
554 // or a RooProduct respectively, track the components of these products instead
555 // of the product term
557
558
559 // Add safety check here - applyTrackingOpt will only be applied if present
560 // dataset is constructed in terms of a RooVectorDataStore
561 if (applyTrackingOpt) {
562 if (!dynamic_cast<RooVectorDataStore*>(_dataClone->store())) {
563 coutW(Optimization) << "RooAbsOptTestStatistic::optimizeConstantTerms(" << GetName()
564 << ") WARNING Cache-and-track optimization (Optimize level 2) is only available for datasets"
565 << " implement in terms of RooVectorDataStore - ignoring this option for current dataset" << std::endl ;
567 }
568 }
569
570 if (applyTrackingOpt) {
572 _funcClone->branchNodeServerList(&branches) ;
573 for (auto arg : branches) {
574 arg->setCacheAndTrackHints(trackNodes);
575 }
576 // Do not set CacheAndTrack on constant expressions
577 trackNodes.remove(*std::unique_ptr<RooAbsCollection>{trackNodes.selectByAttrib("Constant",true)});
578
579 // Set CacheAndTrack flag on all remaining nodes
580 trackNodes.setAttribAll("CacheAndTrack",true) ;
581 }
582
583 // Find all nodes that depend exclusively on constant parameters
584 _cachedNodes.removeAll() ;
585
586 _funcClone->findConstantNodes(*_dataClone->get(),_cachedNodes) ;
587
588 // Cache constant nodes with dataset - also cache entries corresponding to zero-weights in data when using BinnedLikelihood
589 _dataClone->cacheArgs(this,_cachedNodes,_normSet, _skipZeroWeights);
590
591 // Put all cached nodes in AClean value caching mode so that their evaluate() is never called
592 for (auto cacheArg : _cachedNodes) {
593 cacheArg->setOperMode(RooAbsArg::AClean) ;
594 }
595
596 std::unique_ptr<RooAbsCollection> constNodes{_cachedNodes.selectByAttrib("ConstantExpressionCached",true)};
599 if (!constNodes->empty()) {
600 if (constNodes->size()<20) {
601 coutI(Minimization) << " The following expressions have been identified as constant and will be precalculated and cached: " << *constNodes << std::endl ;
602 } else {
603 coutI(Minimization) << " A total of " << constNodes->size() << " expressions have been identified as constant and will be precalculated and cached." << std::endl ;
604 }
605 }
606 if (!actualTrackNodes.empty()) {
607 if (actualTrackNodes.size()<20) {
608 coutI(Minimization) << " The following expressions will be evaluated in cache-and-track mode: " << actualTrackNodes << std::endl ;
609 } else {
610 coutI(Minimization) << " A total of " << constNodes->size() << " expressions will be evaluated in cache-and-track-mode." << std::endl ;
611 }
612 }
613
614 // Disable reading of observables that are no longer used
615 _dataClone->optimizeReadingWithCaching(*_funcClone, _cachedNodes,requiredExtraObservables()) ;
616
617 _optimized = true ;
618
619 } else {
620
621 // Delete the cache
622 _dataClone->resetCache() ;
623
624 // Reactivate all tree branches
625 _dataClone->setArgStatus(*_dataClone->get(),true) ;
626
627 // Reset all nodes to ADirty
628 optimizeCaching() ;
629
630 // Disable propagation of dirty state flags for observables
631 _dataClone->setDirtyProp(false) ;
632
633 _cachedNodes.removeAll() ;
634
635
636 _optimized = false ;
637 }
638}
639
640
641
642////////////////////////////////////////////////////////////////////////////////
643/// Change dataset that is used to given one. If cloneData is true, a clone of
644/// in the input dataset is made. If the test statistic was constructed with
645/// a range specification on the data, the cloneData argument is ignored and
646/// the data is always cloned.
647bool RooAbsOptTestStatistic::setDataSlave(RooAbsData& indata, bool cloneData, bool ownNewData)
648{
649
650 if (operMode()==SimMaster) {
651 return false ;
652 }
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 oocoutW(o, a)
#define coutW(a)
#define cxcoutW(a)
#define coutE(a)
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
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:148
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2570
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
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:56
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
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:63
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:138
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:2335