Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
FitHelpers.cxx
Go to the documentation of this file.
1/// \cond ROOFIT_INTERNAL
2
3/*
4 * Project: RooFit
5 * Authors:
6 * Jonas Rembser, CERN 2023
7 *
8 * Copyright (c) 2023, CERN
9 *
10 * Redistribution and use in source and binary forms,
11 * with or without modification, are permitted according to the terms
12 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
13 */
14
15#include "FitHelpers.h"
16
17#include <RooAbsData.h>
18#include <RooAbsPdf.h>
19#include <RooAbsReal.h>
20#include <RooAddition.h>
21#include <RooBatchCompute.h>
22#include <RooBinSamplingPdf.h>
23#include <RooCategory.h>
24#include <RooCmdConfig.h>
25#include <RooConstraintSum.h>
26#include <RooDataHist.h>
27#include <RooDataSet.h>
28#include <RooDerivative.h>
29#include <RooFit/Evaluator.h>
32#include <RooFitResult.h>
33#include <RooLinkedList.h>
34#include <RooMinimizer.h>
35#include <RooConstVar.h>
36#include <RooRealVar.h>
37#include <RooSimultaneous.h>
38#include <RooFormulaVar.h>
39
40#include <Math/CholeskyDecomp.h>
41#include <Math/Util.h>
42
43#include "ConstraintHelpers.h"
44#include "RooEvaluatorWrapper.h"
45#include "RooFitImplHelpers.h"
47
48#ifdef ROOFIT_LEGACY_EVAL_BACKEND
49#include "RooChi2Var.h"
50#include "RooNLLVar.h"
51
52#ifdef ROOFIT_MULTIPROCESS
54#endif
55#endif
56
57#include <sstream>
58
59using RooFit::Detail::RooNLLVarNew;
60
61namespace {
62
63constexpr int extendedFitDefault = 2;
64
65/// Nested RooSimultaneous are only supported in "switch mode", i.e., if their
66/// index category is not an observable. Throw an error otherwise.
67void checkNestedSimultaneous(RooAbsArg const &top, RooArgSet const &observables)
68{
69 RooArgList branches;
70 top.branchNodeServerList(&branches);
71 for (RooAbsArg *outer : branches) {
72 if (!dynamic_cast<RooSimultaneous const *>(outer)) {
73 continue;
74 }
75 RooArgList outerBranches;
76 outer->branchNodeServerList(&outerBranches);
77 for (RooAbsArg *arg : outerBranches) {
78 auto *nested = dynamic_cast<RooSimultaneous const *>(arg);
79 if (arg == outer || !nested || !nested->indexCatIsObservable(observables)) {
80 continue;
81 }
82 std::stringstream errMsg;
83 errMsg << "RooSimultaneous \"" << outer->GetName() << "\" contains the RooSimultaneous \"" << nested->GetName()
84 << "\", whose index category \"" << nested->indexCat().GetName()
85 << "\" is in the dataset. Nested RooSimultaneous are only supported if their index category is a "
86 "parameter (switch mode). To combine channels, use one RooSimultaneous over a RooCategory with one "
87 "state per channel.";
88 oocoutE(&top, InputArguments) << errMsg.str() << std::endl;
89 throw std::runtime_error(errMsg.str());
90 }
91 }
92}
93
94#ifdef ROOFIT_LEGACY_EVAL_BACKEND
95/// Print a deprecation warning when the legacy evaluation backend is selected for a fit.
96void printLegacyEvalBackendWarning(RooAbsReal const &topLevelArg)
97{
98 oocoutW(&topLevelArg, InputArguments)
99 << "The legacy evaluation backend is deprecated and will be removed in ROOT 6.44.\n"
100 "Please use the default \"cpu\" evaluation backend instead, i.e., don't pass RooFit::EvalBackend(\"legacy\")\n"
101 "or RooFit::BatchMode(\"off\") anymore. If the default backend does not work for your use case, please\n"
102 "report it by opening an issue on the ROOT GitHub repository."
103 << std::endl;
104}
105#endif
106
107////////////////////////////////////////////////////////////////////////////////
108/// Use the asymptotically correct approach to estimate errors in the presence of weights.
109/// This is slower but more accurate than `SumW2Error`. See also https://arxiv.org/abs/1911.01303).
110/// Applies the calculated covaraince matrix to the RooMinimizer and returns
111/// the quality of the covariance matrix.
112/// See also the documentation of RooAbsPdf::fitTo(), where this function is used.
113/// \param[in] minimizer The RooMinimizer to get the fit result from. The state
114/// of the minimizer will be altered by this function: the covariance
115/// matrix caltulated here will be applied to it via
116/// RooMinimizer::applyCovarianceMatrix().
117/// \param[in] data The dataset that was used for the fit.
118int calcAsymptoticCorrectedCovariance(RooAbsReal &pdf, RooMinimizer &minimizer, RooAbsData const &data)
119{
120 RooFormulaVar logpdf("logpdf", "log(pdf)", "log(@0)", pdf);
121 RooArgSet obs;
122 logpdf.getObservables(data.get(), obs);
123
124 // Warning if the dataset is binned. TODO: in some cases,
125 // people also use RooDataSet to encode binned data,
126 // e.g. for simultaneous fits. It would be useful to detect
127 // this in this future as well.
128 if (dynamic_cast<RooDataHist const *>(&data)) {
129 oocoutW(&pdf, InputArguments)
130 << "RooAbsPdf::fitTo(" << pdf.GetName()
131 << ") WARNING: Asymptotic error correction is requested for a binned data set. "
132 "This method is not designed to handle binned data. A standard chi2 fit will likely be more suitable.";
133 };
134
135 // Calculated corrected errors for weighted likelihood fits
136 std::unique_ptr<RooFitResult> rw(minimizer.save());
137 // Weighted inverse Hessian matrix
138 const TMatrixDSym &matV = rw->covarianceMatrix();
139 oocoutI(&pdf, Fitting)
140 << "RooAbsPdf::fitTo(" << pdf.GetName()
141 << ") Calculating covariance matrix according to the asymptotically correct approach. If you find this "
142 "method useful please consider citing https://arxiv.org/abs/1911.01303.\n";
143
144 // Initialise matrix containing first derivatives
145 int nFloatPars = rw->floatParsFinal().size();
146 TMatrixDSym num(nFloatPars);
147 for (int k = 0; k < nFloatPars; k++) {
148 for (int l = 0; l < nFloatPars; l++) {
149 num(k, l) = 0.0;
150 }
151 }
152
153 // Create derivative objects
154 std::vector<std::unique_ptr<RooDerivative>> derivatives;
155 const RooArgList &floated = rw->floatParsFinal();
156 RooArgSet allparams;
157 logpdf.getParameters(data.get(), allparams);
158 std::unique_ptr<RooArgSet> floatingparams{allparams.selectByAttrib("Constant", false)};
159
160 const double eps = 1.0e-4;
161
162 // Calculate derivatives of logpdf
163 for (const auto paramresult : floated) {
164 auto paraminternal = static_cast<RooRealVar *>(floatingparams->find(*paramresult));
165 assert(floatingparams->find(*paramresult)->IsA() == RooRealVar::Class());
166 double error = static_cast<RooRealVar *>(paramresult)->getError();
167 derivatives.emplace_back(logpdf.derivative(*paraminternal, obs, 1, eps * error));
168 }
169
170 // Calculate derivatives for number of expected events, needed for extended ML fit
171 RooAbsPdf *extended_pdf = dynamic_cast<RooAbsPdf *>(&pdf);
172 std::vector<double> diffs_expected(floated.size(), 0.0);
173 if (extended_pdf && extended_pdf->expectedEvents(obs) != 0.0) {
174 for (std::size_t k = 0; k < floated.size(); k++) {
175 const auto paramresult = static_cast<RooRealVar *>(floated.at(k));
176 auto paraminternal = static_cast<RooRealVar *>(floatingparams->find(*paramresult));
177
178 *paraminternal = paramresult->getVal();
179 double error = paramresult->getError();
180 paraminternal->setVal(paramresult->getVal() + eps * error);
181 double expected_plus = log(extended_pdf->expectedEvents(obs));
182 paraminternal->setVal(paramresult->getVal() - eps * error);
183 double expected_minus = log(extended_pdf->expectedEvents(obs));
184 *paraminternal = paramresult->getVal();
185 double diff = (expected_plus - expected_minus) / (2.0 * eps * error);
186 diffs_expected[k] = diff;
187 }
188 }
189
190 // Loop over data
191 for (int j = 0; j < data.numEntries(); j++) {
192 // Sets obs to current data point, this is where the pdf will be evaluated
193 obs.assign(*data.get(j));
194 // Determine first derivatives
195 std::vector<double> diffs(floated.size(), 0.0);
196 for (std::size_t k = 0; k < floated.size(); k++) {
197 const auto paramresult = static_cast<RooRealVar *>(floated.at(k));
198 auto paraminternal = static_cast<RooRealVar *>(floatingparams->find(*paramresult));
199 // first derivative to parameter k at best estimate point for this measurement
200 double diff = derivatives[k]->getVal();
201 // need to reset to best fit point after differentiation
202 *paraminternal = paramresult->getVal();
203 diffs[k] = diff;
204 }
205
206 // Fill numerator matrix
207 for (std::size_t k = 0; k < floated.size(); k++) {
208 for (std::size_t l = 0; l < floated.size(); l++) {
209 num(k, l) += data.weightSquared() * (diffs[k] + diffs_expected[k]) * (diffs[l] + diffs_expected[l]);
210 }
211 }
212 }
213 num.Similarity(matV);
214
215 // Propagate corrected errors to parameters objects
216 minimizer.applyCovarianceMatrix(num);
217
218 // The derivatives are found in RooFit and not with the minimizer (e.g.
219 // minuit), so the quality of the corrected covariance matrix corresponds to
220 // the quality of the original covariance matrix
221 return rw->covQual();
222}
223
224////////////////////////////////////////////////////////////////////////////////
225/// Apply correction to errors and covariance matrix. This uses two covariance
226/// matrices, one with the weights, the other with squared weights, to obtain
227/// the correct errors for weighted likelihood fits.
228/// Applies the calculated covaraince matrix to the RooMinimizer and returns
229/// the quality of the covariance matrix.
230/// See also the documentation of RooAbsPdf::fitTo(), where this function is used.
231/// \param[in] minimizer The RooMinimizer to get the fit result from. The state
232/// of the minimizer will be altered by this function: the covariance
233/// matrix caltulated here will be applied to it via
234/// RooMinimizer::applyCovarianceMatrix().
235/// \param[in] nll The NLL object that was used for the fit.
236int calcSumW2CorrectedCovariance(RooAbsReal const &pdf, RooMinimizer &minimizer, RooAbsReal &nll)
237{
238 // Calculated corrected errors for weighted likelihood fits
239 std::unique_ptr<RooFitResult> rw{minimizer.save()};
240 nll.applyWeightSquared(true);
241 oocoutI(&pdf, Fitting) << "RooAbsPdf::fitTo(" << pdf.GetName()
242 << ") Calculating sum-of-weights-squared correction matrix for covariance matrix\n";
243 minimizer.hesse();
244 std::unique_ptr<RooFitResult> rw2{minimizer.save()};
245 nll.applyWeightSquared(false);
246
247 // Apply correction matrix
248 const TMatrixDSym &matV = rw->covarianceMatrix();
249 TMatrixDSym matC = rw2->covarianceMatrix();
251 if (!decomp) {
252 oocoutE(&pdf, Fitting) << "RooAbsPdf::fitTo(" << pdf.GetName()
253 << ") ERROR: Cannot apply sum-of-weights correction to covariance matrix: correction "
254 "matrix calculated with weight-squared is singular\n";
255 return -1;
256 }
257
258 // replace C by its inverse
259 decomp.Invert(matC);
260 // the class lies about the matrix being symmetric, so fill in the
261 // part above the diagonal
262 for (int i = 0; i < matC.GetNrows(); ++i) {
263 for (int j = 0; j < i; ++j) {
264 matC(j, i) = matC(i, j);
265 }
266 }
267 matC.Similarity(matV);
268 // C now contains V C^-1 V
269 // Propagate corrected errors to parameters objects
270 minimizer.applyCovarianceMatrix(matC);
271
272 return std::min(rw->covQual(), rw2->covQual());
273}
274
275/// Configuration struct for RooAbsPdf::minimizeNLL with all the default values
276/// that also should be taken as the default values for RooAbsPdf::fitTo.
277struct MinimizerConfig {
278 double recoverFromNaN = 10.;
279 int verbose = 0;
280 int doSave = 0;
281 int doTimer = 0;
282 int printLevel = 1;
283 int strategy = 1;
284 int initHesse = 0;
285 int hesse = 1;
286 int minos = 0;
287 int numee = 10;
288 int doEEWall = 1;
289 int doWarn = 1;
290 int doSumW2 = -1;
291 int doAsymptotic = -1;
292 int maxCalls = -1;
293 int doOffset = -1;
294 int parallelize = 0;
295 bool enableParallelGradient = false;
296 bool enableParallelDescent = false;
297 int parallelDescentNumSplits = 0;
298 int parallelDescentSplitStrategy = 0;
299 bool timingAnalysis = false;
300 const RooArgSet *minosSet = nullptr;
301 std::string minType;
302 std::string minAlg = "minuit";
303};
304
305/// Validates the NumCPU() argument for the non-legacy evaluation backends and
306/// returns the effective number of worker threads for the RooFit::Evaluator.
307int effectiveNumWorkers(RooAbsArg const &arg, RooFit::EvalBackend::Value evalBackend, int numCpu)
308{
310
311 if (numCpu <= 1) {
312 return 1;
313 }
314 if (evalBackend == Value::Cuda) {
315 oocoutW(&arg, Fitting) << "The NumCPU() option is ignored by the CUDA evaluation backend." << std::endl;
316 return 1;
317 }
318 if (evalBackend == Value::CodegenNoGrad) {
319 oocoutW(&arg, Fitting) << "The NumCPU() option has no effect with EvalBackend(\"codegen_no_grad\"), "
320 "because the test statistic is evaluated with single-threaded generated code."
321 << std::endl;
322 return 1;
323 }
324 if (evalBackend == Value::Codegen) {
325 oocxcoutI(&arg, Fitting) << "NumCPU(" << numCpu << ") enables multi-threaded evaluation of large batches "
326 << "for test statistic values. The generated gradient code is not affected."
327 << std::endl;
328 return numCpu;
329 }
330 oocxcoutI(&arg, Fitting) << "NumCPU(" << numCpu << ") enables multi-threaded evaluation of large batches in "
331 << "the RooBatchCompute library. The interleaving strategy argument of NumCPU() is "
332 << "ignored." << std::endl;
333 return numCpu;
334}
335
336bool interpretExtendedCmdArg(RooAbsPdf const &pdf, int extendedCmdArg)
337{
338 // Process automatic extended option
339 if (extendedCmdArg == extendedFitDefault) {
341 if (ext) {
342 oocoutI(&pdf, Minimization)
343 << "p.d.f. provides expected number of events, including extended term in likelihood." << std::endl;
344 }
345 return ext;
346 }
347 // If Extended(false) was explicitly set, but the pdf MUST be extended, then
348 // it's time to print an error. This happens when you're fitting a RooAddPdf
349 // with coefficient that represent yields, and without the additional
350 // constraint these coefficients are degenerate because the RooAddPdf
351 // normalizes itself. Nothing correct can come out of this.
352 if (extendedCmdArg == 0) {
354 std::string errMsg = "You used the Extended(false) option on a pdf where the fit MUST be extended! "
355 "The parameters are not well defined and you're getting nonsensical results.";
356 oocoutE(&pdf, InputArguments) << errMsg << std::endl;
357 }
358 }
359 return extendedCmdArg;
360}
361
362/// To set the fitrange attribute of the PDF and custom ranges for the
363/// observables so that RooPlot can automatically plot the fitting range.
364void resetFitrangeAttributes(RooAbsArg &pdf, RooAbsData const &data, std::string const &baseName, const char *rangeName,
365 bool splitRange)
366{
367 // Clear possible range attributes from previous fits.
368 pdf.removeStringAttribute("fitrange");
369
370 // No fitrange was specified, so we do nothing. Or "SplitRange" is used, and
371 // then there are no uniquely defined ranges for the observables (as they
372 // are different in each category).
373 if (!rangeName || splitRange)
374 return;
375
376 RooArgSet observables;
377 pdf.getObservables(data.get(), observables);
378
379 std::string fitrangeValue;
380 auto subranges = ROOT::Split(rangeName, ",");
381 for (auto const &subrange : subranges) {
382 if (subrange.empty())
383 continue;
384 std::string fitrangeValueSubrange = std::string("fit_") + baseName;
385 if (subranges.size() > 1) {
386 fitrangeValueSubrange += "_" + subrange;
387 }
388 fitrangeValue += fitrangeValueSubrange + ",";
389 for (RooAbsArg *arg : observables) {
390
391 if (arg->isCategory())
392 continue;
393 auto &observable = static_cast<RooRealVar &>(*arg);
394
395 observable.setRange(fitrangeValueSubrange.c_str(), observable.getMin(subrange.c_str()),
396 observable.getMax(subrange.c_str()));
397 }
398 }
399 pdf.setStringAttribute("fitrange", fitrangeValue.substr(0, fitrangeValue.size() - 1).c_str());
400}
401
402/// Iterate the simultaneous pdf's categories and build one test-statistic term
403/// per channel via `makeTerm`. Channels excluded by the (optional) category
404/// range are skipped. The per-channel term's special variables are prefixed
405/// with `_<catName>_`. The terms are summed into a RooAddition named
406/// `combinedName`.
407template <typename TermFactory>
408std::unique_ptr<RooAddition> createSimultaneousStat(RooSimultaneous const &simPdf, std::string const &rangeName,
409 std::string const &combinedName, TermFactory &&makeTerm)
410{
411 RooAbsCategoryLValue const &simCat = simPdf.indexCat();
412
413 RooArgList terms;
414 for (auto const &catState : simCat) {
415 std::string const &catName = catState.first;
416 RooAbsCategory::value_type catIndex = catState.second;
417
418 // Skip channels excluded by a category range (only RooCategory supports
419 // ranges on categorical values).
420 if (!rangeName.empty()) {
421 auto simCatAsRooCategory = dynamic_cast<RooCategory const *>(&simCat);
422 if (simCatAsRooCategory && !simCatAsRooCategory->isStateInRange(rangeName.c_str(), catIndex)) {
423 continue;
424 }
425 }
426
427 RooAbsPdf *channelPdf = simPdf.getPdf(catName.c_str());
428 if (!channelPdf) {
429 continue;
430 }
431 std::unique_ptr<RooArgSet> observables{
432 std::unique_ptr<RooArgSet>(channelPdf->getVariables())->selectByAttrib("__obs__", true)};
433 std::unique_ptr<RooNLLVarNew> term = makeTerm(*channelPdf, *observables);
434 term->setPrefix(std::string("_") + catName + "_");
435 terms.addOwned(std::move(term));
436 }
437
438 auto combined = std::make_unique<RooAddition>(combinedName.c_str(), combinedName.c_str(), terms);
439 combined->addOwnedComponents(std::move(terms));
440 return combined;
441}
442
443std::unique_ptr<RooAbsArg> createSimultaneousChi2(RooSimultaneous const &simPdf, std::string const &rangeName,
444 bool isSimPdfExtended, RooDataHist::ErrorType etype)
445{
446 auto chi2 =
447 createSimultaneousStat(simPdf, rangeName, "simChi2", [&](RooAbsPdf &channelPdf, RooArgSet const &observables) {
448 RooNLLVarNew::Config cfg;
449 cfg.statistic = RooNLLVarNew::Statistic::Chi2;
450 cfg.extended = isSimPdfExtended && channelPdf.extendMode() != RooAbsPdf::CanNotBeExtended;
451 cfg.chi2ErrorType = etype;
452 auto name = std::string("chi2_") + channelPdf.GetName();
453 return std::make_unique<RooNLLVarNew>(name.c_str(), name.c_str(), channelPdf, observables, cfg);
454 });
455 // Flag the top node so RooEvaluatorWrapper knows not to skip zero-weight bins
456 chi2->setAttribute("Chi2EvaluationActive");
457 return chi2;
458}
459
460std::unique_ptr<RooAbsArg> createSimultaneousNLL(RooSimultaneous const &simPdf, bool isSimPdfExtended,
461 std::string const &rangeName, RooFit::OffsetMode offset)
462{
463 auto nll =
464 createSimultaneousStat(simPdf, rangeName, "mynll", [&](RooAbsPdf &channelPdf, RooArgSet const &observables) {
465 RooNLLVarNew::Config cfg;
466 // Only request extended NLLs for channels that can be extended.
467 cfg.extended = isSimPdfExtended && channelPdf.extendMode() != RooAbsPdf::CanNotBeExtended;
468 cfg.offsetMode = offset;
469 auto name = std::string("nll_") + channelPdf.GetName();
470 return std::make_unique<RooNLLVarNew>(name.c_str(), name.c_str(), channelPdf, observables, cfg);
471 });
472
473 const int simCount = nll->list().size();
474 for (auto *child : static_range_cast<RooNLLVarNew *>(nll->list())) {
475 child->setSimCount(simCount);
476 }
477 return nll;
478}
479
480/// Apply the `IntegrateBins` precision to either a single pdf or in-place to
481/// the component pdfs of a RooSimultaneous. Newly-allocated wrapper pdfs are
482/// appended to `ownedOut`. The returned reference points either at one of
483/// those wrappers or at the input pdf itself.
484RooAbsPdf &applyIntegrateBinsWrapping(RooAbsPdf &pdf, RooAbsData const &data, double precision, RooArgList &ownedOut)
485{
486 if (auto *simPdf = dynamic_cast<RooSimultaneous *>(&pdf)) {
487 simPdf->wrapPdfsInBinSamplingPdfs(data, precision);
488 return pdf;
489 }
490 if (std::unique_ptr<RooAbsPdf> wrapped = RooBinSamplingPdf::create(pdf, data, precision)) {
491 RooAbsPdf &ref = *wrapped;
492 ownedOut.addOwned(std::move(wrapped));
493 return ref;
494 }
495 return pdf;
496}
497
498/// RAII helper for the `setNormRange` + SplitRange/RangeName attribute setting
499/// that must be done around `compileForNormSet` so that the compiled pdf sees
500/// the restricted normalization range. All mutations are reverted on
501/// destruction.
502class NormRangeScope {
503public:
504 NormRangeScope(RooAbsPdf &pdf, const char *rangeName, bool splitRange) : _pdf{&pdf}
505 {
506 if (pdf.normRange()) {
507 _oldNormRange = pdf.normRange();
508 }
509 pdf.setNormRange(rangeName);
510 pdf.setAttribute("SplitRange", splitRange);
511 pdf.setStringAttribute("RangeName", rangeName);
512 }
513 NormRangeScope(NormRangeScope const &) = delete;
514 NormRangeScope &operator=(NormRangeScope const &) = delete;
515 ~NormRangeScope()
516 {
517 _pdf->setAttribute("SplitRange", false);
518 _pdf->setStringAttribute("RangeName", nullptr);
519 _pdf->setNormRange(_oldNormRange.empty() ? nullptr : _oldNormRange.c_str());
520 }
521
522private:
523 RooAbsPdf *_pdf;
524 std::string _oldNormRange;
525};
526
527/// Shared `compileForNormSet` sequence used by both the NLL and chi2 CPU
528/// backends. Sets up the reduced normalization range via `NormRangeScope`,
529/// then runs the graph compilation. When `likelihoodMode` is true the
530/// CompileContext is flagged accordingly (enabling binned-likelihood
531/// optimisations in the compiled pdf). The returned compiled pdf has
532/// `fixAddCoefRange` already applied when `addCoefRangeName` is non-empty.
533std::unique_ptr<RooAbsPdf> compilePdfForFit(RooAbsPdf &pdf, RooArgSet const &normSet, const char *rangeName,
534 bool splitRange, const char *addCoefRangeName, bool likelihoodMode)
535{
536 NormRangeScope scope{pdf, rangeName, splitRange};
537
539 ctx.setLikelihoodMode(likelihoodMode);
540 std::unique_ptr<RooAbsArg> head = pdf.compileForNormSet(normSet, ctx);
541 std::unique_ptr<RooAbsPdf> pdfClone{&dynamic_cast<RooAbsPdf &>(*head.release())};
542
543 if (addCoefRangeName && *addCoefRangeName) {
544 pdfClone->fixAddCoefRange(addCoefRangeName, false);
545 }
546 return pdfClone;
547}
548
549std::unique_ptr<RooAbsReal> createNLLNew(RooAbsPdf &pdf, RooAbsData &data, std::unique_ptr<RooAbsReal> &&constraints,
550 std::string const &rangeName, RooArgSet const &projDeps, bool isExtended,
551 double integrateOverBinsPrecision, RooFit::OffsetMode offset)
552{
553 if (constraints) {
554 // The computation graph for the constraints is very small, no need to do
555 // the tracking of clean and dirty nodes here.
556 constraints->setOperMode(RooAbsArg::ADirty);
557 }
558
559 RooArgSet observables;
560 pdf.getObservables(data.get(), observables);
561 observables.remove(projDeps, true, true);
562
563 oocxcoutI(&pdf, Fitting) << "RooAbsPdf::fitTo(" << pdf.GetName()
564 << ") fixing normalization set for coefficient determination to observables in data"
565 << "\n";
566 pdf.fixAddCoefNormalization(observables, false);
567
568 RooArgList binSamplingPdfs;
569 RooAbsPdf &finalPdf = applyIntegrateBinsWrapping(pdf, data, integrateOverBinsPrecision, binSamplingPdfs);
570
571 RooArgList nllTerms;
572 auto *simPdf = dynamic_cast<RooSimultaneous *>(&finalPdf);
573 // A RooSimultaneous whose index category is not among the data columns is
574 // a "switch" pdf selecting the component given by the current index state
575 // (analogous to RooMultiPdf): there are no channels to split the NLL into,
576 // so it is treated like an ordinary pdf.
577 if (simPdf && simPdf->indexCatIsObservable(*data.get())) {
578 nllTerms.addOwned(createSimultaneousNLL(*simPdf, isExtended, rangeName, offset));
579 } else {
580 RooNLLVarNew::Config cfg;
581 cfg.extended = isExtended;
582 cfg.offsetMode = offset;
583 nllTerms.addOwned(std::make_unique<RooNLLVarNew>("RooNLLVarNew", "RooNLLVarNew", finalPdf, observables, cfg));
584 }
585 if (constraints) {
586 nllTerms.addOwned(std::move(constraints));
587 }
588
589 std::string nllName = std::string("nll_") + pdf.GetName() + "_" + data.GetName();
590 auto nll = std::make_unique<RooAddition>(nllName.c_str(), nllName.c_str(), nllTerms);
591 nll->addOwnedComponents(std::move(binSamplingPdfs));
592 nll->addOwnedComponents(std::move(nllTerms));
593
594 return nll;
595}
596
597} // namespace
598
599namespace RooFit::FitHelpers {
600
601void defineMinimizationOptions(RooCmdConfig &pc)
602{
603 // Default-initialized instance of MinimizerConfig to get the default
604 // minimizer parameter values.
605 MinimizerConfig minimizerDefaults;
606
607 pc.defineDouble("RecoverFromUndefinedRegions", "RecoverFromUndefinedRegions", 0, minimizerDefaults.recoverFromNaN);
608 pc.defineInt("verbose", "Verbose", 0, minimizerDefaults.verbose);
609 pc.defineInt("doSave", "Save", 0, minimizerDefaults.doSave);
610 pc.defineInt("doTimer", "Timer", 0, minimizerDefaults.doTimer);
611 pc.defineInt("printLevel", "PrintLevel", 0, minimizerDefaults.printLevel);
612 pc.defineInt("strategy", "Strategy", 0, minimizerDefaults.strategy);
613 pc.defineInt("initHesse", "InitialHesse", 0, minimizerDefaults.initHesse);
614 pc.defineInt("hesse", "Hesse", 0, minimizerDefaults.hesse);
615 pc.defineInt("minos", "Minos", 0, minimizerDefaults.minos);
616 pc.defineInt("numee", "PrintEvalErrors", 0, minimizerDefaults.numee);
617 pc.defineInt("doEEWall", "EvalErrorWall", 0, minimizerDefaults.doEEWall);
618 pc.defineInt("doWarn", "Warnings", 0, minimizerDefaults.doWarn);
619 pc.defineInt("doSumW2", "SumW2Error", 0, minimizerDefaults.doSumW2);
620 pc.defineInt("doAsymptoticError", "AsymptoticError", 0, minimizerDefaults.doAsymptotic);
621 pc.defineInt("maxCalls", "MaxCalls", 0, minimizerDefaults.maxCalls);
622 pc.defineInt("doOffset", "OffsetLikelihood", 0, minimizerDefaults.doOffset);
623 pc.defineInt("parallelize", "Parallelize", 0, minimizerDefaults.parallelize); // Three parallelize arguments
624 pc.defineInt("enableParallelGradient", "ParallelGradientOptions", 0, minimizerDefaults.enableParallelGradient);
625 pc.defineInt("enableParallelDescent", "ParallelDescentOptions", 0, minimizerDefaults.enableParallelDescent);
626 pc.defineInt("parallelDescentNumSplits", "ParallelDescentOptions", 1, minimizerDefaults.parallelDescentNumSplits);
627 pc.defineInt("parallelDescentSplitStrategy", "ParallelDescentOptions", 2,
628 minimizerDefaults.parallelDescentSplitStrategy);
629 pc.defineInt("timingAnalysis", "TimingAnalysis", 0, minimizerDefaults.timingAnalysis);
630 pc.defineString("mintype", "Minimizer", 0, minimizerDefaults.minType.c_str());
631 pc.defineString("minalg", "Minimizer", 1, minimizerDefaults.minAlg.c_str());
632 pc.defineSet("minosSet", "Minos", 0, minimizerDefaults.minosSet);
633}
634
635////////////////////////////////////////////////////////////////////////////////
636/// Minimizes a given NLL variable by finding the optimal parameters with the
637/// RooMinimzer. The NLL variable can be created with RooAbsPdf::createNLL.
638/// If you are looking for a function that combines likelihood creation with
639/// fitting, see RooAbsPdf::fitTo.
640/// \param[in] nll The negative log-likelihood variable to minimize.
641/// \param[in] data The dataset that was also used for the NLL. It's a necessary
642/// parameter because it is used in the asymptotic error correction.
643/// \param[in] cfg Configuration struct with all the configuration options for
644/// the RooMinimizer. These are a subset of the options that you can
645/// also pass to RooAbsPdf::fitTo via the RooFit command arguments.
646std::unique_ptr<RooFitResult> minimize(RooAbsReal &pdf, RooAbsReal &nll, RooAbsData const &data, RooCmdConfig const &pc)
647{
648 MinimizerConfig cfg;
649 cfg.recoverFromNaN = pc.getDouble("RecoverFromUndefinedRegions");
650 cfg.verbose = pc.getInt("verbose");
651 cfg.doSave = pc.getInt("doSave");
652 cfg.doTimer = pc.getInt("doTimer");
653 cfg.printLevel = pc.getInt("printLevel");
654 cfg.strategy = pc.getInt("strategy");
655 cfg.initHesse = pc.getInt("initHesse");
656 cfg.hesse = pc.getInt("hesse");
657 cfg.minos = pc.getInt("minos");
658 cfg.numee = pc.getInt("numee");
659 cfg.doEEWall = pc.getInt("doEEWall");
660 cfg.doWarn = pc.getInt("doWarn");
661 cfg.doSumW2 = pc.getInt("doSumW2");
662 cfg.doAsymptotic = pc.getInt("doAsymptoticError");
663 cfg.maxCalls = pc.getInt("maxCalls");
664 cfg.minosSet = pc.getSet("minosSet");
665 cfg.minType = pc.getString("mintype", "");
666 cfg.minAlg = pc.getString("minalg", "minuit");
667 cfg.doOffset = pc.getInt("doOffset");
668 cfg.parallelize = pc.getInt("parallelize");
669 cfg.enableParallelGradient = pc.getInt("enableParallelGradient");
670 cfg.enableParallelDescent = pc.getInt("enableParallelDescent");
671 cfg.parallelDescentNumSplits = pc.getInt("parallelDescentNumSplits");
672 cfg.parallelDescentSplitStrategy = pc.getInt("parallelDescentSplitStrategy");
673 cfg.timingAnalysis = pc.getInt("timingAnalysis");
674
675 // Determine if the dataset has weights
676 bool weightedData = data.isNonPoissonWeighted();
677
678 // The weighted-data uncertainty correction options only apply to likelihood
679 // fits. Skip the NLL-only paths when minimizing a chi-squared test statistic.
680 const bool isChi2 = nll.getAttribute("Chi2EvaluationActive");
681
682 std::string msgPrefix = std::string{"RooAbsPdf::fitTo("} + pdf.GetName() + "): ";
683
684 // Warn user that a method to determine parameter uncertainties should be provided if weighted data is offered
685 if (!isChi2 && weightedData && cfg.doSumW2 == -1 && cfg.doAsymptotic == -1) {
686 oocoutW(&pdf, InputArguments) << msgPrefix <<
687 R"(WARNING: a likelihood fit is requested of what appears to be weighted data.
688 While the estimated values of the parameters will always be calculated taking the weights into account,
689 there are multiple ways to estimate the errors of the parameters. You are advised to make an
690 explicit choice for the error calculation:
691 - Either provide SumW2Error(true), to calculate a sum-of-weights-corrected HESSE error matrix
692 (error will be proportional to the number of events in MC).
693 - Or provide SumW2Error(false), to return errors from original HESSE error matrix
694 (which will be proportional to the sum of the weights, i.e., a dataset with <sum of weights> events).
695 - Or provide AsymptoticError(true), to use the asymptotically correct expression
696 (for details see https://arxiv.org/abs/1911.01303)."
697)";
698 }
699
700 if (cfg.minos && (cfg.doSumW2 == 1 || cfg.doAsymptotic == 1)) {
701 oocoutE(&pdf, InputArguments)
702 << msgPrefix
703 << " sum-of-weights and asymptotic error correction do not work with MINOS errors. Not fitting.\n";
704 return nullptr;
705 }
706 if (cfg.doAsymptotic == 1 && cfg.minos) {
707 oocoutW(&pdf, InputArguments) << msgPrefix << "WARNING: asymptotic correction does not apply to MINOS errors\n";
708 }
709
710 // avoid setting both SumW2 and Asymptotic for uncertainty correction
711 if (cfg.doSumW2 == 1 && cfg.doAsymptotic == 1) {
712 oocoutE(&pdf, InputArguments) << msgPrefix
713 << "ERROR: Cannot compute both asymptotically correct and SumW2 errors.\n";
714 return nullptr;
715 }
716
717 // Apply the experimental likelihood-splitting settings from
718 // ParallelDescentOptions(). A numSplits value of zero keeps the automatic
719 // task-splitting defaults of RooFit::MultiProcess.
720 if (cfg.parallelDescentNumSplits > 0) {
721#ifdef ROOFIT_MULTIPROCESS
722 if (cfg.parallelDescentSplitStrategy == 0) {
724 } else {
726 }
727#else
728 oocoutW(&pdf, InputArguments) << "Likelihood-splitting settings passed via ParallelDescentOptions() are "
729 "ignored, because ROOT was built without RooFit::MultiProcess support"
730 << std::endl;
731#endif
732 }
733
734 // Instantiate RooMinimizer
735 RooMinimizer::Config minimizerConfig;
736 minimizerConfig.enableParallelGradient = cfg.enableParallelGradient;
737 minimizerConfig.enableParallelDescent = cfg.enableParallelDescent;
738 minimizerConfig.parallelize = cfg.parallelize;
739 minimizerConfig.timingAnalysis = cfg.timingAnalysis;
740 minimizerConfig.offsetting = cfg.doOffset;
741 RooMinimizer m(nll, minimizerConfig);
742
743 m.setMinimizerType(cfg.minType);
744 m.setEvalErrorWall(cfg.doEEWall);
745 m.setRecoverFromNaNStrength(cfg.recoverFromNaN);
746 m.setPrintEvalErrors(cfg.numee);
747 if (cfg.maxCalls > 0)
748 m.setMaxFunctionCalls(cfg.maxCalls);
749 if (cfg.printLevel != 1)
750 m.setPrintLevel(cfg.printLevel);
751 if (cfg.verbose)
752 m.setVerbose(true); // Activate verbose options
753 if (cfg.doTimer)
754 m.setProfile(true); // Activate timer options
755 if (cfg.strategy != 1)
756 m.setStrategy(cfg.strategy); // Modify fit strategy
757 if (cfg.initHesse)
758 m.hesse(); // Initialize errors with hesse
759 m.minimize(cfg.minType.c_str(), cfg.minAlg.c_str()); // Minimize using chosen algorithm
760 if (cfg.hesse)
761 m.hesse(); // Evaluate errors with Hesse
762
763 int corrCovQual = -1;
764
765 if (!isChi2 && m.getNPar() > 0) {
766 if (cfg.doAsymptotic == 1)
767 corrCovQual = calcAsymptoticCorrectedCovariance(pdf, m, data); // Asymptotically correct
768 if (cfg.doSumW2 == 1)
769 corrCovQual = calcSumW2CorrectedCovariance(pdf, m, nll);
770 }
771
772 if (cfg.minos)
773 cfg.minosSet ? m.minos(*cfg.minosSet) : m.minos(); // Evaluate errs with Minos
774
775 // Optionally return fit result
776 std::unique_ptr<RooFitResult> ret;
777 if (cfg.doSave) {
778 auto name = std::string("fitresult_") + pdf.GetName() + "_" + data.GetName();
779 auto title = std::string("Result of fit of p.d.f. ") + pdf.GetName() + " to dataset " + data.GetName();
780 ret = std::unique_ptr<RooFitResult>{m.save(name.c_str(), title.c_str())};
781 if ((cfg.doSumW2 == 1 || cfg.doAsymptotic == 1) && m.getNPar() > 0)
782 ret->setCovQual(corrCovQual);
783 }
784
785 return ret;
786}
787
788std::unique_ptr<RooAbsReal> createNLL(RooAbsPdf &pdf, RooAbsData &data, const RooLinkedList &cmdList)
789{
790 checkNestedSimultaneous(pdf, *data.get());
791
792 auto timingScope = std::make_unique<ROOT::Math::Util::TimingScope>(
793 [&pdf](std::string const &msg) { oocoutI(&pdf, Fitting) << msg << std::endl; }, "Creation of NLL object took");
794
795 auto baseName = std::string("nll_") + pdf.GetName() + "_" + data.GetName();
796
797 // Select the pdf-specific commands
798 RooCmdConfig pc("RooAbsPdf::createNLL(" + std::string(pdf.GetName()) + ")");
799
800 pc.defineString("rangeName", "RangeWithName", 0, "", true);
801 pc.defineString("addCoefRange", "SumCoefRange", 0, "");
802 pc.defineString("globstag", "GlobalObservablesTag", 0, "");
803 pc.defineString("globssource", "GlobalObservablesSource", 0, "data");
804 pc.defineDouble("rangeLo", "Range", 0, -999.);
805 pc.defineDouble("rangeHi", "Range", 1, -999.);
806 pc.defineInt("splitRange", "SplitRange", 0, 0);
807 pc.defineInt("ext", "Extended", 0, extendedFitDefault);
808 pc.defineInt("numcpu", "NumCPU", 0, 1);
809 pc.defineInt("interleave", "NumCPU", 1, 0);
810 pc.defineInt("verbose", "Verbose", 0, 0);
811 pc.defineInt("cloneData", "CloneData", 0, 0);
812 pc.defineSet("projDepSet", "ProjectedObservables", 0, nullptr);
813 pc.defineSet("cPars", "Constrain", 0, nullptr);
814 pc.defineSet("glObs", "GlobalObservables", 0, nullptr);
815 pc.defineInt("doOffset", "OffsetLikelihood", 0, 0);
816 pc.defineSet("extCons", "ExternalConstraints", 0, nullptr);
817 pc.defineInt("EvalBackend", "EvalBackend", 0, static_cast<int>(RooFit::EvalBackend::defaultValue()));
818 pc.defineDouble("IntegrateBins", "IntegrateBins", 0, -1.);
819 pc.defineMutex("Range", "RangeWithName");
820 pc.defineMutex("GlobalObservables", "GlobalObservablesTag");
821 pc.defineInt("ModularL", "ModularL", 0, 0);
822
823 // New style likelihoods define parallelization through Parallelize(...) on fitTo or attributes on
824 // RooMinimizer::Config.
825 pc.defineMutex("ModularL", "NumCPU");
826
827 // New style likelihoods define offsetting on minimizer, not on likelihood
828 pc.defineMutex("ModularL", "OffsetLikelihood");
829
830 // Process and check varargs
831 pc.process(cmdList);
832 if (!pc.ok(true)) {
833 return nullptr;
834 }
835
836 if (pc.getInt("ModularL")) {
837 int lut[3] = {2, 1, 0};
839 static_cast<RooFit::TestStatistics::RooAbsL::Extended>(lut[pc.getInt("ext")])};
840
841 RooArgSet cParsSet;
842 RooArgSet extConsSet;
843 RooArgSet glObsSet;
844
845 if (auto tmp = pc.getSet("cPars"))
846 cParsSet.add(*tmp);
847
848 if (auto tmp = pc.getSet("extCons"))
849 extConsSet.add(*tmp);
850
851 if (auto tmp = pc.getSet("glObs"))
852 glObsSet.add(*tmp);
853
854 const std::string rangeName = pc.getString("globstag", "", false);
855
857 builder.Extended(ext)
858 .ConstrainedParameters(cParsSet)
859 .ExternalConstraints(extConsSet)
860 .GlobalObservables(glObsSet)
861 .GlobalObservablesTag(rangeName.c_str())
862 .EvalBackend(RooFit::EvalBackend(static_cast<RooFit::EvalBackend::Value>(pc.getInt("EvalBackend"))));
863
864 return std::make_unique<RooFit::TestStatistics::RooRealL>("likelihood", "", builder.build());
865 }
866
867 // Decode command line arguments
868 const char *rangeName = pc.getString("rangeName", nullptr, true);
869 const char *addCoefRangeName = pc.getString("addCoefRange", nullptr, true);
870 const bool ext = interpretExtendedCmdArg(pdf, pc.getInt("ext"));
871
872 int splitRange = pc.getInt("splitRange");
873 int cloneData = pc.getInt("cloneData");
874 auto offset = static_cast<RooFit::OffsetMode>(pc.getInt("doOffset"));
875
876 if (pc.hasProcessed("Range")) {
877 double rangeLo = pc.getDouble("rangeLo");
878 double rangeHi = pc.getDouble("rangeHi");
879
880 // Create range with name 'fit' with above limits on all observables
881 RooArgSet obs;
882 pdf.getObservables(data.get(), obs);
883 for (auto *rrv : dynamic_range_cast<RooRealVar *>(obs)) {
884 if (rrv)
885 rrv->setRange("fit", rangeLo, rangeHi);
886 }
887
888 // Set range name to be fitted to "fit"
889 rangeName = "fit";
890 }
891
892 // Set the fitrange attribute of th PDF, add observables ranges for plotting
893 resetFitrangeAttributes(pdf, data, baseName, rangeName, splitRange);
894
895 RooArgSet projDeps;
896 auto tmp = pc.getSet("projDepSet");
897 if (tmp) {
898 projDeps.add(*tmp);
899 }
900
901 const std::string globalObservablesSource = pc.getString("globssource", "data", false);
902 if (globalObservablesSource != "data" && globalObservablesSource != "model") {
903 std::string errMsg = "RooAbsPdf::fitTo: GlobalObservablesSource can only be \"data\" or \"model\"!";
904 oocoutE(&pdf, InputArguments) << errMsg << std::endl;
905 throw std::invalid_argument(errMsg);
906 }
907 const bool takeGlobalObservablesFromData = globalObservablesSource == "data";
908
909 // Lambda function to create the correct constraint term for a PDF. In old
910 // RooFit, we use this PDF itself as the argument, for the new BatchMode
911 // we're passing a clone.
912 auto createConstr = [&]() -> std::unique_ptr<RooAbsReal> {
913 return createConstraintTerm(baseName + "_constr", // name
914 pdf, // pdf
915 data, // data
916 pc.getSet("cPars"), // Constrain RooCmdArg
917 pc.getSet("extCons"), // ExternalConstraints RooCmdArg
918 pc.getSet("glObs"), // GlobalObservables RooCmdArg
919 pc.getString("globstag", nullptr, true), // GlobalObservablesTag RooCmdArg
920 takeGlobalObservablesFromData); // From GlobalObservablesSource RooCmdArg
921 };
922
923 auto evalBackend = static_cast<RooFit::EvalBackend::Value>(pc.getInt("EvalBackend"));
924
925 // Construct BatchModeNLL if requested
926 if (evalBackend != RooFit::EvalBackend::Value::Legacy) {
927
928 RooArgSet normSet;
929 pdf.getObservables(data.get(), normSet);
930
931 auto *simPdfForProjDeps = dynamic_cast<RooSimultaneous const *>(&pdf);
932 if (simPdfForProjDeps && simPdfForProjDeps->indexCatIsObservable(normSet)) {
933 for (auto i : projDeps) {
934 auto res = normSet.find(i->GetName());
935 if (res != nullptr) {
936 res->setAttribute("__conditional__");
937 }
938 }
939 } else {
940 normSet.remove(projDeps);
941 }
942
943 std::unique_ptr<RooAbsPdf> pdfClone =
944 compilePdfForFit(pdf, normSet, rangeName, splitRange, addCoefRangeName, /*likelihoodMode=*/true);
945
946 if (addCoefRangeName) {
947 oocxcoutI(&pdf, Fitting) << "RooAbsPdf::fitTo(" << pdf.GetName()
948 << ") fixing interpretation of coefficients of any component to range "
949 << addCoefRangeName << "\n";
950 }
951
952 std::unique_ptr<RooAbsReal> compiledConstr;
953 if (std::unique_ptr<RooAbsReal> constr = createConstr()) {
954 compiledConstr = RooFit::Detail::compileForNormSet(*constr, *data.get());
955 compiledConstr->addOwnedComponents(std::move(constr));
956 }
957
958 auto nll = createNLLNew(*pdfClone, data, std::move(compiledConstr), rangeName ? rangeName : "", projDeps, ext,
959 pc.getDouble("IntegrateBins"), offset);
960
961 const double correction = pdfClone->getCorrection();
962
963 if (correction > 0) {
964 oocoutI(&pdf, Fitting) << "[FitHelpers] Detected correction term from RooAbsPdf::getCorrection(). "
965 << "Adding penalty to NLL." << std::endl;
966
967 // Convert the multiplicative correction to an additive term in -log L
968 auto penaltyTerm = std::make_unique<RooConstVar>((baseName + "_Penalty").c_str(),
969 "Penalty term from getCorrection()", correction);
970
971 // add penalty and NLL
972 auto correctedNLL = std::make_unique<RooAddition>((baseName + "_corrected").c_str(), "NLL + penalty",
973 RooArgSet{*nll, *penaltyTerm});
974
975 // transfer ownership of terms
976 correctedNLL->addOwnedComponents(std::move(nll), std::move(penaltyTerm));
977 nll = std::move(correctedNLL);
978 }
979
980 const int nWorkers = effectiveNumWorkers(pdf, evalBackend, pc.getInt("numcpu"));
981
982 auto nllWrapper = std::make_unique<RooFit::Experimental::RooEvaluatorWrapper>(
983 *nll, &data, evalBackend == RooFit::EvalBackend::Value::Cuda, rangeName ? rangeName : "", pdfClone.get(),
984 takeGlobalObservablesFromData, nWorkers);
985
986 // We destroy the timing scrope for createNLL prematurely, because we
987 // separately measure the time for jitting and gradient creation
988 // inside the RooFuncWrapper.
989 timingScope.reset();
990
991 if (evalBackend == RooFit::EvalBackend::Value::Codegen) {
992 nllWrapper->generateGradient();
993 }
995 nllWrapper->setUseGeneratedFunctionCode(true);
996 }
997
998 nllWrapper->addOwnedComponents(std::move(nll));
999 nllWrapper->addOwnedComponents(std::move(pdfClone));
1000
1001 return nllWrapper;
1002 }
1003
1004 std::unique_ptr<RooAbsReal> nll;
1005
1006#ifdef ROOFIT_LEGACY_EVAL_BACKEND
1007 printLegacyEvalBackendWarning(pdf);
1008
1009 bool verbose = pc.getInt("verbose");
1010
1011 int numcpu = pc.getInt("numcpu");
1012 int numcpu_strategy = pc.getInt("interleave");
1013 // strategy 3 works only for RooSimultaneous.
1014 if (numcpu_strategy == 3 && !pdf.InheritsFrom("RooSimultaneous")) {
1015 oocoutW(&pdf, Minimization) << "Cannot use a NumCpu Strategy = 3 when the pdf is not a RooSimultaneous, "
1016 "falling back to default strategy = 0"
1017 << std::endl;
1018 numcpu_strategy = 0;
1019 }
1020 RooFit::MPSplit interl = (RooFit::MPSplit)numcpu_strategy;
1021
1022 auto binnedLInfo = RooHelpers::getBinnedL(pdf);
1023 RooAbsPdf &actualPdf = binnedLInfo.binnedPdf ? *binnedLInfo.binnedPdf : pdf;
1024
1025 // Construct NLL
1027 RooAbsTestStatistic::Configuration cfg;
1028 cfg.addCoefRangeName = addCoefRangeName ? addCoefRangeName : "";
1029 cfg.nCPU = numcpu;
1030 cfg.interleave = interl;
1031 cfg.verbose = verbose;
1032 cfg.splitCutRange = static_cast<bool>(splitRange);
1033 cfg.cloneInputData = static_cast<bool>(cloneData);
1034 cfg.integrateOverBinsPrecision = pc.getDouble("IntegrateBins");
1035 cfg.binnedL = binnedLInfo.isBinnedL;
1036 cfg.takeGlobalObservablesFromData = takeGlobalObservablesFromData;
1037 cfg.rangeName = rangeName ? rangeName : "";
1038 auto nllVar = std::make_unique<RooNLLVar>(baseName.c_str(), "-log(likelihood)", actualPdf, data, projDeps, ext, cfg);
1039 nllVar->enableBinOffsetting(offset == RooFit::OffsetMode::Bin);
1040 nll = std::move(nllVar);
1042
1043 // Include constraints, if any, in likelihood
1044 if (std::unique_ptr<RooAbsReal> constraintTerm = createConstr()) {
1045
1046 // Even though it is technically only required when the computation graph
1047 // is changed because global observables are taken from data, it is safer
1048 // to clone the constraint model in general to reset the normalization
1049 // integral caches and avoid ASAN build failures (the PDF of the main
1050 // measurement is cloned too anyway, so not much overhead). This can be
1051 // reconsidered after the caching of normalization sets by pointer is changed
1052 // to a more memory-safe solution.
1053 constraintTerm = RooHelpers::cloneTreeWithSameParameters(*constraintTerm, data.get());
1054
1055 // Redirect the global observables to the ones from the dataset if applicable.
1056 constraintTerm->setData(data, false);
1057
1058 // The computation graph for the constraints is very small, no need to do
1059 // the tracking of clean and dirty nodes here.
1060 constraintTerm->setOperMode(RooAbsArg::ADirty);
1061
1062 auto orignll = std::move(nll);
1063 nll = std::make_unique<RooAddition>((baseName + "_with_constr").c_str(), "nllWithCons",
1064 RooArgSet(*orignll, *constraintTerm));
1065 nll->addOwnedComponents(std::move(orignll), std::move(constraintTerm));
1066 }
1067
1069 nll->enableOffsetting(true);
1070 }
1071
1072 if (const double correction = pdf.getCorrection(); correction > 0) {
1073 oocoutI(&pdf, Fitting) << "[FitHelpers] Detected correction term from RooAbsPdf::getCorrection(). "
1074 << "Adding penalty to NLL." << std::endl;
1075
1076 // Convert the multiplicative correction to an additive term in -log L
1077 auto penaltyTerm = std::make_unique<RooConstVar>((baseName + "_Penalty").c_str(),
1078 "Penalty term from getCorrection()", correction);
1079
1080 auto correctedNLL = std::make_unique<RooAddition>(
1081 // add penalty and NLL
1082 (baseName + "_corrected").c_str(), "NLL + penalty", RooArgSet(*nll, *penaltyTerm));
1083
1084 // transfer ownership of terms
1085 correctedNLL->addOwnedComponents(std::move(nll), std::move(penaltyTerm));
1086 nll = std::move(correctedNLL);
1087 }
1088#else
1089 throw std::runtime_error("RooFit was not built with the legacy evaluation backend");
1090#endif
1091
1092 return nll;
1093}
1094
1095std::unique_ptr<RooAbsReal> createChi2(RooAbsReal &real, RooDataHist &data, const RooLinkedList &cmdList)
1096{
1097 checkNestedSimultaneous(real, *data.get());
1098
1099 RooCmdConfig pc("createChi2(" + std::string(real.GetName()) + ")");
1100
1101 pc.defineInt("EvalBackend", "EvalBackend", 0, static_cast<int>(RooFit::EvalBackend::defaultValue()));
1102 pc.defineInt("numcpu", "NumCPU", 0, 1);
1103 pc.defineInt("verbose", "Verbose", 0, 0);
1104 pc.defineString("rangeName", "RangeWithName", 0, "", true);
1105 pc.defineDouble("rangeLo", "Range", 0, -999.);
1106 pc.defineDouble("rangeHi", "Range", 1, -999.);
1107 pc.defineMutex("Range", "RangeWithName");
1108 pc.defineInt("etype", "DataError", 0, (Int_t)RooDataHist::Auto);
1109 pc.defineInt("extended", "Extended", 0, extendedFitDefault);
1110 pc.defineInt("splitRange", "SplitRange", 0, 0);
1111 pc.defineDouble("integrate_bins", "IntegrateBins", 0, -1);
1112 pc.defineString("addCoefRange", "SumCoefRange", 0, "");
1113 pc.allowUndefined();
1114
1115 pc.process(cmdList);
1116 if (!pc.ok(true)) {
1117 return nullptr;
1118 }
1119
1120 // Clear possible range attributes from previous fits.
1121 real.removeStringAttribute("fitrange");
1122
1123 std::string baseName = "chi2_" + std::string(real.GetName()) + "_" + data.GetName();
1124
1125 auto evalBackend = static_cast<RooFit::EvalBackend::Value>(pc.getInt("EvalBackend"));
1126
1127 RooDataHist::ErrorType etype = static_cast<RooDataHist::ErrorType>(pc.getInt("etype"));
1128 // Resolve Auto to a concrete mode so it's consistent across backends.
1129 if (etype == RooDataHist::Auto) {
1130 etype = data.isNonPoissonWeighted() ? RooDataHist::SumW2 : RooDataHist::Expected;
1131 }
1132
1133 auto *pdf = dynamic_cast<RooAbsPdf *>(&real);
1134 const char *rangeName = pc.getString("rangeName", nullptr, true);
1135
1136 // Translate Range(lo, hi) into a "fit" named range on all observables.
1137 if (pc.hasProcessed("Range")) {
1138 const double rangeLo = pc.getDouble("rangeLo");
1139 const double rangeHi = pc.getDouble("rangeHi");
1140 RooArgSet obs;
1141 real.getObservables(data.get(), obs);
1142 for (auto *rrv : dynamic_range_cast<RooRealVar *>(obs)) {
1143 if (rrv) {
1144 rrv->setRange("fit", rangeLo, rangeHi);
1145 }
1146 }
1147 rangeName = "fit";
1148 }
1149
1150 if (evalBackend != RooFit::EvalBackend::Value::Legacy) {
1152
1153 const int splitRange = pc.getInt("splitRange");
1154 resetFitrangeAttributes(real, data, baseName, rangeName, splitRange);
1155
1156 std::unique_ptr<RooFit::Experimental::RooEvaluatorWrapper> wrapper;
1157
1158 const int nWorkers = effectiveNumWorkers(real, evalBackend, pc.getInt("numcpu"));
1159
1160 // Function mode: the input is a non-pdf RooAbsReal. We can short-circuit
1161 // the pdf-compilation pipeline since there's no real pdf to normalize.
1162 if (!pdf) {
1163 RooArgSet observables;
1164 real.getObservables(data.get(), observables);
1165 RooNLLVarNew::Config cfg;
1166 cfg.statistic = RooNLLVarNew::Statistic::Chi2;
1167 cfg.chi2ErrorType = etype;
1168 auto chi2 = std::make_unique<RooNLLVarNew>(baseName.c_str(), baseName.c_str(), real, observables, cfg);
1169 wrapper = std::make_unique<RooFit::Experimental::RooEvaluatorWrapper>(
1170 *chi2, &data, evalBackend == RooFit::EvalBackend::Value::Cuda, rangeName ? rangeName : "",
1171 /*simPdf=*/nullptr,
1172 /*takeGlobalObservablesFromData=*/true, nWorkers);
1173 wrapper->addOwnedComponents(std::move(chi2));
1174 } else {
1175 const bool extended = interpretExtendedCmdArg(*pdf, pc.getInt("extended"));
1176
1177 RooArgSet normSet;
1178 pdf->getObservables(data.get(), normSet);
1179
1180 oocxcoutI(pdf, Fitting) << "createChi2(" << pdf->GetName()
1181 << ") fixing normalization set for coefficient determination to observables in data\n";
1182 pdf->fixAddCoefNormalization(normSet, false);
1183
1184 std::unique_ptr<RooAbsPdf> pdfClone =
1185 compilePdfForFit(*pdf, normSet, rangeName, splitRange, pc.getString("addCoefRange", nullptr, true),
1186 /*likelihoodMode=*/false);
1187
1188 RooArgList binSamplingPdfs;
1189 RooAbsPdf &finalPdf =
1190 applyIntegrateBinsWrapping(*pdfClone, data, pc.getDouble("integrate_bins"), binSamplingPdfs);
1191
1192 std::unique_ptr<RooAbsReal> chi2;
1193 auto *simPdfClone = dynamic_cast<RooSimultaneous *>(&finalPdf);
1194 // Like in createNLLNew(): a "switch"-mode RooSimultaneous (index
1195 // category not among the data columns) is treated as an ordinary pdf.
1196 if (simPdfClone && simPdfClone->indexCatIsObservable(*data.get())) {
1197 chi2 = std::unique_ptr<RooAbsReal>{dynamic_cast<RooAbsReal *>(
1198 createSimultaneousChi2(*simPdfClone, rangeName ? rangeName : "", extended, etype).release())};
1199 } else {
1200 RooArgSet observables;
1201 finalPdf.getObservables(data.get(), observables);
1202 RooNLLVarNew::Config cfg;
1203 cfg.statistic = RooNLLVarNew::Statistic::Chi2;
1204 cfg.extended = extended;
1205 cfg.chi2ErrorType = etype;
1206 chi2 = std::make_unique<RooNLLVarNew>(baseName.c_str(), baseName.c_str(), finalPdf, observables, cfg);
1207 }
1208
1209 wrapper = std::make_unique<RooFit::Experimental::RooEvaluatorWrapper>(
1210 *chi2, &data, evalBackend == RooFit::EvalBackend::Value::Cuda, rangeName ? rangeName : "", pdfClone.get(),
1211 /*takeGlobalObservablesFromData=*/true, nWorkers);
1212 wrapper->addOwnedComponents(std::move(binSamplingPdfs));
1213 wrapper->addOwnedComponents(std::move(chi2));
1214 wrapper->addOwnedComponents(std::move(pdfClone));
1215 }
1216
1217 if (evalBackend == RooFit::EvalBackend::Value::Codegen) {
1218 wrapper->generateGradient();
1219 }
1220 if (evalBackend == RooFit::EvalBackend::Value::CodegenNoGrad) {
1221 wrapper->setUseGeneratedFunctionCode(true);
1222 }
1223
1225 return wrapper;
1226 }
1227
1228#ifdef ROOFIT_LEGACY_EVAL_BACKEND
1229 printLegacyEvalBackendWarning(real);
1230
1231 RooAbsTestStatistic::Configuration cfg;
1232
1234
1235 bool extended = false;
1236 if (pdf) {
1237 extended = interpretExtendedCmdArg(*pdf, pc.getInt("extended"));
1238 }
1239
1240 const char *addCoefRangeName = pc.getString("addCoefRange", nullptr, true);
1241 int splitRange = pc.getInt("splitRange");
1242
1243 // Set the fitrange attribute of th PDF, add observables ranges for plotting
1244 resetFitrangeAttributes(real, data, baseName, rangeName, splitRange);
1245
1246 cfg.rangeName = rangeName ? rangeName : "";
1247 cfg.nCPU = pc.getInt("numcpu");
1248 cfg.interleave = RooFit::Interleave;
1249 cfg.verbose = static_cast<bool>(pc.getInt("verbose"));
1250 cfg.cloneInputData = false;
1251 cfg.integrateOverBinsPrecision = pc.getDouble("integrate_bins");
1252 cfg.addCoefRangeName = addCoefRangeName ? addCoefRangeName : "";
1253 cfg.splitCutRange = static_cast<bool>(splitRange);
1254 auto chi2 = std::make_unique<RooChi2Var>(baseName.c_str(), baseName.c_str(), real, static_cast<RooDataHist &>(data),
1255 extended, etype, cfg);
1256
1258
1259 return chi2;
1260#else
1261 throw std::runtime_error("createChi2() is not supported without the legacy evaluation backend");
1262 return nullptr;
1263#endif
1264}
1265
1266std::unique_ptr<RooFitResult> fitTo(RooAbsReal &real, RooAbsData &data, const RooLinkedList &cmdList, bool chi2)
1267{
1268 const bool isDataHist = dynamic_cast<RooDataHist const *>(&data);
1269
1270 RooCmdConfig pc("fitTo(" + std::string(real.GetName()) + ")");
1271
1272 RooLinkedList fitCmdList(cmdList);
1273 std::string nllCmdListString;
1274
1275 // Check on the raw command list whether parallel minimization is requested,
1276 // because in that case ModularL(true) is implied below. The check needs to
1277 // happen before filtering the command list: with a modular likelihood,
1278 // offsetting is configured on the minimizer instead of the likelihood, so
1279 // the OffsetLikelihood argument must not be forwarded to createNLL(), where
1280 // it is mutually exclusive with ModularL.
1281 auto cmdEnabled = [&cmdList](const char *cmdName) {
1282 auto *arg = static_cast<RooCmdArg *>(cmdList.FindObject(cmdName));
1283 return arg && arg->getInt(0) != 0;
1284 };
1285 const bool parallelRequested =
1286 cmdEnabled("Parallelize") || cmdEnabled("ParallelGradientOptions") || cmdEnabled("ParallelDescentOptions");
1287
1288 if (!chi2) {
1289 nllCmdListString = "ProjectedObservables,Extended,Range,"
1290 "RangeWithName,SumCoefRange,NumCPU,SplitRange,Constrained,Constrain,ExternalConstraints,"
1291 "CloneData,GlobalObservables,GlobalObservablesSource,GlobalObservablesTag,"
1292 "EvalBackend,IntegrateBins,ModularL";
1293
1294 if (!parallelRequested && !cmdEnabled("ModularL")) {
1295 nllCmdListString += ",OffsetLikelihood";
1296 }
1297 } else {
1298 auto createChi2DataHistCmdArgs = "Range,RangeWithName,NumCPU,IntegrateBins,ProjectedObservables,"
1299 "AddCoefRange,SplitRange,DataError,Extended,EvalBackend";
1300 auto createChi2DataSetCmdArgs = "YVar,Integrate,RangeWithName,NumCPU,Verbose";
1301 nllCmdListString += isDataHist ? createChi2DataHistCmdArgs : createChi2DataSetCmdArgs;
1302 }
1303
1304 RooLinkedList nllCmdList = pc.filterCmdList(fitCmdList, nllCmdListString.c_str());
1305
1306 pc.defineDouble("prefit", "Prefit", 0, 0);
1307 defineMinimizationOptions(pc);
1308
1309 // Process and check varargs
1310 pc.process(fitCmdList);
1311 if (!pc.ok(true)) {
1312 return nullptr;
1313 }
1314
1315 // TimingAnalysis works only for RooSimultaneous.
1316 if (pc.getInt("timingAnalysis") && !real.InheritsFrom("RooSimultaneous")) {
1317 oocoutW(&real, Minimization) << "The timingAnalysis feature was built for minimization with RooSimultaneous "
1318 "and is not implemented for other PDF's. Please create a RooSimultaneous to "
1319 "enable this feature."
1320 << std::endl;
1321 }
1322
1323 // Decode command line arguments
1324 double prefit = pc.getDouble("prefit");
1325
1326 if (prefit != 0) {
1327 size_t nEvents = static_cast<size_t>(prefit * data.numEntries());
1328 if (prefit > 0.5 || nEvents < 100) {
1329 oocoutW(&real, InputArguments) << "PrefitDataFraction should be in suitable range."
1330 << "With the current PrefitDataFraction=" << prefit
1331 << ", the number of events would be " << nEvents << " out of "
1332 << data.numEntries() << ". Skipping prefit..." << std::endl;
1333 } else {
1334 size_t step = data.numEntries() / nEvents;
1335
1336 RooDataSet tiny("tiny", "tiny", *data.get(), data.isWeighted() ? RooFit::WeightVar() : RooCmdArg());
1337
1338 for (int i = 0; i < data.numEntries(); i += step) {
1339 const RooArgSet *event = data.get(i);
1340 tiny.add(*event, data.weight());
1341 }
1342 RooLinkedList tinyCmdList(cmdList);
1343 pc.filterCmdList(tinyCmdList, "Prefit,Hesse,Minos,Verbose,Save,Timer");
1344 RooCmdArg hesse_option = RooFit::Hesse(false);
1345 RooCmdArg print_option = RooFit::PrintLevel(-1);
1346
1347 tinyCmdList.Add(&hesse_option);
1348 tinyCmdList.Add(&print_option);
1349
1350 fitTo(real, tiny, tinyCmdList, chi2);
1351 }
1352 }
1353
1354 RooCmdArg modularL_option;
1355 if (parallelRequested) {
1356 // Set to new style likelihood if parallelization is requested
1357 modularL_option = RooFit::ModularL(true);
1358 nllCmdList.Add(&modularL_option);
1359 }
1360
1361 std::unique_ptr<RooAbsReal> nll;
1362 if (chi2) {
1363 if (isDataHist) {
1364 nll = std::unique_ptr<RooAbsReal>{real.createChi2(static_cast<RooDataHist &>(data), nllCmdList)};
1365 }
1366 } else {
1367 nll = std::unique_ptr<RooAbsReal>{dynamic_cast<RooAbsPdf &>(real).createNLL(data, nllCmdList)};
1368 }
1369
1370 if (!nll) {
1371 oocoutE(&real, InputArguments) << "RooFit::FitHelpers::fitTo(" << real.GetName()
1372 << ") could not create the test statistic, no fit performed" << std::endl;
1373 return nullptr;
1374 }
1375
1376 return RooFit::FitHelpers::minimize(real, *nll, data, pc);
1377}
1378
1379} // namespace RooFit::FitHelpers
1380
1381/// \endcond
header file containing the templated implementation of matrix inversion routines for use with ROOT's ...
ROOT::RRangeCast< T, true, Range_t > dynamic_range_cast(Range_t &&coll)
ROOT::RRangeCast< T, false, Range_t > static_range_cast(Range_t &&coll)
cudaEvent_t event
#define oocoutW(o, a)
#define oocoutE(o, a)
#define oocoutI(o, a)
#define oocxcoutI(o, a)
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
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 Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
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 Int_t Int_t Window_t child
char name[80]
Definition TGX11.cxx:142
class to compute the Cholesky decomposition of a matrix
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:77
virtual bool isCategory() const
Definition RooAbsArg.h:502
void setStringAttribute(const Text_t *key, const Text_t *value)
Associate string 'value' to this object under key 'key'.
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 removeStringAttribute(const Text_t *key)
Delete a string attribute with a given key.
RooFit::OwningPtr< RooArgSet > getVariables(bool stripDisconnected=true) const
Return RooArgSet with all variables (tree leaf nodes of expression tree)
void setAttribute(const Text_t *name, bool value=true)
Set (default) or clear a named boolean attribute of this object.
void branchNodeServerList(RooAbsCollection *list, const RooAbsArg *arg=nullptr, bool recurseNonDerived=false) const
Fill supplied list with all branch nodes of the arg tree starting with ourself as top node.
Abstract base class for objects that represent a discrete value that can be set from the outside,...
virtual bool remove(const RooAbsArg &var, bool silent=false, bool matchByNameOnly=false)
Remove the specified argument from our list.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
void assign(const RooAbsCollection &other) const
Sets the value, cache and constant attribute of any argument in our set that also appears in the othe...
Storage_t::size_type size() const
RooAbsArg * first() const
virtual bool addOwned(RooAbsArg &var, bool silent=false)
Add an argument and transfer the ownership to the collection.
RooAbsArg * find(const char *name) const
Find object with given name in list.
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:55
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const override
virtual double expectedEvents(const RooArgSet *nset) const
Return expected number of events to be used in calculation of extended likelihood.
void setNormRange(const char *rangeName)
virtual double getCorrection() const
This function returns the penalty term.
@ CanBeExtended
Definition RooAbsPdf.h:208
@ MustBeExtended
Definition RooAbsPdf.h:208
@ CanNotBeExtended
Definition RooAbsPdf.h:208
const char * normRange() const
Definition RooAbsPdf.h:246
virtual ExtendMode extendMode() const
Returns ability of PDF to provide extended likelihood terms.
Definition RooAbsPdf.h:212
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:107
virtual void fixAddCoefNormalization(const RooArgSet &addNormSet=RooArgSet(), bool force=true)
Fix the interpretation of the coefficient of any RooAddPdf component in the expression tree headed by...
virtual void fixAddCoefRange(const char *rangeName=nullptr, bool force=true)
Fix the interpretation of the coefficient of any RooAddPdf component in the expression tree headed by...
static void setEvalErrorLoggingMode(ErrorLoggingMode m)
Set evaluation error logging mode.
RooFit::OwningPtr< RooAbsReal > createChi2(RooDataHist &data, CmdArgs_t const &... cmdArgs)
Create a variable from a histogram and this function.
Definition RooAbsReal.h:190
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooAbsArg * at(Int_t idx) const
Return object at given index, or nullptr if index is out of range.
Definition RooArgList.h:110
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
RooArgSet * selectByAttrib(const char *name, bool value) const
Use RooAbsCollection::selectByAttrib(), but return as RooArgSet.
Definition RooArgSet.h:144
static std::unique_ptr< RooAbsPdf > create(RooAbsPdf &pdf, RooAbsData const &data, double precision)
Creates a wrapping RooBinSamplingPdf if appropriate.
Object to represent discrete states.
Definition RooCategory.h:28
Named container for two doubles, two integers two object points and three string pointers that can be...
Definition RooCmdArg.h:26
Configurable parser for RooCmdArg named arguments.
void defineMutex(const char *head, Args_t &&... tail)
Define arguments where any pair is mutually exclusive.
bool process(const RooCmdArg &arg)
Process given RooCmdArg.
bool hasProcessed(const char *cmdName) const
Return true if RooCmdArg with name 'cmdName' has been processed.
double getDouble(const char *name, double defaultValue=0.0) const
Return double property registered with name 'name'.
bool defineDouble(const char *name, const char *argName, int doubleNum, double defValue=0.0)
Define double property name 'name' mapped to double in slot 'doubleNum' in RooCmdArg with name argNam...
RooArgSet * getSet(const char *name, RooArgSet *set=nullptr) const
Return RooArgSet property registered with name 'name'.
bool defineSet(const char *name, const char *argName, int setNum, const RooArgSet *set=nullptr)
Define TObject property name 'name' mapped to object in slot 'setNum' in RooCmdArg with name argName ...
bool ok(bool verbose) const
Return true of parsing was successful.
const char * getString(const char *name, const char *defaultValue="", bool convEmptyToNull=false) const
Return string property registered with name 'name'.
bool defineString(const char *name, const char *argName, int stringNum, const char *defValue="", bool appendMode=false)
Define double property name 'name' mapped to double in slot 'stringNum' in RooCmdArg with name argNam...
bool defineInt(const char *name, const char *argName, int intNum, int defValue=0)
Define integer property name 'name' mapped to integer in slot 'intNum' in RooCmdArg with name argName...
void allowUndefined(bool flag=true)
If flag is true the processing of unrecognized RooCmdArgs is not considered an error.
int getInt(const char *name, int defaultValue=0) const
Return integer property registered with name 'name'.
RooLinkedList filterCmdList(RooLinkedList &cmdInList, const char *cmdNameList, bool removeFromInList=true) const
Utility function to filter commands listed in cmdNameList from cmdInList.
Container class to hold N-dimensional binned data.
Definition RooDataHist.h:40
Container class to hold unbinned data.
Definition RooDataSet.h:32
static Value & defaultValue()
A RooFormulaVar is a generic implementation of a real-valued object, which takes a RooArgList of serv...
Collection class for internal use, storing a collection of RooAbsArg pointers in a doubly linked list...
virtual void Add(TObject *arg)
TObject * FindObject(const char *name) const override
Return pointer to object with given name.
Wrapper class around ROOT::Math::Minimizer that provides a seamless interface between the minimizer f...
RooFit::OwningPtr< RooFitResult > save(const char *name=nullptr, const char *title=nullptr)
Save and return a RooFitResult snapshot of current minimizer status.
int hesse()
Execute HESSE.
void applyCovarianceMatrix(TMatrixDSym const &V)
Apply results of given external covariance matrix.
Variable that can be changed from the outside.
Definition RooRealVar.h:37
static TClass * Class()
void setRange(const char *name, double min, double max, bool shared=true)
Set a fit or plotting range.
Facilitates simultaneous fitting of multiple PDFs to subsets of a given dataset.
RooAbsPdf * getPdf(RooStringView catName) const
Return the p.d.f associated with the given index category name.
void wrapPdfsInBinSamplingPdfs(RooAbsData const &data, double precision)
Wraps the components of this RooSimultaneous in RooBinSamplingPdfs.
bool indexCatIsObservable(RooArgSet const &vars) const
Check if the index category is among the variables vars, matching by name.
const RooAbsCategoryLValue & indexCat() const
Int_t GetNrows() const
TMatrixTSym< Element > & Similarity(const TMatrixT< Element > &n)
Calculate B * (*this) * B^T , final matrix will be (nrowsb x nrowsb) This is a similarity transform w...
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:548
RooCmdArg WeightVar(const char *name="weight", bool reinterpretAsWeight=false)
RooCmdArg Hesse(bool flag=true)
RooCmdArg ModularL(bool flag=false)
RooCmdArg PrintLevel(Int_t code)
RVec< PromoteType< T > > log(const RVec< T > &v)
Definition RVec.hxx:1821
CoordSystem::Scalar get(DisplacementVector2D< CoordSystem, Tag > const &p)
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
double nll(double pdf, double weight, int binnedL, int doBinOffset)
Definition MathFuncs.h:449
std::unique_ptr< T > compileForNormSet(T const &arg, RooArgSet const &normSet)
OffsetMode
For setting the offset mode with the Offset() command argument to RooAbsPdf::fitTo()
std::unique_ptr< T > cloneTreeWithSameParameters(T const &arg, RooArgSet const *observables=nullptr)
Clone RooAbsArg object and reattach to original parameters.
BinnedLOutput getBinnedL(RooAbsPdf const &pdf)
const char * Value
Definition TXMLSetup.cxx:72
static std::size_t defaultNComponentTasks
Definition Config.h:38
Config argument to RooMinimizer constructor.
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4