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 static bool hasWarned = false;
423 if (!hasWarned) {
424 std::stringstream ss;
425 ss << "Deprecated constant term optimization detected,\n"
426 << "enabled via RooFit::Optimize() or RooMinimizer::optimizeConst():\n"
427 << " This functionality only affects the legacy evaluation backend.\n"
428 << " The vectorized CPU backend performs const term optimization automatically.\n"
429 << " The option is ignored and will be removed in ROOT 6.42.\n"
430 << " Should your fit not be possible without the legacy backend, please open a GitHub issue.\n";
431 oocoutW(static_cast<RooAbsArg *>(nullptr), InputArguments) << ss.str() << std::endl;
432 hasWarned = true;
433 }
434
435 // std::cout << "ROATS::constOpt(" << GetName() << ") funcClone structure dump BEFORE const-opt" << std::endl ;
436 // _funcClone->Print("t") ;
437
438 RooAbsTestStatistic::constOptimizeTestStatistic(opcode,doAlsoTrackingOpt);
439 if (operMode()!=Slave) return ;
440
441 if (_dataClone->hasFilledCache() && _dataClone->store()->cacheOwner()!=this) {
442 if (opcode==Activate) {
443 cxcoutW(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
444 << ") dataset cache is owned by another object, no constant term optimization can be applied" << std::endl ;
445 }
446 return ;
447 }
448
449 if (!allowFunctionCache()) {
450 if (opcode==Activate) {
451 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
452 << ") function caching prohibited by test statistic, no constant term optimization is applied" << std::endl ;
453 }
454 return ;
455 }
456
457 if (_dataClone->hasFilledCache() && opcode==Activate) {
458 opcode=ValueChange ;
459 }
460
461 switch(opcode) {
462 case Activate:
463 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
464 << ") optimizing evaluation of test statistic by finding all nodes in p.d.f that depend exclusively"
465 << " on observables and constant parameters and precalculating their values" << std::endl ;
467 break ;
468
469 case DeActivate:
470 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
471 << ") deactivating optimization of constant terms in test statistic" << std::endl ;
472 optimizeConstantTerms(false) ;
473 break ;
474
475 case ConfigChange:
476 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
477 << ") one ore more parameter were changed from constant to floating or vice versa, "
478 << "re-evaluating constant term optimization" << std::endl ;
479 optimizeConstantTerms(false) ;
481 break ;
482
483 case ValueChange:
484 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
485 << ") the value of one ore more constant parameter were changed re-evaluating constant term optimization" << std::endl ;
486 // Request a forcible cache update of all cached nodes
487 _dataClone->store()->forceCacheUpdate() ;
488
489 break ;
490 }
491
492// std::cout << "ROATS::constOpt(" << GetName() << ") funcClone structure dump AFTER const-opt" << std::endl ;
493// _funcClone->Print("t") ;
494}
495
496
497
498////////////////////////////////////////////////////////////////////////////////
499/// This method changes the value caching logic for all nodes that depends on any of the observables
500/// as defined by the given dataset. When evaluating a test statistic constructed from the RooAbsReal
501/// with a dataset the observables are guaranteed to change with every call, thus there is no point
502/// in tracking these changes which result in a net overhead. Thus for observable-dependent nodes,
503/// the evaluation mechanism is changed from being dependent on a 'valueDirty' flag to guaranteed evaluation.
504/// On the dataset side, the observables objects are modified to no longer send valueDirty messages
505/// to their client
506
507void RooAbsOptTestStatistic::optimizeCaching()
508{
509// std::cout << "RooAbsOptTestStatistic::optimizeCaching(" << GetName() << "," << this << ")" << std::endl ;
510
511 // Trigger create of all object caches now in nodes that have deferred object creation
512 // so that cache contents can be processed immediately
513 _funcClone->getVal(_normSet) ;
514
515 // Set value caching mode for all nodes that depend on any of the observables to ADirty
516 _funcClone->optimizeCacheMode(*_funcObsSet) ;
517
518 // Disable propagation of dirty state flags for observables
519 _dataClone->setDirtyProp(false) ;
520
521 // Disable reading of observables that are not used
522 _dataClone->optimizeReadingWithCaching(*_funcClone, RooArgSet(),requiredExtraObservables()) ;
523}
524
525
526
527////////////////////////////////////////////////////////////////////////////////
528/// Driver function to activate global constant term optimization.
529/// If activated, constant terms are found and cached with the dataset.
530/// The operation mode of cached nodes is set to AClean meaning that
531/// their getVal() call will never result in an evaluate call.
532/// Finally the branches in the dataset that correspond to observables
533/// that are exclusively used in constant terms are disabled as
534/// they serve no more purpose
535
536void RooAbsOptTestStatistic::optimizeConstantTerms(bool activate, bool applyTrackingOpt)
537{
538 if(activate) {
539
540 if (_optimized) {
541 return ;
542 }
543
544 // Trigger create of all object caches now in nodes that have deferred object creation
545 // so that cache contents can be processed immediately
546 _funcClone->getVal(_normSet) ;
547
548
549 // WVE - Patch to allow customization of optimization level per component pdf
550 if (_funcClone->getAttribute("NoOptimizeLevel1")) {
551 coutI(Minimization) << " Optimization customization: Level-1 constant-term optimization prohibited by attribute NoOptimizeLevel1 set on top-level pdf "
552 << _funcClone->ClassName() << "::" << _funcClone->GetName() << std::endl ;
553 return ;
554 }
555 if (_funcClone->getAttribute("NoOptimizeLevel2")) {
556 coutI(Minimization) << " Optimization customization: Level-2 constant-term optimization prohibited by attribute NoOptimizeLevel2 set on top-level pdf "
557 << _funcClone->ClassName() << "::" << _funcClone->GetName() << std::endl ;
559 }
560
561 // Apply tracking optimization here. Default strategy is to track components
562 // of RooAddPdfs and RooRealSumPdfs. If these components are a RooProdPdf
563 // or a RooProduct respectively, track the components of these products instead
564 // of the product term
566
567
568 // Add safety check here - applyTrackingOpt will only be applied if present
569 // dataset is constructed in terms of a RooVectorDataStore
570 if (applyTrackingOpt) {
571 if (!dynamic_cast<RooVectorDataStore*>(_dataClone->store())) {
572 coutW(Optimization) << "RooAbsOptTestStatistic::optimizeConstantTerms(" << GetName()
573 << ") WARNING Cache-and-track optimization (Optimize level 2) is only available for datasets"
574 << " implement in terms of RooVectorDataStore - ignoring this option for current dataset" << std::endl ;
576 }
577 }
578
579 if (applyTrackingOpt) {
581 _funcClone->branchNodeServerList(&branches) ;
582 for (auto arg : branches) {
583 arg->setCacheAndTrackHints(trackNodes);
584 }
585 // Do not set CacheAndTrack on constant expressions
586 trackNodes.remove(*std::unique_ptr<RooAbsCollection>{trackNodes.selectByAttrib("Constant",true)});
587
588 // Set CacheAndTrack flag on all remaining nodes
589 trackNodes.setAttribAll("CacheAndTrack",true) ;
590 }
591
592 // Find all nodes that depend exclusively on constant parameters
593 _cachedNodes.removeAll() ;
594
595 _funcClone->findConstantNodes(*_dataClone->get(),_cachedNodes) ;
596
597 // Cache constant nodes with dataset - also cache entries corresponding to zero-weights in data when using BinnedLikelihood
598 _dataClone->cacheArgs(this,_cachedNodes,_normSet, _skipZeroWeights);
599
600 // Put all cached nodes in AClean value caching mode so that their evaluate() is never called
601 for (auto cacheArg : _cachedNodes) {
602 cacheArg->setOperMode(RooAbsArg::AClean) ;
603 }
604
605 std::unique_ptr<RooAbsCollection> constNodes{_cachedNodes.selectByAttrib("ConstantExpressionCached",true)};
608 if (!constNodes->empty()) {
609 if (constNodes->size()<20) {
610 coutI(Minimization) << " The following expressions have been identified as constant and will be precalculated and cached: " << *constNodes << std::endl ;
611 } else {
612 coutI(Minimization) << " A total of " << constNodes->size() << " expressions have been identified as constant and will be precalculated and cached." << std::endl ;
613 }
614 }
615 if (!actualTrackNodes.empty()) {
616 if (actualTrackNodes.size()<20) {
617 coutI(Minimization) << " The following expressions will be evaluated in cache-and-track mode: " << actualTrackNodes << std::endl ;
618 } else {
619 coutI(Minimization) << " A total of " << constNodes->size() << " expressions will be evaluated in cache-and-track-mode." << std::endl ;
620 }
621 }
622
623 // Disable reading of observables that are no longer used
624 _dataClone->optimizeReadingWithCaching(*_funcClone, _cachedNodes,requiredExtraObservables()) ;
625
626 _optimized = true ;
627
628 } else {
629
630 // Delete the cache
631 _dataClone->resetCache() ;
632
633 // Reactivate all tree branches
634 _dataClone->setArgStatus(*_dataClone->get(),true) ;
635
636 // Reset all nodes to ADirty
637 optimizeCaching() ;
638
639 // Disable propagation of dirty state flags for observables
640 _dataClone->setDirtyProp(false) ;
641
642 _cachedNodes.removeAll() ;
643
644
645 _optimized = false ;
646 }
647}
648
649
650
651////////////////////////////////////////////////////////////////////////////////
652/// Change dataset that is used to given one. If cloneData is true, a clone of
653/// in the input dataset is made. If the test statistic was constructed with
654/// a range specification on the data, the cloneData argument is ignored and
655/// the data is always cloned.
656bool RooAbsOptTestStatistic::setDataSlave(RooAbsData& indata, bool cloneData, bool ownNewData)
657{
658
659 if (operMode()==SimMaster) {
660 //cout << "ROATS::setDataSlave() ERROR this is SimMaster _funcClone = " << _funcClone << std::endl ;
661 return false ;
662 }
663
664 //cout << "ROATS::setDataSlave() new dataset size = " << indata.numEntries() << std::endl ;
665 //indata.Print("v") ;
666
667
668 // If the current dataset is owned, transfer the ownership to unique pointer
669 // that will get out of scope at the end of this function. We can't delete it
670 // right now, because there might be global observables in the model that
671 // first need to be redirected to the new dataset with a later call to
672 // RooAbsArg::recursiveRedirectServers.
673 std::unique_ptr<RooAbsData> oldOwnedData;
674 if (_ownData) {
676 _dataClone = nullptr ;
677 }
678
679 if (!cloneData && !_rangeName.empty()) {
680 coutW(InputArguments) << "RooAbsOptTestStatistic::setData(" << GetName() << ") WARNING: test statistic was constructed with range selection on data, "
681 << "ignoring request to _not_ clone the input dataset" << std::endl ;
682 cloneData = true ;
683 }
684
685 if (cloneData) {
686 // Cloning input dataset
687 _dataClone = std::unique_ptr<RooAbsData>{indata.reduce(RooFit::SelectVars(*indata.get()),RooFit::CutRange(_rangeName.c_str()))}.release();
688 _ownData = true ;
689
690 } else {
691
692 // Taking input dataset
693 _dataClone = &indata ;
695
696 }
697
698 // Attach function clone to dataset
699 _dataClone->attachBuffers(*_funcObsSet) ;
700 _dataClone->setDirtyProp(false) ;
701 _data = _dataClone ;
702
703 // ReCache constant nodes with dataset
704 if (!_cachedNodes.empty()) {
705 _dataClone->cacheArgs(this,_cachedNodes,_normSet, _skipZeroWeights);
706 }
707
708 // Adjust internal event count
709 setEventCount(indata.numEntries()) ;
710
711 setValueDirty() ;
712
713 // It would be unusual if the global observables are used in the likelihood
714 // outside of the constraint terms, but if they are we have to be consistent
715 // and also redirect them to the snapshots in the dataset if appropriate.
716 if(_takeGlobalObservablesFromData && _data->getGlobalObservables()) {
717 recursiveRedirectServers(*_data->getGlobalObservables()) ;
718 }
719
720 return true ;
721}
722
723
724
725
726////////////////////////////////////////////////////////////////////////////////
727
728RooAbsData& RooAbsOptTestStatistic::data()
729{
730 if (_sealed) {
731 bool notice = (sealNotice() && strlen(sealNotice())) ;
732 coutW(ObjectHandling) << "RooAbsOptTestStatistic::data(" << GetName()
733 << ") WARNING: object sealed by creator - access to data is not permitted: "
734 << (notice?sealNotice():"<no user notice>") << std::endl ;
735 static RooDataSet dummy ("dummy","dummy",RooArgSet()) ;
736 return dummy ;
737 }
738 return *_dataClone ;
739}
740
741
742////////////////////////////////////////////////////////////////////////////////
743
744const RooAbsData& RooAbsOptTestStatistic::data() const
745{
746 if (_sealed) {
747 bool notice = (sealNotice() && strlen(sealNotice())) ;
748 coutW(ObjectHandling) << "RooAbsOptTestStatistic::data(" << GetName()
749 << ") WARNING: object sealed by creator - access to data is not permitted: "
750 << (notice?sealNotice():"<no user notice>") << std::endl ;
751 static RooDataSet dummy ("dummy","dummy",RooArgSet()) ;
752 return dummy ;
753 }
754 return *_dataClone ;
755}
756
757
758////////////////////////////////////////////////////////////////////////////////
759/// Inspect PDF to find out if we are doing a binned fit to a 1-dimensional unbinned PDF.
760/// If this is the case, enable finer sampling of bins by wrapping PDF into a RooBinSamplingPdf.
761/// The member _integrateBinsPrecision decides how we act:
762/// - < 0: Don't do anything.
763/// - = 0: Only enable feature if fitting unbinned PDF to RooDataHist.
764/// - > 0: Enable as requested.
765void RooAbsOptTestStatistic::setUpBinSampling() {
766
767 auto& pdf = static_cast<RooAbsPdf&>(*_funcClone);
769 newPdf->addOwnedComponents(*_funcClone);
770 _funcClone = newPdf.release();
771 }
772
773}
774
775
776/// Returns a suffix string that is unique for RooAbsOptTestStatistic
777/// instances that don't share the same cloned input data object.
778const char* RooAbsOptTestStatistic::cacheUniqueSuffix() const {
779 return Form("_%lx", _dataClone->uniqueId().value()) ;
780}
781
782
783void RooAbsOptTestStatistic::runRecalculateCache(std::size_t firstEvent, std::size_t lastEvent, std::size_t stepSize) const
784{
785 _dataClone->store()->recalculateCache(_projDeps, firstEvent, lastEvent, stepSize, _skipZeroWeights);
786}
787
788/// \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:59
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:146
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2495
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:2338