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 } else {
230 _dataClone = static_cast<RooAbsData*>(indata.Clone()) ;
231 }
232 _ownData = true ;
233
234
235 // ******************************************************************
236 // *** PART 3 *** Make adjustments for fit ranges, if specified *
237 // ******************************************************************
238
239 std::unique_ptr<RooArgSet> origObsSet( real.getObservables(indata) );
240 if (rangeName && strlen(rangeName)) {
241 cxcoutI(Fitting) << "RooAbsOptTestStatistic::ctor(" << GetName() << ") constructing test statistic for sub-range named " << rangeName << std::endl ;
242
243 if(auto pdfClone = dynamic_cast<RooAbsPdf*>(_funcClone)) {
244 pdfClone->setNormRange(rangeName);
245 }
246
247 // Print warnings if the requested ranges are not available for the observable
248 for (const auto arg : *_funcObsSet) {
249
250 if (auto realObs = dynamic_cast<RooRealVar*>(arg)) {
251
252 auto tokens = ROOT::Split(rangeName, ",");
253 for(std::string const& token : tokens) {
254 if(!realObs->hasRange(token.c_str())) {
255 std::stringstream errMsg;
256 errMsg << "The observable \"" << realObs->GetName() << "\" doesn't define the requested range \""
257 << token << "\". Replacing it with the default range." << std::endl;
258 coutI(Fitting) << errMsg.str() << std::endl;
259 }
260 }
261 }
262 }
263 }
264
265
266 // ******************************************************************
267 // *** PART 3.2 *** Binned fits *
268 // ******************************************************************
269
271
272
273 // Fix RooAddPdf coefficients to original normalization range
274 if (rangeName && strlen(rangeName)) {
275
276 // WVE Remove projected dependents from normalization
277 _funcClone->fixAddCoefNormalization(*_dataClone->get(),false) ;
278
280 cxcoutI(Fitting) << "RooAbsOptTestStatistic::ctor(" << GetName()
281 << ") fixing interpretation of coefficients of any RooAddPdf component to range " << addCoefRangeName << std::endl ;
282 _funcClone->fixAddCoefRange(addCoefRangeName,false) ;
283 }
284 }
285
286
287 // This is deferred from part 2 - but must happen after part 3 - otherwise invalid bins cannot be properly marked in cacheValidEntries
288 _dataClone->attachBuffers(*_funcObsSet) ;
289 setEventCount(_dataClone->numEntries()) ;
290
291
292
293
294 // *********************************************************************
295 // *** PART 4 *** Adjust normalization range for projected observables *
296 // *********************************************************************
297
298 // Remove projected dependents from normalization set
299 if (!projDeps.empty()) {
300
301 _projDeps = new RooArgSet;
302 projDeps.snapshot(*_projDeps, false) ;
303
304 //RooArgSet* tobedel = (RooArgSet*) _normSet->selectCommon(*_projDeps) ;
305 _normSet->remove(*_projDeps,true,true) ;
306
307 // Mark all projected dependents as such
309 _funcObsSet->selectCommon(*_projDeps, projDataDeps);
310 projDataDeps.setAttribAll("projectedDependent") ;
311 }
312
313
314 coutI(Optimization) << "RooAbsOptTestStatistic::ctor(" << GetName() << ") optimizing internal clone of p.d.f for likelihood evaluation."
315 << "Lazy evaluation and associated change tracking will disabled for all nodes that depend on observables" << std::endl ;
316
317
318 // *********************************************************************
319 // *** PART 4 *** Finalization and activation of optimization *
320 // *********************************************************************
321
322 // Redirect pointers of base class to clone
323 _func = _funcClone ;
324 _data = _dataClone ;
325
326 _funcClone->getVal(_normSet) ;
327
328 optimizeCaching() ;
329
330 // It would be unusual if the global observables are used in the likelihood
331 // outside of the constraint terms, but if they are we have to be consistent
332 // and also redirect them to the snapshots in the dataset if appropriate.
333 if(_takeGlobalObservablesFromData && _data->getGlobalObservables()) {
334 recursiveRedirectServers(*_data->getGlobalObservables()) ;
335 }
336
337}
338
339
340////////////////////////////////////////////////////////////////////////////////
341/// Destructor
342
343RooAbsOptTestStatistic::~RooAbsOptTestStatistic()
344{
345 if (operMode()==Slave) {
346 delete _funcClone ;
347 delete _funcObsSet ;
348 if (_projDeps) {
349 delete _projDeps ;
350 }
351 if (_ownData) {
352 delete _dataClone ;
353 }
354 }
355 delete _normSet ;
356}
357
358
359
360////////////////////////////////////////////////////////////////////////////////
361/// Method to combined test statistic results calculated into partitions into
362/// the global result. This default implementation adds the partition return
363/// values
364
365double RooAbsOptTestStatistic::combinedValue(RooAbsReal** array, Int_t n) const
366{
367 // Default implementation returns sum of components
368 double sum(0);
369 double carry(0);
370 for (Int_t i = 0; i < n; ++i) {
371 double y = array[i]->getValV();
372 carry += reinterpret_cast<RooAbsOptTestStatistic*>(array[i])->getCarry();
373 y -= carry;
374 const double t = sum + y;
375 carry = (t - sum) - y;
376 sum = t;
377 }
378 _evalCarry = carry;
379 return sum ;
380}
381
382
383
384////////////////////////////////////////////////////////////////////////////////
385/// Catch server redirect calls and forward to internal clone of function
386
387bool RooAbsOptTestStatistic::redirectServersHook(const RooAbsCollection& newServerList, bool mustReplaceAll, bool nameChange, bool isRecursive)
388{
389 RooAbsTestStatistic::redirectServersHook(newServerList,mustReplaceAll,nameChange,isRecursive) ;
390 if (operMode()!=Slave) return false ;
391 bool ret = _funcClone->recursiveRedirectServers(newServerList,false,nameChange) ;
393}
394
395
396
397////////////////////////////////////////////////////////////////////////////////
398/// Catch print hook function and forward to function clone
399
400void RooAbsOptTestStatistic::printCompactTreeHook(ostream& os, const char* indent)
401{
402 RooAbsTestStatistic::printCompactTreeHook(os,indent) ;
403 if (operMode()!=Slave) return ;
405 indent2 += "opt >>" ;
406 _funcClone->printCompactTree(os,indent2.Data()) ;
407 os << indent2 << " dataset clone = " << _dataClone << " first obs = " << _dataClone->get()->first() << std::endl ;
408}
409
410
411
412////////////////////////////////////////////////////////////////////////////////
413/// Driver function to propagate constant term optimizations in test statistic.
414/// If code Activate is sent, constant term optimization will be executed.
415/// If code Deactivate is sent, any existing constant term optimizations will
416/// be abandoned. If codes ConfigChange or ValueChange are sent, any existing
417/// constant term optimizations will be redone.
418
419void RooAbsOptTestStatistic::constOptimizeTestStatistic(ConstOpCode opcode, bool doAlsoTrackingOpt)
420{
421 static bool hasWarned = false;
422 if (!hasWarned) {
423 std::stringstream ss;
424 ss << "Deprecated constant term optimization detected,\n"
425 << "enabled via RooFit::Optimize() or RooMinimizer::optimizeConst():\n"
426 << " This functionality only affects the legacy evaluation backend.\n"
427 << " The vectorized CPU backend performs const term optimization automatically.\n"
428 << " The option is ignored and will be removed in ROOT 6.42.\n"
429 << " Should your fit not be possible without the legacy backend, please open a GitHub issue.\n";
430 oocoutW(static_cast<RooAbsArg *>(nullptr), InputArguments) << ss.str() << std::endl;
431 hasWarned = true;
432 }
433
434 RooAbsTestStatistic::constOptimizeTestStatistic(opcode,doAlsoTrackingOpt);
435 if (operMode()!=Slave) return ;
436
437 if (_dataClone->hasFilledCache() && _dataClone->store()->cacheOwner()!=this) {
438 if (opcode==Activate) {
439 cxcoutW(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
440 << ") dataset cache is owned by another object, no constant term optimization can be applied" << std::endl ;
441 }
442 return ;
443 }
444
445 if (!allowFunctionCache()) {
446 if (opcode==Activate) {
447 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
448 << ") function caching prohibited by test statistic, no constant term optimization is applied" << std::endl ;
449 }
450 return ;
451 }
452
453 if (_dataClone->hasFilledCache() && opcode==Activate) {
454 opcode=ValueChange ;
455 }
456
457 switch(opcode) {
458 case Activate:
459 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
460 << ") optimizing evaluation of test statistic by finding all nodes in p.d.f that depend exclusively"
461 << " on observables and constant parameters and precalculating their values" << std::endl ;
463 break ;
464
465 case DeActivate:
466 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
467 << ") deactivating optimization of constant terms in test statistic" << std::endl ;
468 optimizeConstantTerms(false) ;
469 break ;
470
471 case ConfigChange:
472 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
473 << ") one ore more parameter were changed from constant to floating or vice versa, "
474 << "re-evaluating constant term optimization" << std::endl ;
475 optimizeConstantTerms(false) ;
477 break ;
478
479 case ValueChange:
480 cxcoutI(Optimization) << "RooAbsOptTestStatistic::constOptimize(" << GetName()
481 << ") the value of one ore more constant parameter were changed re-evaluating constant term optimization" << std::endl ;
482 // Request a forcible cache update of all cached nodes
483 _dataClone->store()->forceCacheUpdate() ;
484
485 break ;
486 }
487
488}
489
490
491
492////////////////////////////////////////////////////////////////////////////////
493/// This method changes the value caching logic for all nodes that depends on any of the observables
494/// as defined by the given dataset. When evaluating a test statistic constructed from the RooAbsReal
495/// with a dataset the observables are guaranteed to change with every call, thus there is no point
496/// in tracking these changes which result in a net overhead. Thus for observable-dependent nodes,
497/// the evaluation mechanism is changed from being dependent on a 'valueDirty' flag to guaranteed evaluation.
498/// On the dataset side, the observables objects are modified to no longer send valueDirty messages
499/// to their client
500
501void RooAbsOptTestStatistic::optimizeCaching()
502{
503 // Trigger create of all object caches now in nodes that have deferred object creation
504 // so that cache contents can be processed immediately
505 _funcClone->getVal(_normSet) ;
506
507 // Set value caching mode for all nodes that depend on any of the observables to ADirty
508 _funcClone->optimizeCacheMode(*_funcObsSet) ;
509
510 // Disable propagation of dirty state flags for observables
511 _dataClone->setDirtyProp(false) ;
512
513 // Disable reading of observables that are not used
514 _dataClone->optimizeReadingWithCaching(*_funcClone, RooArgSet(),requiredExtraObservables()) ;
515}
516
517
518
519////////////////////////////////////////////////////////////////////////////////
520/// Driver function to activate global constant term optimization.
521/// If activated, constant terms are found and cached with the dataset.
522/// The operation mode of cached nodes is set to AClean meaning that
523/// their getVal() call will never result in an evaluate call.
524/// Finally the branches in the dataset that correspond to observables
525/// that are exclusively used in constant terms are disabled as
526/// they serve no more purpose
527
528void RooAbsOptTestStatistic::optimizeConstantTerms(bool activate, bool applyTrackingOpt)
529{
530 if(activate) {
531
532 if (_optimized) {
533 return ;
534 }
535
536 // Trigger create of all object caches now in nodes that have deferred object creation
537 // so that cache contents can be processed immediately
538 _funcClone->getVal(_normSet) ;
539
540
541 // WVE - Patch to allow customization of optimization level per component pdf
542 if (_funcClone->getAttribute("NoOptimizeLevel1")) {
543 coutI(Minimization) << " Optimization customization: Level-1 constant-term optimization prohibited by attribute NoOptimizeLevel1 set on top-level pdf "
544 << _funcClone->ClassName() << "::" << _funcClone->GetName() << std::endl ;
545 return ;
546 }
547 if (_funcClone->getAttribute("NoOptimizeLevel2")) {
548 coutI(Minimization) << " Optimization customization: Level-2 constant-term optimization prohibited by attribute NoOptimizeLevel2 set on top-level pdf "
549 << _funcClone->ClassName() << "::" << _funcClone->GetName() << std::endl ;
551 }
552
553 // Apply tracking optimization here. Default strategy is to track components
554 // of RooAddPdfs and RooRealSumPdfs. If these components are a RooProdPdf
555 // or a RooProduct respectively, track the components of these products instead
556 // of the product term
558
559
560 // Add safety check here - applyTrackingOpt will only be applied if present
561 // dataset is constructed in terms of a RooVectorDataStore
562 if (applyTrackingOpt) {
563 if (!dynamic_cast<RooVectorDataStore*>(_dataClone->store())) {
564 coutW(Optimization) << "RooAbsOptTestStatistic::optimizeConstantTerms(" << GetName()
565 << ") WARNING Cache-and-track optimization (Optimize level 2) is only available for datasets"
566 << " implement in terms of RooVectorDataStore - ignoring this option for current dataset" << std::endl ;
568 }
569 }
570
571 if (applyTrackingOpt) {
573 _funcClone->branchNodeServerList(&branches) ;
574 for (auto arg : branches) {
575 arg->setCacheAndTrackHints(trackNodes);
576 }
577 // Do not set CacheAndTrack on constant expressions
578 trackNodes.remove(*std::unique_ptr<RooAbsCollection>{trackNodes.selectByAttrib("Constant",true)});
579
580 // Set CacheAndTrack flag on all remaining nodes
581 trackNodes.setAttribAll("CacheAndTrack",true) ;
582 }
583
584 // Find all nodes that depend exclusively on constant parameters
585 _cachedNodes.removeAll() ;
586
587 _funcClone->findConstantNodes(*_dataClone->get(),_cachedNodes) ;
588
589 // Cache constant nodes with dataset - also cache entries corresponding to zero-weights in data when using BinnedLikelihood
590 _dataClone->cacheArgs(this,_cachedNodes,_normSet, _skipZeroWeights);
591
592 // Put all cached nodes in AClean value caching mode so that their evaluate() is never called
593 for (auto cacheArg : _cachedNodes) {
594 cacheArg->setOperMode(RooAbsArg::AClean) ;
595 }
596
597 std::unique_ptr<RooAbsCollection> constNodes{_cachedNodes.selectByAttrib("ConstantExpressionCached",true)};
600 if (!constNodes->empty()) {
601 if (constNodes->size()<20) {
602 coutI(Minimization) << " The following expressions have been identified as constant and will be precalculated and cached: " << *constNodes << std::endl ;
603 } else {
604 coutI(Minimization) << " A total of " << constNodes->size() << " expressions have been identified as constant and will be precalculated and cached." << std::endl ;
605 }
606 }
607 if (!actualTrackNodes.empty()) {
608 if (actualTrackNodes.size()<20) {
609 coutI(Minimization) << " The following expressions will be evaluated in cache-and-track mode: " << actualTrackNodes << std::endl ;
610 } else {
611 coutI(Minimization) << " A total of " << constNodes->size() << " expressions will be evaluated in cache-and-track-mode." << std::endl ;
612 }
613 }
614
615 // Disable reading of observables that are no longer used
616 _dataClone->optimizeReadingWithCaching(*_funcClone, _cachedNodes,requiredExtraObservables()) ;
617
618 _optimized = true ;
619
620 } else {
621
622 // Delete the cache
623 _dataClone->resetCache() ;
624
625 // Reactivate all tree branches
626 _dataClone->setArgStatus(*_dataClone->get(),true) ;
627
628 // Reset all nodes to ADirty
629 optimizeCaching() ;
630
631 // Disable propagation of dirty state flags for observables
632 _dataClone->setDirtyProp(false) ;
633
634 _cachedNodes.removeAll() ;
635
636
637 _optimized = false ;
638 }
639}
640
641
642
643////////////////////////////////////////////////////////////////////////////////
644/// Change dataset that is used to given one. If cloneData is true, a clone of
645/// in the input dataset is made. If the test statistic was constructed with
646/// a range specification on the data, the cloneData argument is ignored and
647/// the data is always cloned.
648bool RooAbsOptTestStatistic::setDataSlave(RooAbsData& indata, bool cloneData, bool ownNewData)
649{
650
651 if (operMode()==SimMaster) {
652 return false ;
653 }
654
655
656 // If the current dataset is owned, transfer the ownership to unique pointer
657 // that will get out of scope at the end of this function. We can't delete it
658 // right now, because there might be global observables in the model that
659 // first need to be redirected to the new dataset with a later call to
660 // RooAbsArg::recursiveRedirectServers.
661 std::unique_ptr<RooAbsData> oldOwnedData;
662 if (_ownData) {
664 _dataClone = nullptr ;
665 }
666
667 if (!cloneData && !_rangeName.empty()) {
668 coutW(InputArguments) << "RooAbsOptTestStatistic::setData(" << GetName() << ") WARNING: test statistic was constructed with range selection on data, "
669 << "ignoring request to _not_ clone the input dataset" << std::endl ;
670 cloneData = true ;
671 }
672
673 if (cloneData) {
674 // Cloning input dataset
675 _dataClone = std::unique_ptr<RooAbsData>{indata.reduce(RooFit::SelectVars(*indata.get()),RooFit::CutRange(_rangeName.c_str()))}.release();
676 _ownData = true ;
677
678 } else {
679
680 // Taking input dataset
681 _dataClone = &indata ;
683
684 }
685
686 // Attach function clone to dataset
687 _dataClone->attachBuffers(*_funcObsSet) ;
688 _dataClone->setDirtyProp(false) ;
689 _data = _dataClone ;
690
691 // ReCache constant nodes with dataset
692 if (!_cachedNodes.empty()) {
693 _dataClone->cacheArgs(this,_cachedNodes,_normSet, _skipZeroWeights);
694 }
695
696 // Adjust internal event count
697 setEventCount(indata.numEntries()) ;
698
699 setValueDirty() ;
700
701 // It would be unusual if the global observables are used in the likelihood
702 // outside of the constraint terms, but if they are we have to be consistent
703 // and also redirect them to the snapshots in the dataset if appropriate.
704 if(_takeGlobalObservablesFromData && _data->getGlobalObservables()) {
705 recursiveRedirectServers(*_data->getGlobalObservables()) ;
706 }
707
708 return true ;
709}
710
711
712
713
714////////////////////////////////////////////////////////////////////////////////
715
716RooAbsData& RooAbsOptTestStatistic::data()
717{
718 if (_sealed) {
719 bool notice = (sealNotice() && strlen(sealNotice())) ;
720 coutW(ObjectHandling) << "RooAbsOptTestStatistic::data(" << GetName()
721 << ") WARNING: object sealed by creator - access to data is not permitted: "
722 << (notice?sealNotice():"<no user notice>") << std::endl ;
723 static RooDataSet dummy ("dummy","dummy",RooArgSet()) ;
724 return dummy ;
725 }
726 return *_dataClone ;
727}
728
729
730////////////////////////////////////////////////////////////////////////////////
731
732const RooAbsData& RooAbsOptTestStatistic::data() const
733{
734 if (_sealed) {
735 bool notice = (sealNotice() && strlen(sealNotice())) ;
736 coutW(ObjectHandling) << "RooAbsOptTestStatistic::data(" << GetName()
737 << ") WARNING: object sealed by creator - access to data is not permitted: "
738 << (notice?sealNotice():"<no user notice>") << std::endl ;
739 static RooDataSet dummy ("dummy","dummy",RooArgSet()) ;
740 return dummy ;
741 }
742 return *_dataClone ;
743}
744
745
746////////////////////////////////////////////////////////////////////////////////
747/// Inspect PDF to find out if we are doing a binned fit to a 1-dimensional unbinned PDF.
748/// If this is the case, enable finer sampling of bins by wrapping PDF into a RooBinSamplingPdf.
749/// The member _integrateBinsPrecision decides how we act:
750/// - < 0: Don't do anything.
751/// - = 0: Only enable feature if fitting unbinned PDF to RooDataHist.
752/// - > 0: Enable as requested.
753void RooAbsOptTestStatistic::setUpBinSampling() {
754
755 auto& pdf = static_cast<RooAbsPdf&>(*_funcClone);
757 newPdf->addOwnedComponents(*_funcClone);
758 _funcClone = newPdf.release();
759 }
760
761}
762
763
764/// Returns a suffix string that is unique for RooAbsOptTestStatistic
765/// instances that don't share the same cloned input data object.
766const char* RooAbsOptTestStatistic::cacheUniqueSuffix() const {
767 return Form("_%lx", _dataClone->uniqueId().value()) ;
768}
769
770
771void RooAbsOptTestStatistic::runRecalculateCache(std::size_t firstEvent, std::size_t lastEvent, std::size_t stepSize) const
772{
773 _dataClone->store()->recalculateCache(_projDeps, firstEvent, lastEvent, stepSize, _skipZeroWeights);
774}
775
776/// \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:145
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2496
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