52constexpr const char *RooNLLVarNew::weightVarName;
53constexpr const char *RooNLLVarNew::weightVarNameSumW2;
54constexpr const char *RooNLLVarNew::binVolumeVarName;
55constexpr const char *RooNLLVarNew::weightErrorLoVarName;
56constexpr const char *RooNLLVarNew::weightErrorHiVarName;
61std::unique_ptr<RooConstVar> dummyVar(
const char *
name)
63 return std::make_unique<RooConstVar>(
name,
name, 1.0);
71 _observables(
"!observables",
"List of observables", this),
72 _weightVar{
"!weightVar",
"weightVar", this, weightVar, true, false}
75 _observables.add(*obs);
78 RooOffsetPdf(
const RooOffsetPdf &other,
const char *
name =
nullptr)
80 _observables(
"!servers", this, other._observables),
81 _weightVar{
"!weightVar", this, other._weightVar}
84 TObject *clone(
const char *newname)
const override {
return new RooOffsetPdf(*
this, newname); }
88 std::span<double> output = ctx.
output();
89 std::size_t nEvents = output.size();
91 std::span<const double> weights = ctx.
at(_weightVar);
99 for (std::size_t i = 0; i < nEvents; ++i) {
101 var->setVal(ctx.
at(var)[i]);
103 dataHist.
add(_observables, weights[weights.size() == 1 ? 0 : i]);
107 RooHistPdf pdf{
"offsetPdf",
"offsetPdf", _observables, dataHist};
108 for (std::size_t i = 0; i < nEvents; ++i) {
110 var->setVal(ctx.
at(var)[i]);
112 output[i] = pdf.getVal(_observables);
117 double evaluate()
const override {
return 0.0; }
131 _func{
"func",
"func", this, func},
132 _weightVar{
"weightVar",
"weightVar", this, dummyVar(weightVarName)},
133 _weightSquaredVar{weightVarNameSumW2, weightVarNameSumW2, this, dummyVar(
"weightSquardVar")},
134 _statistic{cfg.statistic},
135 _chi2ErrorType{cfg.chi2ErrorType}
137 auto *pdf =
dynamic_cast<RooAbsPdf *
>(&func);
139 if (_statistic == Statistic::Chi2) {
143 setAttribute(
"Chi2EvaluationActive");
144 _funcMode = !pdf ? FuncMode::Function : (cfg.extended ? FuncMode::ExtendedPdf : FuncMode::Pdf);
146 _binnedL = pdf && pdf->getAttribute(
"BinnedLikelihoodActive");
157 const bool wantsExpectedEvents = pdf && ((_statistic == Statistic::NLL && cfg.extended && !_binnedL) ||
158 (_statistic == Statistic::Chi2 && _funcMode == FuncMode::ExtendedPdf));
159 if (wantsExpectedEvents) {
160 std::unique_ptr<RooAbsReal> expectedEvents = pdf->createExpectedEventsFunc(&obs);
161 if (expectedEvents) {
163 std::make_unique<RooTemplateProxy<RooAbsReal>>(
"expectedEvents",
"expectedEvents",
this, *expectedEvents);
164 addOwnedComponents(std::move(expectedEvents));
168 if (_statistic == Statistic::NLL) {
173 if (_binnedL && !pdf->getAttribute(
"BinnedLikelihoodActiveYields")) {
174 fillBinWidthsFromPdfBoundaries(*pdf, obs);
182 if (!_binnedL && _doBinOffset) {
183 auto offsetPdf = std::make_unique<RooOffsetPdf>(
"_offset_func",
"_offset_func", obs, *_weightVar);
184 _offsetPdf = std::make_unique<RooTemplateProxy<RooAbsPdf>>(
"offsetPdf",
"offsetPdf",
this, *offsetPdf);
185 addOwnedComponents(std::move(offsetPdf));
190 auto binVolumeDummy = std::make_unique<RooConstVar>(binVolumeVarName, binVolumeVarName, 1.0);
191 _binVolumes = std::make_unique<RooTemplateProxy<RooAbsReal>>(binVolumeVarName, binVolumeVarName,
this,
192 *binVolumeDummy,
true,
false);
193 addOwnedComponents(std::move(binVolumeDummy));
196 auto errLoDummy = std::make_unique<RooConstVar>(weightErrorLoVarName, weightErrorLoVarName, 1.0);
197 auto errHiDummy = std::make_unique<RooConstVar>(weightErrorHiVarName, weightErrorHiVarName, 1.0);
198 _weightErrLo = std::make_unique<RooTemplateProxy<RooAbsReal>>(weightErrorLoVarName, weightErrorLoVarName,
this,
199 *errLoDummy,
true,
false);
200 _weightErrHi = std::make_unique<RooTemplateProxy<RooAbsReal>>(weightErrorHiVarName, weightErrorHiVarName,
this,
201 *errHiDummy,
true,
false);
202 addOwnedComponents(std::move(errLoDummy));
203 addOwnedComponents(std::move(errHiDummy));
207 resetWeightVarNames();
210RooNLLVarNew::RooNLLVarNew(
const RooNLLVarNew &other,
const char *
name)
212 _func{
"func", this, other._func},
213 _weightVar{
"weightVar", this, other._weightVar},
214 _weightSquaredVar{
"weightSquaredVar", this, other._weightSquaredVar},
215 _weightSquared{other._weightSquared},
216 _binnedL{other._binnedL},
217 _doOffset{other._doOffset},
218 _doBinOffset{other._doBinOffset},
219 _statistic{other._statistic},
220 _funcMode{other._funcMode},
221 _chi2ErrorType{other._chi2ErrorType},
222 _simCount{other._simCount},
223 _prefix{other._prefix},
226 if (other._expectedEvents) {
227 _expectedEvents = std::make_unique<RooTemplateProxy<RooAbsReal>>(
"expectedEvents",
this, *other._expectedEvents);
229 if (other._binVolumes) {
230 _binVolumes = std::make_unique<RooTemplateProxy<RooAbsReal>>(binVolumeVarName,
this, *other._binVolumes);
232 if (other._weightErrLo) {
233 _weightErrLo = std::make_unique<RooTemplateProxy<RooAbsReal>>(weightErrorLoVarName,
this, *other._weightErrLo);
235 if (other._weightErrHi) {
236 _weightErrHi = std::make_unique<RooTemplateProxy<RooAbsReal>>(weightErrorHiVarName,
this, *other._weightErrHi);
240void RooNLLVarNew::fillBinWidthsFromPdfBoundaries(
RooAbsReal const &pdf,
RooArgSet const &observables)
243 if (!_binw.empty()) {
247 if (observables.
size() != 1) {
248 throw std::runtime_error(
"BinnedPdf optimization only works with a 1D pdf.");
251 std::list<double> *boundaries = pdf.
binBoundaries(*var, var->getMin(), var->getMax());
252 std::list<double>::iterator biter = boundaries->begin();
253 _binw.resize(boundaries->size() - 1);
254 double lastBound = (*biter);
257 while (biter != boundaries->end()) {
258 _binw[ibin] = (*biter) - lastBound;
259 lastBound = (*biter);
267 std::span<const double> weights)
const
272 const bool predsAreYields = _binw.empty();
274 for (std::size_t i = 0; i < preds.size(); ++i) {
277 double N = weights[i];
278 double mu = preds[i];
279 if (!predsAreYields) {
283 if (mu <= 0 && N > 0) {
285 logEvalError(
Form(
"Observed %f events in bin %lu with zero event yield",
N, (
unsigned long)i));
288 sumWeightKahanSum +=
N;
292 finalizeResult(ctx,
result, sumWeightKahanSum.Sum());
300double RooNLLVarNew::sumOfWeights(
RooFit::EvalContext &ctx, std::span<const double> weights,
bool squared)
const
302 std::size_t &generation = squared ? _sumWeight2Gen : _sumWeightGen;
303 double &cache = squared ? _sumWeight2Cache : _sumWeightCache;
311void RooNLLVarNew::doEvalChi2(
RooFit::EvalContext &ctx, std::span<const double> preds, std::span<const double> weights,
312 std::span<const double> weightsSumW2)
const
321 std::span<const double> binVol = ctx.
at(*_binVolumes);
322 std::span<const double> errLo = _weightErrLo ? ctx.
at(*_weightErrLo) : std::span<const double>{};
323 std::span<const double> errHi = _weightErrHi ? ctx.
at(*_weightErrHi) : std::span<const double>{};
325 const double sumWeight = sumOfWeights(ctx, weights,
false);
327 double normFactor = 1.0;
329 case FuncMode::Pdf: normFactor = sumWeight;
break;
330 case FuncMode::ExtendedPdf: normFactor = ctx.
at(*_expectedEvents)[0];
break;
331 case FuncMode::Function: normFactor = 1.0;
break;
337 for (std::size_t i = 0; i < preds.size(); ++i) {
338 const double N = weights[i];
339 const double mu = preds[i] * normFactor * binVol[i];
340 const double diff = mu -
N;
343 switch (_chi2ErrorType) {
347 const double err = diff > 0 ? errHi[i] : errLo[i];
351 default: sigma2 = mu;
break;
355 if (sigma2 == 0.0 &&
N == 0.0 && mu == 0.0) {
359 logEvalError(
Form(
"chi2 bin %lu has non-positive error; term replaced with NaN", (
unsigned long)i));
360 result += std::numeric_limits<double>::quiet_NaN();
364 result += diff * diff / sigma2;
365 sumWeightKahanSum +=
N;
368 finalizeResult(ctx,
result, sumWeightKahanSum.Sum());
373 std::span<const double> weights = ctx.
at(_weightVar);
374 std::span<const double> weightsSumW2 = ctx.
at(_weightSquaredVar);
376 if (_statistic == Statistic::Chi2) {
377 return doEvalChi2(ctx, ctx.
at(&*_func), weights, weightsSumW2);
381 return doEvalBinnedL(ctx, ctx.
at(&*_func), _weightSquared ? weightsSumW2 : weights);
384 auto config = ctx.
config(
this);
388 double sumWeight = sumOfWeights(ctx, weights,
false);
389 double sumWeight2 = 0.;
390 if (_expectedEvents && _weightSquared) {
391 sumWeight2 = sumOfWeights(ctx, weightsSumW2,
true);
395 _doBinOffset ? ctx.at(*_offsetPdf) : std::span<const
double>{});
397 if (nllOut.nInfiniteValues > 0) {
398 oocoutW(&*_func, Eval) <<
"RooAbsPdf::getLogVal(" << _func->GetName()
399 <<
") WARNING: top-level pdf has some infinite values" << std::endl;
401 for (std::size_t i = 0; i < nllOut.nNonPositiveValues; ++i) {
402 _func->logEvalError(
"getLogVal() top-level p.d.f not greater than zero");
404 for (std::size_t i = 0; i < nllOut.nNaNValues; ++i) {
405 _func->logEvalError(
"getLogVal() top-level p.d.f evaluates to NaN");
408 if (_expectedEvents) {
411 std::span<const double> expected = ctx.
at(*_expectedEvents);
412 nllOut.nllSum += pdf.extendedTerm(sumWeight, expected[0], _weightSquared ? sumWeight2 : 0.0, _doBinOffset);
415 finalizeResult(ctx, {nllOut.nllSum, nllOut.nllSumCarry}, sumWeight);
422void RooNLLVarNew::setPrefix(std::string
const &prefix)
426 resetWeightVarNames();
429void RooNLLVarNew::resetWeightVarNames()
431 _weightVar->SetName((_prefix + weightVarName).c_str());
432 _weightSquaredVar->SetName((_prefix + weightVarNameSumW2).c_str());
434 (*_offsetPdf)->SetName((_prefix +
"_offset_func").c_str());
437 (*_binVolumes)->SetName((_prefix + binVolumeVarName).c_str());
440 (*_weightErrLo)->SetName((_prefix + weightErrorLoVarName).c_str());
443 (*_weightErrHi)->SetName((_prefix + weightErrorHiVarName).c_str());
449void RooNLLVarNew::applyWeightSquared(
bool flag)
451 if (_statistic == Statistic::Chi2) {
453 coutW(Fitting) <<
"RooNLLVarNew::applyWeightSquared(" <<
GetName()
454 <<
") has no effect on a chi-squared evaluator; ignoring." << std::endl;
458 _weightSquared = flag;
461void RooNLLVarNew::enableOffsetting(
bool flag)
473 if (_statistic == Statistic::NLL && !_doBinOffset && _simCount > 1) {
474 result += weightSum * std::log(
static_cast<double>(_simCount));
481 if (_offset.Sum() == 0 && _offset.Carry() == 0 && (
result.Sum() != 0 ||
result.Carry() != 0)) {
ROOT::RRangeCast< T, false, Range_t > static_range_cast(Range_t &&coll)
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 * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
The Kahan summation is a compensated summation algorithm, which significantly reduces numerical error...
Common abstract base class for objects that represent a value and a "shape" in RooFit.
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.
Storage_t::size_type size() const
RooAbsArg * first() const
Abstract interface for all probability density functions.
Abstract base class for objects that represent a real value and implements functionality common to al...
virtual std::list< double > * binBoundaries(RooAbsRealLValue &obs, double xlo, double xhi) const
Retrieve bin boundaries if this distribution is binned in obs.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Container class to hold N-dimensional binned data.
void add(const RooArgSet &row, double wgt=1.0) override
Add wgt to the bin content enclosed by the coordinates passed in row.
std::span< const double > at(RooAbsArg const *arg, RooAbsArg const *caller=nullptr)
std::span< double > output()
RooBatchCompute::Config config(RooAbsArg const *arg) const
std::size_t inputGeneration() const
A counter that is incremented every time new input data is loaded into the evaluation context.
void setOutputWithOffset(RooAbsArg const *arg, ROOT::Math::KahanSum< double > val, ROOT::Math::KahanSum< double > const &offset)
Sets the output value with an offset.
A probability density function sampled from a multidimensional histogram.
Variable that can be changed from the outside.
Mother of all ROOT objects.
double reduceSum(Config cfg, InputArr input, size_t n)
ReduceNLLOutput reduceNLL(Config cfg, std::span< const double > probas, std::span< const double > weights, std::span< const double > offsetProbas)
double nll(double pdf, double weight, int binnedL, int doBinOffset)
void evaluate(typename Architecture_t::Tensor_t &A, EActivationFunction f)
Apply the given activation function to each value in the given tensor A.
void probas(TString dataset, TString fin="TMVA.root", Bool_t useTMVAStyle=kTRUE)
std::string GetName(TCppScope_t)