Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooNLLVar.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 RooNLLVar.cxx
21\class RooNLLVar
22\ingroup Roofitcore
23
24Implements a -log(likelihood) calculation from a dataset
25and a PDF. The NLL is calculated as
26\f[
27 \sum_\mathrm{data} -\log( \mathrm{pdf}(x_\mathrm{data}))
28\f]
29In extended mode, a
30\f$ N_\mathrm{expect} - N_\mathrm{observed}*log(N_\mathrm{expect}) \f$ term is added.
31**/
32
33#include "RooNLLVar.h"
34
35#include <RooAbsData.h>
36#include <RooAbsDataStore.h>
37#include <RooAbsPdf.h>
38#include <RooCmdConfig.h>
39#include <RooDataHist.h>
40#include <RooHistPdf.h>
41#include <RooMsgService.h>
42#include <RooNaNPacker.h>
43#include <RooProdPdf.h>
44#include "RooRealMPFE.h"
45#include <RooRealSumPdf.h>
46#include <RooRealVar.h>
47
48#include "TMath.h"
49#include "Math/Util.h"
50
51#include <algorithm>
52
53RooNLLVar::~RooNLLVar() {}
54
55
56////////////////////////////////////////////////////////////////////////////////
57/// Construct likelihood from given p.d.f and (binned or unbinned dataset)
58/// For internal use.
59
60RooNLLVar::RooNLLVar(const char *name, const char *title, RooAbsPdf& pdf, RooAbsData& indata,
61 bool extended, RooAbsTestStatistic::Configuration const& cfg) :
62 RooNLLVar{name, title, pdf, indata, RooArgSet(), extended, cfg} {}
63
64
65////////////////////////////////////////////////////////////////////////////////
66/// Construct likelihood from given p.d.f and (binned or unbinned dataset)
67/// For internal use.
68
69RooNLLVar::RooNLLVar(const char *name, const char *title, RooAbsPdf &pdf, RooAbsData &indata, const RooArgSet &projDeps,
70 bool extended, RooAbsTestStatistic::Configuration const &cfg)
71 : RooAbsOptTestStatistic(name, title, pdf, indata, projDeps, cfg),
72 _extended(extended),
74{
75 // If binned likelihood flag is set, pdf is a RooRealSumPdf representing a yield vector
76 // for a binned likelihood calculation
77
78 // Retrieve and cache bin widths needed to convert un-normalized binnedPdf values back to yields
79 if (_binnedPdf) {
80
81 // The Active label will disable pdf integral calculations
82 _binnedPdf->setAttribute("BinnedLikelihoodActive") ;
83
84 RooArgSet obs;
85 _funcClone->getObservables(_dataClone->get(), obs);
86 if (obs.size()!=1) {
87 _binnedPdf = nullptr;
88 } else {
89 auto* var = static_cast<RooRealVar*>(obs.first());
90 std::unique_ptr<std::list<double>> boundaries{_binnedPdf->binBoundaries(*var,var->getMin(),var->getMax())};
91 auto biter = boundaries->begin() ;
92 _binw.reserve(boundaries->size()-1) ;
93 double lastBound = (*biter) ;
94 ++biter ;
95 while (biter!=boundaries->end()) {
96 _binw.push_back((*biter) - lastBound);
97 lastBound = (*biter) ;
98 ++biter ;
99 }
100 }
101 }
102}
103
104
105
106////////////////////////////////////////////////////////////////////////////////
107/// Copy constructor
108
109RooNLLVar::RooNLLVar(const RooNLLVar& other, const char* name) :
110 RooAbsOptTestStatistic(other,name),
111 _extended(other._extended),
114 _binw(other._binw),
116{
117}
118
119
120////////////////////////////////////////////////////////////////////////////////
121/// Create a test statistic using several properties of the current instance. This is used to duplicate
122/// the test statistic in multi-processing scenarios.
123RooAbsTestStatistic* RooNLLVar::create(const char *name, const char *title, RooAbsReal& pdf, RooAbsData& adata,
124 const RooArgSet& projDeps, RooAbsTestStatistic::Configuration const& cfg) {
125 RooAbsPdf & thePdf = dynamic_cast<RooAbsPdf&>(pdf);
126 // check if pdf can be extended
127 bool extendedPdf = _extended && thePdf.canBeExtended();
128
129 auto testStat = new RooNLLVar(name, title, thePdf, adata, projDeps, extendedPdf, cfg);
130 return testStat;
131}
132
133
134////////////////////////////////////////////////////////////////////////////////
135
136void RooNLLVar::applyWeightSquared(bool flag)
137{
138 if (_gofOpMode==Slave) {
139 if (flag != _weightSq) {
140 _weightSq = flag;
141 std::swap(_offset, _offsetSaveW2);
142 }
143 setValueDirty();
144 } else if ( _gofOpMode==MPMaster) {
145 for (int i=0 ; i<_nCPU ; i++)
147 } else if ( _gofOpMode==SimMaster) {
148 for(auto& gof : _gofArray)
149 static_cast<RooNLLVar&>(*gof).applyWeightSquared(flag);
150 }
151}
152
153
154////////////////////////////////////////////////////////////////////////////////
155/// Calculate and return likelihood on subset of data.
156/// \param[in] firstEvent First event to be processed.
157/// \param[in] lastEvent First event not to be processed, any more.
158/// \param[in] stepSize Steps between events.
159/// \note For batch computations, the step size **must** be one.
160///
161/// If this an extended likelihood, the extended term is added to the return likelihood
162/// in the batch that encounters the event with index 0.
163
164double RooNLLVar::evaluatePartition(std::size_t firstEvent, std::size_t lastEvent, std::size_t stepSize) const
165{
166 // Throughout the calculation, we use Kahan's algorithm for summing to
167 // prevent loss of precision - this is a factor four more expensive than
168 // straight addition, but since evaluating the PDF is usually much more
169 // expensive than that, we tolerate the additional cost...
171 double sumWeight{0.0};
172
173 auto * pdfClone = static_cast<RooAbsPdf*>(_funcClone);
174
175
176 // If pdf is marked as binned - do a binned likelihood calculation here (sum of log-Poisson for each bin)
177 if (_binnedPdf) {
179 for (auto i=firstEvent ; i<lastEvent ; i+=stepSize) {
180
181 _dataClone->get(i) ;
182
183 double eventWeight = _dataClone->weight();
184
185
186 // Calculate log(Poisson(N|mu) for this bin
187 double N = eventWeight ;
188 double mu = _binnedPdf->getVal()*_binw[i] ;
189 //cout << "RooNLLVar::binnedL(" << GetName() << ") N=" << N << " mu = " << mu << std::endl ;
190
191 if (mu<=0 && N>0) {
192
193 // Catch error condition: data present where zero events are predicted
194 logEvalError(Form("Observed %f events in bin %lu with zero event yield",N,(unsigned long)i)) ;
195
196 } else if (std::abs(mu)<1e-10 && std::abs(N)<1e-10) {
197
198 // Special handling of this case since log(Poisson(0,0)=0 but can't be calculated with usual log-formula
199 // since log(mu)=0. No update of result is required since term=0.
200
201 } else {
202
203 double term = 0.0;
204 if(_doBinOffset) {
205 term -= -mu + N + N * (std::log(mu) - std::log(N));
206 } else {
207 term -= -mu + N * std::log(mu) - TMath::LnGamma(N+1);
208 }
209 result += term;
210 sumWeightKahanSum += eventWeight;
211
212 }
213 }
214
216
217 } else { //unbinned PDF
218
220
221 // include the extended maximum likelihood term, if requested
222 if(_extended && _setNum==_extSet) {
223 result += pdfClone->extendedTerm(*_dataClone, _weightSq, _doBinOffset);
224 }
225 } //unbinned PDF
226
227
228 // If part of simultaneous PDF normalize probability over
229 // number of simultaneous PDFs: -sum(log(p/n)) = -sum(log(p)) + N*log(n)
230 // If we do bin-by bin offsetting, we don't do this because it cancels out
231 if (!_doBinOffset && _simCount>1) {
232 result += sumWeight * std::log(static_cast<double>(_simCount));
233 }
234
235
236 // At the end of the first full calculation, wire the caches
237 if (_first) {
238 _first = false ;
239 _funcClone->wireAllCaches() ;
240 }
241
242
243 // Check if value offset flag is set.
244 if (_doOffset) {
245
246 // If no offset is stored enable this feature now
247 if (_offset.Sum() == 0 && _offset.Carry() == 0 && (result.Sum() != 0 || result.Carry() != 0)) {
248 coutI(Minimization) << "RooNLLVar::evaluatePartition(" << GetName() << ") first = "<< firstEvent << " last = " << lastEvent << " Likelihood offset now set to " << result.Sum() << std::endl ;
249 _offset = result ;
250 }
251
252 // Subtract offset
253 result -= _offset;
254 }
255
256 _evalCarry = result.Carry();
257 return result.Sum() ;
258}
259
260RooNLLVar::ComputeResult RooNLLVar::computeScalar(std::size_t stepSize, std::size_t firstEvent, std::size_t lastEvent) const {
261 auto pdfClone = static_cast<const RooAbsPdf*>(_funcClone);
263}
264
265RooNLLVar::ComputeResult RooNLLVar::computeScalarFunc(const RooAbsPdf *pdfClone, RooAbsData *dataClone,
266 RooArgSet *normSet, bool weightSq, std::size_t stepSize,
267 std::size_t firstEvent, std::size_t lastEvent, RooAbsPdf const* offsetPdf)
268{
272
273 for (auto i=firstEvent; i<lastEvent; i+=stepSize) {
274 dataClone->get(i) ;
275
276 double weight = dataClone->weight(); //FIXME
277
278 if (0. == weight * weight) continue ;
279 if (weightSq) weight = dataClone->weightSquared() ;
280
281 double logProba = pdfClone->getLogVal(normSet);
282
283 if(offsetPdf) {
284 logProba -= offsetPdf->getLogVal(normSet);
285 }
286
287 const double term = -weight * logProba;
288
289 kahanWeight.Add(weight);
290 kahanProb.Add(term);
291 packedNaN.accumulate(term);
292 }
293
294 if (packedNaN.getPayload() != 0.) {
295 // Some events with evaluation errors. Return "badness" of errors.
296 return {ROOT::Math::KahanSum<double>{packedNaN.getNaNWithPayload()}, kahanWeight.Sum()};
297 }
298
299 return {kahanProb, kahanWeight.Sum()};
300}
301
302bool RooNLLVar::setDataSlave(RooAbsData &indata, bool cloneData, bool ownNewData)
303{
304 bool ret = RooAbsOptTestStatistic::setDataSlave(indata, cloneData, ownNewData);
305 // To re-create the data template pdf if necessary
306 _offsetPdf.reset();
308 return ret;
309}
310
311void RooNLLVar::enableBinOffsetting(bool flag)
312{
313 if (!_init) {
314 initialize();
315 }
316
318
319 // If this is a "master" that delegates the actual work to "slaves", the
320 // _offsetPdf will not be reset.
321 bool needsResetting = true;
322
323 switch (operMode()) {
324 case Slave: break;
325 case SimMaster: {
326 for (auto &gof : _gofArray) {
327 static_cast<RooNLLVar &>(*gof).enableBinOffsetting(flag);
328 }
329 needsResetting = false;
330 break;
331 }
332 case MPMaster: {
333 for (int i = 0; i < _nCPU; ++i) {
334 static_cast<RooNLLVar &>(_mpfeArray[i]->arg()).enableBinOffsetting(flag);
335 }
336 needsResetting = false;
337 break;
338 }
339 }
340
341 if (!needsResetting)
342 return;
343
344 if (flag && !_offsetPdf) {
345 std::string name = std::string{GetName()} + "_offsetPdf";
346 std::unique_ptr<RooDataHist> dataTemplate;
347 if (auto dh = dynamic_cast<RooDataHist *>(_dataClone)) {
348 dataTemplate = std::make_unique<RooDataHist>(*dh);
349 } else {
350 dataTemplate = std::unique_ptr<RooDataHist>(static_cast<RooDataSet const &>(*_dataClone).binnedClone());
351 }
352 _offsetPdf = std::make_unique<RooHistPdf>(name.c_str(), name.c_str(), *_funcObsSet, std::move(dataTemplate));
353 _offsetPdf->setOperMode(ADirty);
354 }
355 setValueDirty();
356}
357
358/// \endcond
#define e(i)
Definition RSha256.hxx:103
#define coutI(a)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define N
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
char name[80]
Definition TGX11.cxx:142
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2571
The Kahan summation is a compensated summation algorithm, which significantly reduces numerical error...
Definition Util.h:141
const_iterator begin() const
const_iterator end() const
Storage_t::size_type size() const
RooAbsArg * first() const
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:55
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
Container class to hold N-dimensional binned data.
Definition RooDataHist.h:40
Container class to hold unbinned data.
Definition RooDataSet.h:32
RooFit::OwningPtr< RooDataHist > binnedClone(const char *newName=nullptr, const char *newTitle=nullptr) const
Return binned clone of this dataset.
Implements a PDF constructed from a sum of functions:
Variable that can be changed from the outside.
Definition RooRealVar.h:37
void initialize(typename Architecture_t::Matrix_t &A, EInitialization m)
Definition Functions.h:282
Double_t LnGamma(Double_t z)
Computation of ln[gamma(z)] for all z.
Definition TMath.cxx:509
Little struct that can pack a float into the unused bits of the mantissa of a NaN double.