Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooNLLVarNew.cxx
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 * Authors:
4 * Jonas Rembser, CERN 2021
5 * Emmanouil Michalainas, CERN 2021
6 *
7 * Copyright (c) 2021, CERN
8 *
9 * Redistribution and use in source and binary forms,
10 * with or without modification, are permitted according to the terms
11 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
12 */
13
14/**
15\file RooNLLVarNew.cxx
16\class RooNLLVarNew
17\ingroup Roofitcore
18
19This is a simple class designed to produce the nll values needed by the fitter.
20In contrast to the `RooNLLVar` class, any logic except the bare minimum has been
21transfered away to other classes, like the `RooFitDriver`. This class also calls
22functions from `RooBatchCompute` library to provide faster computation times.
23**/
24
25#include "RooNLLVarNew.h"
26
27#include <RooBatchCompute.h>
28#include <RooNaNPacker.h>
29#include <RooConstVar.h>
30#include <RooRealVar.h>
32
33#include <ROOT/StringUtils.hxx>
34
35#include <TClass.h>
36#include <TMath.h>
37#include <Math/Util.h>
38
39#include <numeric>
40#include <stdexcept>
41#include <vector>
42
43using namespace ROOT::Experimental;
44
45// Declare constexpr static members to make them available if odr-used in C++14.
46constexpr const char *RooNLLVarNew::weightVarName;
47constexpr const char *RooNLLVarNew::weightVarNameSumW2;
48
49namespace {
50
51RooArgSet getObs(RooAbsArg const &arg, RooArgSet const &observables)
52{
53 RooArgSet out;
54 arg.getObservables(&observables, out);
55 return out;
56}
57
58// Use RooConstVar for dummies such that they don't get included in getParameters().
59RooConstVar *dummyVar(const char *name)
60{
61 return new RooConstVar(name, name, 1.0);
62}
63
64} // namespace
65
66/** Construct a RooNLLVarNew
67\param name the name
68\param title the title
69\param pdf The pdf for which the nll is computed for
70\param observables The observabes of the pdf
71\param isExtended Set to true if this is an extended fit
72**/
73RooNLLVarNew::RooNLLVarNew(const char *name, const char *title, RooAbsPdf &pdf, RooArgSet const &observables,
74 bool isExtended, RooFit::OffsetMode offsetMode)
75 : RooAbsReal(name, title),
76 _pdf{"pdf", "pdf", this, pdf},
77 _weightVar{"weightVar", "weightVar", this, *dummyVar(weightVarName), true, false, true},
78 _weightSquaredVar{weightVarNameSumW2, weightVarNameSumW2, this, *dummyVar("weightSquardVar"), true, false, true},
79 _binVolumeVar{"binVolumeVar", "binVolumeVar", this, *dummyVar("_bin_volume"), true, false, true},
80 _binnedL{pdf.getAttribute("BinnedLikelihoodActive")}
81{
82 RooArgSet obs{getObs(pdf, observables)};
83
84 // In the "BinnedLikelihoodActiveYields" mode, the pdf values can directly
85 // be interpreted as yields and don't need to be multiplied by the bin
86 // widths. That's why we don't need to even fill them in this case.
87 if (_binnedL && !pdf.getAttribute("BinnedLikelihoodActiveYields")) {
89 }
90
91 if (isExtended && !_binnedL) {
92 std::unique_ptr<RooAbsReal> expectedEvents = pdf.createExpectedEventsFunc(&obs);
93 if (expectedEvents) {
95 std::make_unique<RooTemplateProxy<RooAbsReal>>("expectedEvents", "expectedEvents", this, *expectedEvents);
96 addOwnedComponents(std::move(expectedEvents));
97 }
98 }
99
103}
104
106 : RooAbsReal(other, name),
107 _pdf{"pdf", this, other._pdf},
108 _weightVar{"weightVar", this, other._weightVar},
109 _weightSquaredVar{"weightSquaredVar", this, other._weightSquaredVar},
110 _weightSquared{other._weightSquared},
111 _binnedL{other._binnedL},
112 _doOffset{other._doOffset},
113 _simCount{other._simCount},
114 _prefix{other._prefix},
115 _binw{other._binw}
116{
117 if (other._expectedEvents) {
118 _expectedEvents = std::make_unique<RooTemplateProxy<RooAbsReal>>("expectedEvents", this, *other._expectedEvents);
119 }
120}
121
123{
124 // Check if the bin widths were already filled
125 if (!_binw.empty()) {
126 return;
127 }
128
129 if (observables.size() != 1) {
130 throw std::runtime_error("BinnedPdf optimization only works with a 1D pdf.");
131 } else {
132 auto *var = static_cast<RooRealVar *>(observables.first());
133 std::list<double> *boundaries = pdf.binBoundaries(*var, var->getMin(), var->getMax());
134 std::list<double>::iterator biter = boundaries->begin();
135 _binw.resize(boundaries->size() - 1);
136 double lastBound = (*biter);
137 ++biter;
138 int ibin = 0;
139 while (biter != boundaries->end()) {
140 _binw[ibin] = (*biter) - lastBound;
141 lastBound = (*biter);
142 ibin++;
143 ++biter;
144 }
145 }
146}
147
149{
151 ROOT::Math::KahanSum<double> sumWeightKahanSum{0.0};
152
153 const bool predsAreYields = _binw.empty();
154
155 for (std::size_t i = 0; i < preds.size(); ++i) {
156
157 double eventWeight = weights[i];
158
159 // Calculate log(Poisson(N|mu) for this bin
160 double N = eventWeight;
161 double mu = preds[i];
162 if (!predsAreYields) {
163 mu *= _binw[i];
164 }
165
166 if (mu <= 0 && N > 0) {
167
168 // Catch error condition: data present where zero events are predicted
169 logEvalError(Form("Observed %f events in bin %lu with zero event yield", N, (unsigned long)i));
170
171 } else if (std::abs(mu) < 1e-10 && std::abs(N) < 1e-10) {
172
173 // Special handling of this case since log(Poisson(0,0)=0 but can't be calculated with usual log-formula
174 // since log(mu)=0. No update of result is required since term=0.
175
176 } else {
177
178 result += -1 * (-mu + N * log(mu) - TMath::LnGamma(N + 1));
179 sumWeightKahanSum += eventWeight;
180 }
181 }
182
183 return finalizeResult(result, sumWeightKahanSum.Sum());
184}
185
186/** Compute multiple negative logs of propabilities
187
188\param output An array of doubles where the computation results will be stored
189\param nOut not used
190\note nEvents is the number of events to be processed (the dataMap size)
191\param dataMap A map containing spans with the input data for the computation
192**/
193void RooNLLVarNew::computeBatch(cudaStream_t *stream, double *output, size_t /*nOut*/,
194 RooFit::Detail::DataMap const &dataMap) const
195{
196 RooSpan<const double> weights = dataMap.at(_weightVar);
197 RooSpan<const double> weightsSumW2 = dataMap.at(_weightSquaredVar);
198
199 if (_binnedL) {
200 output[0] = computeBatchBinnedL(dataMap.at(&*_pdf), _weightSquared ? weightsSumW2 : weights);
201 return;
202 }
203
205
206 auto probas = dataMap.at(_pdf);
207
208 _sumWeight =
209 weights.size() == 1 ? weights[0] * probas.size() : dispatch->reduceSum(stream, weights.data(), weights.size());
210 if (_expectedEvents && _weightSquared && _sumWeight2 == 0.0) {
211 _sumWeight2 = weights.size() == 1 ? weightsSumW2[0] * probas.size()
212 : dispatch->reduceSum(stream, weightsSumW2.data(), weightsSumW2.size());
213 }
214
215 auto nllOut = dispatch->reduceNLL(stream, probas, _weightSquared ? weightsSumW2 : weights, weights, _sumWeight,
217
218 if (nllOut.nLargeValues > 0) {
219 oocoutW(&*_pdf, Eval) << "RooAbsPdf::getLogVal(" << _pdf->GetName()
220 << ") WARNING: top-level pdf has unexpectedly large values" << std::endl;
221 }
222 for (std::size_t i = 0; i < nllOut.nNonPositiveValues; ++i) {
223 _pdf->logEvalError("getLogVal() top-level p.d.f not greater than zero");
224 }
225 for (std::size_t i = 0; i < nllOut.nNaNValues; ++i) {
226 _pdf->logEvalError("getLogVal() top-level p.d.f evaluates to NaN");
227 }
228
229 if (_expectedEvents) {
230 RooSpan<const double> expected = dataMap.at(*_expectedEvents);
231 nllOut.nllSum += _pdf->extendedTerm(_sumWeight, expected[0], _weightSquared ? _sumWeight2 : 0.0, _doBinOffset);
232 }
233
234 output[0] = finalizeResult(nllOut.nllSum, _sumWeight);
235}
236
237void RooNLLVarNew::getParametersHook(const RooArgSet * /*nset*/, RooArgSet *params, bool /*stripDisconnected*/) const
238{
239 // strip away the special variables
241}
242
243////////////////////////////////////////////////////////////////////////////////
244/// Sets the prefix for the special variables of this NLL, like weights or bin
245/// volumes.
246/// \param[in] prefix The prefix to add to the observables and weight names.
247void RooNLLVarNew::setPrefix(std::string const &prefix)
248{
249 _prefix = prefix;
250
252}
253
255{
258 _binVolumeVar->SetName((_prefix + "_bin_volume").c_str());
259}
260
261////////////////////////////////////////////////////////////////////////////////
262/// Toggles the weight square correction.
264{
265 _weightSquared = flag;
266}
267
269{
270 _doOffset = flag;
272}
273
275{
276 // If part of simultaneous PDF normalize probability over
277 // number of simultaneous PDFs: -sum(log(p/n)) = -sum(log(p)) + N*log(n)
278 if (_simCount > 1) {
279 result += weightSum * std::log(static_cast<double>(_simCount));
280 }
281
282 // Check if value offset flag is set.
283 if (_doOffset) {
284
285 // If no offset is stored enable this feature now
286 if (_offset.Sum() == 0 && _offset.Carry() == 0 && (result.Sum() != 0 || result.Carry() != 0)) {
287 _offset = result;
288 }
289
290 // Subtract offset
291 if (!RooAbsReal::hideOffset()) {
292 result -= _offset;
293 }
294 }
295 return result.Sum();
296}
#define e(i)
Definition RSha256.hxx:103
#define oocoutW(o, a)
#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:110
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2467
RooTemplateProxy< RooAbsReal > _binVolumeVar
RooTemplateProxy< RooAbsReal > _weightVar
void enableOffsetting(bool) override
void computeBatch(cudaStream_t *, double *output, size_t nOut, RooFit::Detail::DataMap const &) const override
Compute multiple negative logs of propabilities.
void applyWeightSquared(bool flag) override
Toggles the weight square correction.
void getParametersHook(const RooArgSet *nset, RooArgSet *list, bool stripDisconnected) const override
ROOT::Math::KahanSum< double > _offset
! Offset as KahanSum to avoid loss of precision
void setPrefix(std::string const &prefix)
Sets the prefix for the special variables of this NLL, like weights or bin volumes.
void fillBinWidthsFromPdfBoundaries(RooAbsReal const &pdf, RooArgSet const &observables)
RooTemplateProxy< RooAbsPdf > _pdf
void enableBinOffsetting(bool on=true)
RooTemplateProxy< RooAbsReal > _weightSquaredVar
std::unique_ptr< RooTemplateProxy< RooAbsReal > > _expectedEvents
double computeBatchBinnedL(RooSpan< const double > preds, RooSpan< const double > weights) const
std::vector< double > _binw
static constexpr const char * weightVarName
double finalizeResult(ROOT::Math::KahanSum< double > result, double weightSum) const
static constexpr const char * weightVarNameSumW2
The Kahan summation is a compensated summation algorithm, which significantly reduces numerical error...
Definition Util.h:122
T Sum() const
Definition Util.h:240
T Carry() const
Definition Util.h:250
RooAbsArg is the common abstract base class for objects that represent a value and a "shape" in RooFi...
Definition RooAbsArg.h:74
RooFit::OwningPtr< RooArgSet > getObservables(const RooArgSet &set, bool valueOnly=true) const
Given a set of possible observables, return the observables that this PDF depends on.
void SetName(const char *name) override
Set the name of the TNamed.
bool addOwnedComponents(const RooAbsCollection &comps)
Take ownership of the contents of 'comps'.
bool getAttribute(const Text_t *name) const
Check if a named attribute is set. By default, all attributes are unset.
virtual bool remove(const RooAbsArg &var, bool silent=false, bool matchByNameOnly=false)
Remove the specified argument from our list.
Storage_t::size_type size() const
RooAbsArg * first() const
virtual std::unique_ptr< RooAbsReal > createExpectedEventsFunc(const RooArgSet *nset) const
Returns an object that represents the expected number of events for a given normalization set,...
double extendedTerm(double sumEntries, double expected, double sumEntriesW2=0.0, bool doOffset=false) const
RooAbsReal is the common abstract base class for objects that represent a real value and implements f...
Definition RooAbsReal.h:62
virtual std::list< double > * binBoundaries(RooAbsRealLValue &obs, double xlo, double xhi) const
Retrieve bin boundaries if this distribution is binned in obs.
static bool hideOffset()
void logEvalError(const char *message, const char *serverValueString=nullptr) const
Log evaluation error message.
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:55
RooConstVar represent a constant real-valued object.
Definition RooConstVar.h:26
RooSpan< const double > at(RooAbsArg const *arg, RooAbsArg const *caller=nullptr)
Definition DataMap.cxx:21
RooRealVar represents a variable that can be changed from the outside.
Definition RooRealVar.h:40
A simple container to hold a batch of data values.
Definition RooSpan.h:34
constexpr std::size_t size() const noexcept
Definition RooSpan.h:119
constexpr std::span< T >::pointer data() const
Definition RooSpan.h:102
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
R__EXTERN RooBatchComputeInterface * dispatchCUDA
R__EXTERN RooBatchComputeInterface * dispatchCPU
This dispatch pointer points to an implementation of the compute library, provided one has been loade...
OffsetMode
For setting the offset mode with the Offset() command argument to RooAbsPdf::fitTo()
Double_t LnGamma(Double_t z)
Computation of ln[gamma(z)] for all z.
Definition TMath.cxx:509
static void output()