48#ifdef ROOFIT_LEGACY_EVAL_BACKEND
52#ifdef ROOFIT_MULTIPROCESS
57using RooFit::Detail::RooNLLVarNew;
61constexpr int extendedFitDefault = 2;
63#ifdef ROOFIT_LEGACY_EVAL_BACKEND
65void printLegacyEvalBackendWarning(
RooAbsReal const &topLevelArg)
67 oocoutW(&topLevelArg, InputArguments)
68 <<
"The legacy evaluation backend is deprecated and will be removed in ROOT 6.44.\n"
69 "Please use the default \"cpu\" evaluation backend instead, i.e., don't pass RooFit::EvalBackend(\"legacy\")\n"
70 "or RooFit::BatchMode(\"off\") anymore. If the default backend does not work for your use case, please\n"
71 "report it by opening an issue on the ROOT GitHub repository."
91 logpdf.getObservables(
data.get(), obs);
99 <<
"RooAbsPdf::fitTo(" << pdf.
GetName()
100 <<
") WARNING: Asymptotic error correction is requested for a binned data set. "
101 "This method is not designed to handle binned data. A standard chi2 fit will likely be more suitable.";
105 std::unique_ptr<RooFitResult> rw(minimizer.
save());
109 <<
"RooAbsPdf::fitTo(" << pdf.
GetName()
110 <<
") Calculating covariance matrix according to the asymptotically correct approach. If you find this "
111 "method useful please consider citing https://arxiv.org/abs/1911.01303.\n";
114 int nFloatPars = rw->floatParsFinal().size();
116 for (
int k = 0; k < nFloatPars; k++) {
117 for (
int l = 0;
l < nFloatPars;
l++) {
123 std::vector<std::unique_ptr<RooDerivative>> derivatives;
124 const RooArgList &floated = rw->floatParsFinal();
126 logpdf.getParameters(
data.get(), allparams);
127 std::unique_ptr<RooArgSet> floatingparams{allparams.
selectByAttrib(
"Constant",
false)};
129 const double eps = 1.0e-4;
132 for (
const auto paramresult : floated) {
133 auto paraminternal =
static_cast<RooRealVar *
>(floatingparams->find(*paramresult));
135 double error =
static_cast<RooRealVar *
>(paramresult)->getError();
136 derivatives.emplace_back(logpdf.derivative(*paraminternal, obs, 1, eps * error));
141 std::vector<double> diffs_expected(floated.
size(), 0.0);
143 for (std::size_t k = 0; k < floated.
size(); k++) {
144 const auto paramresult =
static_cast<RooRealVar *
>(floated.
at(k));
145 auto paraminternal =
static_cast<RooRealVar *
>(floatingparams->find(*paramresult));
147 *paraminternal = paramresult->
getVal();
148 double error = paramresult->getError();
149 paraminternal->setVal(paramresult->getVal() + eps * error);
151 paraminternal->setVal(paramresult->getVal() - eps * error);
153 *paraminternal = paramresult->getVal();
154 double diff = (expected_plus - expected_minus) / (2.0 * eps * error);
155 diffs_expected[k] = diff;
160 for (
int j = 0; j <
data.numEntries(); j++) {
164 std::vector<double> diffs(floated.
size(), 0.0);
165 for (std::size_t k = 0; k < floated.
size(); k++) {
166 const auto paramresult =
static_cast<RooRealVar *
>(floated.
at(k));
167 auto paraminternal =
static_cast<RooRealVar *
>(floatingparams->find(*paramresult));
169 double diff = derivatives[k]->getVal();
171 *paraminternal = paramresult->getVal();
176 for (std::size_t k = 0; k < floated.
size(); k++) {
177 for (std::size_t
l = 0;
l < floated.
size();
l++) {
178 num(k,
l) +=
data.weightSquared() * (diffs[k] + diffs_expected[k]) * (diffs[
l] + diffs_expected[
l]);
182 num.Similarity(matV);
190 return rw->covQual();
208 std::unique_ptr<RooFitResult> rw{minimizer.
save()};
209 nll.applyWeightSquared(
true);
211 <<
") Calculating sum-of-weights-squared correction matrix for covariance matrix\n";
213 std::unique_ptr<RooFitResult> rw2{minimizer.
save()};
214 nll.applyWeightSquared(
false);
222 <<
") ERROR: Cannot apply sum-of-weights correction to covariance matrix: correction "
223 "matrix calculated with weight-squared is singular\n";
231 for (
int i = 0; i < matC.
GetNrows(); ++i) {
232 for (
int j = 0; j < i; ++j) {
233 matC(j, i) = matC(i, j);
241 return std::min(rw->covQual(), rw2->covQual());
246struct MinimizerConfig {
247 double recoverFromNaN = 10.;
260 int doAsymptotic = -1;
264 bool enableParallelGradient =
false;
265 bool enableParallelDescent =
false;
266 int parallelDescentNumSplits = 0;
267 int parallelDescentSplitStrategy = 0;
268 bool timingAnalysis =
false;
271 std::string minAlg =
"minuit";
283 if (evalBackend == Value::Cuda) {
284 oocoutW(&arg, Fitting) <<
"The NumCPU() option is ignored by the CUDA evaluation backend." << std::endl;
287 if (evalBackend == Value::CodegenNoGrad) {
288 oocoutW(&arg, Fitting) <<
"The NumCPU() option has no effect with EvalBackend(\"codegen_no_grad\"), "
289 "because the test statistic is evaluated with single-threaded generated code."
293 if (evalBackend == Value::Codegen) {
294 oocxcoutI(&arg, Fitting) <<
"NumCPU(" << numCpu <<
") enables multi-threaded evaluation of large batches "
295 <<
"for test statistic values. The generated gradient code is not affected."
299 oocxcoutI(&arg, Fitting) <<
"NumCPU(" << numCpu <<
") enables multi-threaded evaluation of large batches in "
300 <<
"the RooBatchCompute library. The interleaving strategy argument of NumCPU() is "
301 <<
"ignored." << std::endl;
305bool interpretExtendedCmdArg(
RooAbsPdf const &pdf,
int extendedCmdArg)
308 if (extendedCmdArg == extendedFitDefault) {
312 <<
"p.d.f. provides expected number of events, including extended term in likelihood." << std::endl;
321 if (extendedCmdArg == 0) {
323 std::string errMsg =
"You used the Extended(false) option on a pdf where the fit MUST be extended! "
324 "The parameters are not well defined and you're getting nonsensical results.";
325 oocoutE(&pdf, InputArguments) << errMsg << std::endl;
328 return extendedCmdArg;
333void resetFitrangeAttributes(
RooAbsArg &pdf,
RooAbsData const &
data, std::string
const &baseName,
const char *rangeName,
342 if (!rangeName || splitRange)
348 std::string fitrangeValue;
350 for (
auto const &subrange : subranges) {
351 if (subrange.empty())
353 std::string fitrangeValueSubrange = std::string(
"fit_") + baseName;
354 if (subranges.size() > 1) {
355 fitrangeValueSubrange +=
"_" + subrange;
357 fitrangeValue += fitrangeValueSubrange +
",";
362 auto &observable =
static_cast<RooRealVar &
>(*arg);
364 observable.
setRange(fitrangeValueSubrange.c_str(), observable.getMin(subrange.c_str()),
365 observable.getMax(subrange.c_str()));
368 pdf.
setStringAttribute(
"fitrange", fitrangeValue.substr(0, fitrangeValue.size() - 1).c_str());
376template <
typename TermFactory>
377std::unique_ptr<RooAddition> createSimultaneousStat(
RooSimultaneous const &simPdf, std::string
const &rangeName,
378 std::string
const &combinedName, TermFactory &&makeTerm)
383 for (
auto const &catState : simCat) {
384 std::string
const &catName = catState.
first;
389 if (!rangeName.empty()) {
390 auto simCatAsRooCategory =
dynamic_cast<RooCategory const *
>(&simCat);
391 if (simCatAsRooCategory && !simCatAsRooCategory->isStateInRange(rangeName.c_str(), catIndex)) {
400 std::unique_ptr<RooArgSet> observables{
402 std::unique_ptr<RooNLLVarNew> term = makeTerm(*channelPdf, *observables);
403 term->setPrefix(std::string(
"_") + catName +
"_");
407 auto combined = std::make_unique<RooAddition>(combinedName.c_str(), combinedName.c_str(), terms);
408 combined->addOwnedComponents(std::move(terms));
412std::unique_ptr<RooAbsArg> createSimultaneousChi2(
RooSimultaneous const &simPdf, std::string
const &rangeName,
416 createSimultaneousStat(simPdf, rangeName,
"simChi2", [&](
RooAbsPdf &channelPdf,
RooArgSet const &observables) {
417 RooNLLVarNew::Config cfg;
418 cfg.statistic = RooNLLVarNew::Statistic::Chi2;
420 cfg.chi2ErrorType = etype;
421 auto name = std::string(
"chi2_") + channelPdf.
GetName();
422 return std::make_unique<RooNLLVarNew>(
name.c_str(),
name.c_str(), channelPdf, observables, cfg);
425 chi2->setAttribute(
"Chi2EvaluationActive");
429std::unique_ptr<RooAbsArg> createSimultaneousNLL(
RooSimultaneous const &simPdf,
bool isSimPdfExtended,
433 createSimultaneousStat(simPdf, rangeName,
"mynll", [&](
RooAbsPdf &channelPdf,
RooArgSet const &observables) {
434 RooNLLVarNew::Config cfg;
438 auto name = std::string(
"nll_") + channelPdf.
GetName();
439 return std::make_unique<RooNLLVarNew>(
name.c_str(),
name.c_str(), channelPdf, observables, cfg);
442 const int simCount =
nll->list().size();
444 child->setSimCount(simCount);
461 ownedOut.
addOwned(std::move(wrapped));
471class NormRangeScope {
473 NormRangeScope(
RooAbsPdf &pdf,
const char *rangeName,
bool splitRange) : _pdf{&pdf}
482 NormRangeScope(NormRangeScope
const &) =
delete;
483 NormRangeScope &operator=(NormRangeScope
const &) =
delete;
486 _pdf->setAttribute(
"SplitRange",
false);
487 _pdf->setStringAttribute(
"RangeName",
nullptr);
488 _pdf->setNormRange(_oldNormRange.empty() ?
nullptr : _oldNormRange.c_str());
493 std::string _oldNormRange;
502std::unique_ptr<RooAbsPdf> compilePdfForFit(
RooAbsPdf &pdf,
RooArgSet const &normSet,
const char *rangeName,
503 bool splitRange,
const char *addCoefRangeName,
bool likelihoodMode)
505 NormRangeScope scope{pdf, rangeName, splitRange};
508 ctx.setLikelihoodMode(likelihoodMode);
510 std::unique_ptr<RooAbsPdf> pdfClone{&
dynamic_cast<RooAbsPdf &
>(*head.release())};
512 if (addCoefRangeName && *addCoefRangeName) {
518std::unique_ptr<RooAbsReal> createNLLNew(
RooAbsPdf &pdf,
RooAbsData &
data, std::unique_ptr<RooAbsReal> &&constraints,
519 std::string
const &rangeName,
RooArgSet const &projDeps,
bool isExtended,
530 observables.
remove(projDeps,
true,
true);
533 <<
") fixing normalization set for coefficient determination to observables in data"
538 RooAbsPdf &finalPdf = applyIntegrateBinsWrapping(pdf,
data, integrateOverBinsPrecision, binSamplingPdfs);
547 nllTerms.
addOwned(createSimultaneousNLL(*simPdf, isExtended, rangeName,
offset));
549 RooNLLVarNew::Config cfg;
550 cfg.extended = isExtended;
552 nllTerms.
addOwned(std::make_unique<RooNLLVarNew>(
"RooNLLVarNew",
"RooNLLVarNew", finalPdf, observables, cfg));
555 nllTerms.
addOwned(std::move(constraints));
558 std::string nllName = std::string(
"nll_") + pdf.
GetName() +
"_" +
data.GetName();
559 auto nll = std::make_unique<RooAddition>(nllName.c_str(), nllName.c_str(), nllTerms);
560 nll->addOwnedComponents(std::move(binSamplingPdfs));
561 nll->addOwnedComponents(std::move(nllTerms));
568namespace RooFit::FitHelpers {
574 MinimizerConfig minimizerDefaults;
576 pc.
defineDouble(
"RecoverFromUndefinedRegions",
"RecoverFromUndefinedRegions", 0, minimizerDefaults.recoverFromNaN);
577 pc.
defineInt(
"verbose",
"Verbose", 0, minimizerDefaults.verbose);
578 pc.
defineInt(
"doSave",
"Save", 0, minimizerDefaults.doSave);
579 pc.
defineInt(
"doTimer",
"Timer", 0, minimizerDefaults.doTimer);
580 pc.
defineInt(
"printLevel",
"PrintLevel", 0, minimizerDefaults.printLevel);
581 pc.
defineInt(
"strategy",
"Strategy", 0, minimizerDefaults.strategy);
582 pc.
defineInt(
"initHesse",
"InitialHesse", 0, minimizerDefaults.initHesse);
583 pc.
defineInt(
"hesse",
"Hesse", 0, minimizerDefaults.hesse);
584 pc.
defineInt(
"minos",
"Minos", 0, minimizerDefaults.minos);
585 pc.
defineInt(
"numee",
"PrintEvalErrors", 0, minimizerDefaults.numee);
586 pc.
defineInt(
"doEEWall",
"EvalErrorWall", 0, minimizerDefaults.doEEWall);
587 pc.
defineInt(
"doWarn",
"Warnings", 0, minimizerDefaults.doWarn);
588 pc.
defineInt(
"doSumW2",
"SumW2Error", 0, minimizerDefaults.doSumW2);
589 pc.
defineInt(
"doAsymptoticError",
"AsymptoticError", 0, minimizerDefaults.doAsymptotic);
590 pc.
defineInt(
"maxCalls",
"MaxCalls", 0, minimizerDefaults.maxCalls);
591 pc.
defineInt(
"doOffset",
"OffsetLikelihood", 0, minimizerDefaults.doOffset);
592 pc.
defineInt(
"parallelize",
"Parallelize", 0, minimizerDefaults.parallelize);
593 pc.
defineInt(
"enableParallelGradient",
"ParallelGradientOptions", 0, minimizerDefaults.enableParallelGradient);
594 pc.
defineInt(
"enableParallelDescent",
"ParallelDescentOptions", 0, minimizerDefaults.enableParallelDescent);
595 pc.
defineInt(
"parallelDescentNumSplits",
"ParallelDescentOptions", 1, minimizerDefaults.parallelDescentNumSplits);
596 pc.
defineInt(
"parallelDescentSplitStrategy",
"ParallelDescentOptions", 2,
597 minimizerDefaults.parallelDescentSplitStrategy);
598 pc.
defineInt(
"timingAnalysis",
"TimingAnalysis", 0, minimizerDefaults.timingAnalysis);
599 pc.
defineString(
"mintype",
"Minimizer", 0, minimizerDefaults.minType.c_str());
600 pc.
defineString(
"minalg",
"Minimizer", 1, minimizerDefaults.minAlg.c_str());
601 pc.
defineSet(
"minosSet",
"Minos", 0, minimizerDefaults.minosSet);
618 cfg.recoverFromNaN = pc.
getDouble(
"RecoverFromUndefinedRegions");
619 cfg.verbose = pc.
getInt(
"verbose");
620 cfg.doSave = pc.
getInt(
"doSave");
621 cfg.doTimer = pc.
getInt(
"doTimer");
622 cfg.printLevel = pc.
getInt(
"printLevel");
623 cfg.strategy = pc.
getInt(
"strategy");
624 cfg.initHesse = pc.
getInt(
"initHesse");
625 cfg.hesse = pc.
getInt(
"hesse");
626 cfg.minos = pc.
getInt(
"minos");
627 cfg.numee = pc.
getInt(
"numee");
628 cfg.doEEWall = pc.
getInt(
"doEEWall");
629 cfg.doWarn = pc.
getInt(
"doWarn");
630 cfg.doSumW2 = pc.
getInt(
"doSumW2");
631 cfg.doAsymptotic = pc.
getInt(
"doAsymptoticError");
632 cfg.maxCalls = pc.
getInt(
"maxCalls");
633 cfg.minosSet = pc.
getSet(
"minosSet");
634 cfg.minType = pc.
getString(
"mintype",
"");
635 cfg.minAlg = pc.
getString(
"minalg",
"minuit");
636 cfg.doOffset = pc.
getInt(
"doOffset");
637 cfg.parallelize = pc.
getInt(
"parallelize");
638 cfg.enableParallelGradient = pc.
getInt(
"enableParallelGradient");
639 cfg.enableParallelDescent = pc.
getInt(
"enableParallelDescent");
640 cfg.parallelDescentNumSplits = pc.
getInt(
"parallelDescentNumSplits");
641 cfg.parallelDescentSplitStrategy = pc.
getInt(
"parallelDescentSplitStrategy");
642 cfg.timingAnalysis = pc.
getInt(
"timingAnalysis");
645 bool weightedData =
data.isNonPoissonWeighted();
649 const bool isChi2 =
nll.getAttribute(
"Chi2EvaluationActive");
651 std::string msgPrefix = std::string{
"RooAbsPdf::fitTo("} + pdf.
GetName() +
"): ";
654 if (!isChi2 && weightedData && cfg.doSumW2 == -1 && cfg.doAsymptotic == -1) {
655 oocoutW(&pdf, InputArguments) << msgPrefix <<
656 R
"(WARNING: a likelihood fit is requested of what appears to be weighted data.
657 While the estimated values of the parameters will always be calculated taking the weights into account,
658 there are multiple ways to estimate the errors of the parameters. You are advised to make an
659 explicit choice for the error calculation:
660 - Either provide SumW2Error(true), to calculate a sum-of-weights-corrected HESSE error matrix
661 (error will be proportional to the number of events in MC).
662 - Or provide SumW2Error(false), to return errors from original HESSE error matrix
663 (which will be proportional to the sum of the weights, i.e., a dataset with <sum of weights> events).
664 - Or provide AsymptoticError(true), to use the asymptotically correct expression
665 (for details see https://arxiv.org/abs/1911.01303)."
669 if (cfg.minos && (cfg.doSumW2 == 1 || cfg.doAsymptotic == 1)) {
672 <<
" sum-of-weights and asymptotic error correction do not work with MINOS errors. Not fitting.\n";
675 if (cfg.doAsymptotic == 1 && cfg.minos) {
676 oocoutW(&pdf, InputArguments) << msgPrefix <<
"WARNING: asymptotic correction does not apply to MINOS errors\n";
680 if (cfg.doSumW2 == 1 && cfg.doAsymptotic == 1) {
681 oocoutE(&pdf, InputArguments) << msgPrefix
682 <<
"ERROR: Cannot compute both asymptotically correct and SumW2 errors.\n";
689 if (cfg.parallelDescentNumSplits > 0) {
690#ifdef ROOFIT_MULTIPROCESS
691 if (cfg.parallelDescentSplitStrategy == 0) {
697 oocoutW(&pdf, InputArguments) <<
"Likelihood-splitting settings passed via ParallelDescentOptions() are "
698 "ignored, because ROOT was built without RooFit::MultiProcess support"
712 m.setMinimizerType(cfg.minType);
713 m.setEvalErrorWall(cfg.doEEWall);
714 m.setRecoverFromNaNStrength(cfg.recoverFromNaN);
715 m.setPrintEvalErrors(cfg.numee);
716 if (cfg.maxCalls > 0)
717 m.setMaxFunctionCalls(cfg.maxCalls);
718 if (cfg.printLevel != 1)
719 m.setPrintLevel(cfg.printLevel);
724 if (cfg.strategy != 1)
725 m.setStrategy(cfg.strategy);
728 m.minimize(cfg.minType.c_str(), cfg.minAlg.c_str());
732 int corrCovQual = -1;
734 if (!isChi2 &&
m.getNPar() > 0) {
735 if (cfg.doAsymptotic == 1)
736 corrCovQual = calcAsymptoticCorrectedCovariance(pdf,
m,
data);
737 if (cfg.doSumW2 == 1)
738 corrCovQual = calcSumW2CorrectedCovariance(pdf,
m, nll);
742 cfg.minosSet ?
m.minos(*cfg.minosSet) :
m.minos();
745 std::unique_ptr<RooFitResult> ret;
747 auto name = std::string(
"fitresult_") + pdf.
GetName() +
"_" +
data.GetName();
748 auto title = std::string(
"Result of fit of p.d.f. ") + pdf.
GetName() +
" to dataset " +
data.GetName();
749 ret = std::unique_ptr<RooFitResult>{
m.save(
name.c_str(), title.c_str())};
750 if ((cfg.doSumW2 == 1 || cfg.doAsymptotic == 1) &&
m.getNPar() > 0)
751 ret->setCovQual(corrCovQual);
759 auto timingScope = std::make_unique<ROOT::Math::Util::TimingScope>(
760 [&pdf](std::string
const &msg) {
oocoutI(&pdf, Fitting) << msg << std::endl; },
"Creation of NLL object took");
762 auto baseName = std::string(
"nll_") + pdf.
GetName() +
"_" +
data.GetName();
767 pc.
defineString(
"rangeName",
"RangeWithName", 0,
"",
true);
769 pc.
defineString(
"globstag",
"GlobalObservablesTag", 0,
"");
770 pc.
defineString(
"globssource",
"GlobalObservablesSource", 0,
"data");
773 pc.
defineInt(
"splitRange",
"SplitRange", 0, 0);
774 pc.
defineInt(
"ext",
"Extended", 0, extendedFitDefault);
776 pc.
defineInt(
"interleave",
"NumCPU", 1, 0);
777 pc.
defineInt(
"verbose",
"Verbose", 0, 0);
778 pc.
defineInt(
"cloneData",
"CloneData", 0, 0);
779 pc.
defineSet(
"projDepSet",
"ProjectedObservables", 0,
nullptr);
780 pc.
defineSet(
"cPars",
"Constrain", 0,
nullptr);
781 pc.
defineSet(
"glObs",
"GlobalObservables", 0,
nullptr);
782 pc.
defineInt(
"doOffset",
"OffsetLikelihood", 0, 0);
783 pc.
defineSet(
"extCons",
"ExternalConstraints", 0,
nullptr);
785 pc.
defineDouble(
"IntegrateBins",
"IntegrateBins", 0, -1.);
787 pc.
defineMutex(
"GlobalObservables",
"GlobalObservablesTag");
788 pc.
defineInt(
"ModularL",
"ModularL", 0, 0);
803 if (pc.
getInt(
"ModularL")) {
804 int lut[3] = {2, 1, 0};
812 if (
auto tmp = pc.
getSet(
"cPars"))
815 if (
auto tmp = pc.
getSet(
"extCons"))
816 extConsSet.
add(*tmp);
818 if (
auto tmp = pc.
getSet(
"glObs"))
821 const std::string rangeName = pc.
getString(
"globstag",
"",
false);
824 builder.Extended(ext)
825 .ConstrainedParameters(cParsSet)
826 .ExternalConstraints(extConsSet)
827 .GlobalObservables(glObsSet)
828 .GlobalObservablesTag(rangeName.c_str())
831 return std::make_unique<RooFit::TestStatistics::RooRealL>(
"likelihood",
"", builder.build());
835 const char *rangeName = pc.
getString(
"rangeName",
nullptr,
true);
836 const char *addCoefRangeName = pc.
getString(
"addCoefRange",
nullptr,
true);
837 const bool ext = interpretExtendedCmdArg(pdf, pc.
getInt(
"ext"));
839 int splitRange = pc.
getInt(
"splitRange");
840 int cloneData = pc.
getInt(
"cloneData");
844 double rangeLo = pc.
getDouble(
"rangeLo");
845 double rangeHi = pc.
getDouble(
"rangeHi");
852 rrv->setRange(
"fit", rangeLo, rangeHi);
860 resetFitrangeAttributes(pdf,
data, baseName, rangeName, splitRange);
863 auto tmp = pc.
getSet(
"projDepSet");
868 const std::string globalObservablesSource = pc.
getString(
"globssource",
"data",
false);
869 if (globalObservablesSource !=
"data" && globalObservablesSource !=
"model") {
870 std::string errMsg =
"RooAbsPdf::fitTo: GlobalObservablesSource can only be \"data\" or \"model\"!";
871 oocoutE(&pdf, InputArguments) << errMsg << std::endl;
872 throw std::invalid_argument(errMsg);
874 const bool takeGlobalObservablesFromData = globalObservablesSource ==
"data";
879 auto createConstr = [&]() -> std::unique_ptr<RooAbsReal> {
880 return createConstraintTerm(baseName +
"_constr",
887 takeGlobalObservablesFromData);
899 if (simPdfForProjDeps && simPdfForProjDeps->indexCatIsObservable(normSet)) {
900 for (
auto i : projDeps) {
901 auto res = normSet.
find(i->GetName());
902 if (res !=
nullptr) {
910 std::unique_ptr<RooAbsPdf> pdfClone =
911 compilePdfForFit(pdf, normSet, rangeName, splitRange, addCoefRangeName,
true);
913 if (addCoefRangeName) {
915 <<
") fixing interpretation of coefficients of any component to range "
916 << addCoefRangeName <<
"\n";
919 std::unique_ptr<RooAbsReal> compiledConstr;
920 if (std::unique_ptr<RooAbsReal> constr = createConstr()) {
922 compiledConstr->addOwnedComponents(std::move(constr));
925 auto nll = createNLLNew(*pdfClone,
data, std::move(compiledConstr), rangeName ? rangeName :
"", projDeps, ext,
926 pc.getDouble(
"IntegrateBins"),
offset);
928 const double correction = pdfClone->getCorrection();
930 if (correction > 0) {
931 oocoutI(&pdf, Fitting) <<
"[FitHelpers] Detected correction term from RooAbsPdf::getCorrection(). "
932 <<
"Adding penalty to NLL." << std::endl;
935 auto penaltyTerm = std::make_unique<RooConstVar>((baseName +
"_Penalty").c_str(),
936 "Penalty term from getCorrection()", correction);
939 auto correctedNLL = std::make_unique<RooAddition>((baseName +
"_corrected").c_str(),
"NLL + penalty",
943 correctedNLL->addOwnedComponents(std::move(nll), std::move(penaltyTerm));
944 nll = std::move(correctedNLL);
947 const int nWorkers = effectiveNumWorkers(pdf, evalBackend, pc.
getInt(
"numcpu"));
949 auto nllWrapper = std::make_unique<RooFit::Experimental::RooEvaluatorWrapper>(
951 takeGlobalObservablesFromData, nWorkers);
959 nllWrapper->generateGradient();
962 nllWrapper->setUseGeneratedFunctionCode(
true);
965 nllWrapper->addOwnedComponents(std::move(nll));
966 nllWrapper->addOwnedComponents(std::move(pdfClone));
971 std::unique_ptr<RooAbsReal>
nll;
973#ifdef ROOFIT_LEGACY_EVAL_BACKEND
974 printLegacyEvalBackendWarning(pdf);
978 int numcpu = pc.
getInt(
"numcpu");
979 int numcpu_strategy = pc.
getInt(
"interleave");
981 if (numcpu_strategy == 3 && !pdf.
InheritsFrom(
"RooSimultaneous")) {
982 oocoutW(&pdf, Minimization) <<
"Cannot use a NumCpu Strategy = 3 when the pdf is not a RooSimultaneous, "
983 "falling back to default strategy = 0"
990 RooAbsPdf &actualPdf = binnedLInfo.binnedPdf ? *binnedLInfo.binnedPdf : pdf;
994 RooAbsTestStatistic::Configuration cfg;
995 cfg.addCoefRangeName = addCoefRangeName ? addCoefRangeName :
"";
997 cfg.interleave = interl;
999 cfg.splitCutRange =
static_cast<bool>(splitRange);
1000 cfg.cloneInputData =
static_cast<bool>(cloneData);
1001 cfg.integrateOverBinsPrecision = pc.
getDouble(
"IntegrateBins");
1002 cfg.binnedL = binnedLInfo.isBinnedL;
1003 cfg.takeGlobalObservablesFromData = takeGlobalObservablesFromData;
1004 cfg.rangeName = rangeName ? rangeName :
"";
1005 auto nllVar = std::make_unique<RooNLLVar>(baseName.c_str(),
"-log(likelihood)", actualPdf,
data, projDeps, ext, cfg);
1007 nll = std::move(nllVar);
1011 if (std::unique_ptr<RooAbsReal> constraintTerm = createConstr()) {
1023 constraintTerm->setData(
data,
false);
1029 auto orignll = std::move(nll);
1030 nll = std::make_unique<RooAddition>((baseName +
"_with_constr").c_str(),
"nllWithCons",
1032 nll->addOwnedComponents(std::move(orignll), std::move(constraintTerm));
1036 nll->enableOffsetting(
true);
1039 if (
const double correction = pdf.
getCorrection(); correction > 0) {
1040 oocoutI(&pdf, Fitting) <<
"[FitHelpers] Detected correction term from RooAbsPdf::getCorrection(). "
1041 <<
"Adding penalty to NLL." << std::endl;
1044 auto penaltyTerm = std::make_unique<RooConstVar>((baseName +
"_Penalty").c_str(),
1045 "Penalty term from getCorrection()", correction);
1047 auto correctedNLL = std::make_unique<RooAddition>(
1049 (baseName +
"_corrected").c_str(),
"NLL + penalty",
RooArgSet(*nll, *penaltyTerm));
1052 correctedNLL->addOwnedComponents(std::move(nll), std::move(penaltyTerm));
1053 nll = std::move(correctedNLL);
1056 throw std::runtime_error(
"RooFit was not built with the legacy evaluation backend");
1068 pc.
defineInt(
"verbose",
"Verbose", 0, 0);
1069 pc.
defineString(
"rangeName",
"RangeWithName", 0,
"",
true);
1074 pc.
defineInt(
"extended",
"Extended", 0, extendedFitDefault);
1075 pc.
defineInt(
"splitRange",
"SplitRange", 0, 0);
1076 pc.
defineDouble(
"integrate_bins",
"IntegrateBins", 0, -1);
1077 pc.
defineString(
"addCoefRange",
"SumCoefRange", 0,
"");
1088 std::string baseName =
"chi2_" + std::string(real.
GetName()) +
"_" +
data.GetName();
1098 auto *pdf =
dynamic_cast<RooAbsPdf *
>(&real);
1099 const char *rangeName = pc.
getString(
"rangeName",
nullptr,
true);
1103 const double rangeLo = pc.
getDouble(
"rangeLo");
1104 const double rangeHi = pc.
getDouble(
"rangeHi");
1109 rrv->setRange(
"fit", rangeLo, rangeHi);
1118 const int splitRange = pc.
getInt(
"splitRange");
1119 resetFitrangeAttributes(real,
data, baseName, rangeName, splitRange);
1121 std::unique_ptr<RooFit::Experimental::RooEvaluatorWrapper> wrapper;
1123 const int nWorkers = effectiveNumWorkers(real, evalBackend, pc.
getInt(
"numcpu"));
1130 RooNLLVarNew::Config cfg;
1131 cfg.statistic = RooNLLVarNew::Statistic::Chi2;
1132 cfg.chi2ErrorType = etype;
1133 auto chi2 = std::make_unique<RooNLLVarNew>(baseName.c_str(), baseName.c_str(), real, observables, cfg);
1134 wrapper = std::make_unique<RooFit::Experimental::RooEvaluatorWrapper>(
1138 wrapper->addOwnedComponents(std::move(chi2));
1140 const bool extended = interpretExtendedCmdArg(*pdf, pc.
getInt(
"extended"));
1146 <<
") fixing normalization set for coefficient determination to observables in data\n";
1149 std::unique_ptr<RooAbsPdf> pdfClone =
1150 compilePdfForFit(*pdf, normSet, rangeName, splitRange, pc.
getString(
"addCoefRange",
nullptr,
true),
1155 applyIntegrateBinsWrapping(*pdfClone,
data, pc.
getDouble(
"integrate_bins"), binSamplingPdfs);
1157 std::unique_ptr<RooAbsReal> chi2;
1161 if (simPdfClone && simPdfClone->indexCatIsObservable(*
data.get())) {
1162 chi2 = std::unique_ptr<RooAbsReal>{
dynamic_cast<RooAbsReal *
>(
1163 createSimultaneousChi2(*simPdfClone, rangeName ? rangeName :
"", extended, etype).release())};
1167 RooNLLVarNew::Config cfg;
1168 cfg.statistic = RooNLLVarNew::Statistic::Chi2;
1169 cfg.extended = extended;
1170 cfg.chi2ErrorType = etype;
1171 chi2 = std::make_unique<RooNLLVarNew>(baseName.c_str(), baseName.c_str(), finalPdf, observables, cfg);
1174 wrapper = std::make_unique<RooFit::Experimental::RooEvaluatorWrapper>(
1177 wrapper->addOwnedComponents(std::move(binSamplingPdfs));
1178 wrapper->addOwnedComponents(std::move(chi2));
1179 wrapper->addOwnedComponents(std::move(pdfClone));
1183 wrapper->generateGradient();
1186 wrapper->setUseGeneratedFunctionCode(
true);
1193#ifdef ROOFIT_LEGACY_EVAL_BACKEND
1194 printLegacyEvalBackendWarning(real);
1196 RooAbsTestStatistic::Configuration cfg;
1200 bool extended =
false;
1202 extended = interpretExtendedCmdArg(*pdf, pc.
getInt(
"extended"));
1205 const char *addCoefRangeName = pc.
getString(
"addCoefRange",
nullptr,
true);
1206 int splitRange = pc.
getInt(
"splitRange");
1209 resetFitrangeAttributes(real,
data, baseName, rangeName, splitRange);
1211 cfg.rangeName = rangeName ? rangeName :
"";
1212 cfg.nCPU = pc.
getInt(
"numcpu");
1214 cfg.verbose =
static_cast<bool>(pc.
getInt(
"verbose"));
1215 cfg.cloneInputData =
false;
1216 cfg.integrateOverBinsPrecision = pc.
getDouble(
"integrate_bins");
1217 cfg.addCoefRangeName = addCoefRangeName ? addCoefRangeName :
"";
1218 cfg.splitCutRange =
static_cast<bool>(splitRange);
1219 auto chi2 = std::make_unique<RooChi2Var>(baseName.c_str(), baseName.c_str(), real,
static_cast<RooDataHist &
>(
data),
1220 extended, etype, cfg);
1226 throw std::runtime_error(
"createChi2() is not supported without the legacy evaluation backend");
1238 std::string nllCmdListString;
1246 auto cmdEnabled = [&cmdList](
const char *cmdName) {
1248 return arg && arg->getInt(0) != 0;
1250 const bool parallelRequested =
1251 cmdEnabled(
"Parallelize") || cmdEnabled(
"ParallelGradientOptions") || cmdEnabled(
"ParallelDescentOptions");
1254 nllCmdListString =
"ProjectedObservables,Extended,Range,"
1255 "RangeWithName,SumCoefRange,NumCPU,SplitRange,Constrained,Constrain,ExternalConstraints,"
1256 "CloneData,GlobalObservables,GlobalObservablesSource,GlobalObservablesTag,"
1257 "EvalBackend,IntegrateBins,ModularL";
1259 if (!parallelRequested && !cmdEnabled(
"ModularL")) {
1260 nllCmdListString +=
",OffsetLikelihood";
1263 auto createChi2DataHistCmdArgs =
"Range,RangeWithName,NumCPU,IntegrateBins,ProjectedObservables,"
1264 "AddCoefRange,SplitRange,DataError,Extended,EvalBackend";
1265 auto createChi2DataSetCmdArgs =
"YVar,Integrate,RangeWithName,NumCPU,Verbose";
1266 nllCmdListString += isDataHist ? createChi2DataHistCmdArgs : createChi2DataSetCmdArgs;
1272 defineMinimizationOptions(pc);
1282 oocoutW(&real, Minimization) <<
"The timingAnalysis feature was built for minimization with RooSimultaneous "
1283 "and is not implemented for other PDF's. Please create a RooSimultaneous to "
1284 "enable this feature."
1292 size_t nEvents =
static_cast<size_t>(prefit *
data.numEntries());
1293 if (prefit > 0.5 || nEvents < 100) {
1294 oocoutW(&real, InputArguments) <<
"PrefitDataFraction should be in suitable range."
1295 <<
"With the current PrefitDataFraction=" << prefit
1296 <<
", the number of events would be " << nEvents <<
" out of "
1297 <<
data.numEntries() <<
". Skipping prefit..." << std::endl;
1299 size_t step =
data.numEntries() / nEvents;
1303 for (
int i = 0; i <
data.numEntries(); i += step) {
1308 pc.
filterCmdList(tinyCmdList,
"Prefit,Hesse,Minos,Verbose,Save,Timer");
1312 tinyCmdList.Add(&hesse_option);
1313 tinyCmdList.Add(&print_option);
1315 fitTo(real, tiny, tinyCmdList, chi2);
1320 if (parallelRequested) {
1323 nllCmdList.
Add(&modularL_option);
1326 std::unique_ptr<RooAbsReal>
nll;
1332 nll = std::unique_ptr<RooAbsReal>{
dynamic_cast<RooAbsPdf &
>(real).createNLL(
data, nllCmdList)};
1336 oocoutE(&real, InputArguments) <<
"RooFit::FitHelpers::fitTo(" << real.
GetName()
1337 <<
") could not create the test statistic, no fit performed" << std::endl;
1341 return RooFit::FitHelpers::minimize(real, *nll,
data, pc);
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)
int Int_t
Signed integer 4 bytes (int)
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
class to compute the Cholesky decomposition of a matrix
Common abstract base class for objects that represent a value and a "shape" in RooFit.
virtual bool isCategory() const
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.
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.
Abstract interface for all probability density functions.
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.
const char * normRange() const
virtual ExtendMode extendMode() const
Returns ability of PDF to provide extended likelihood terms.
Abstract base class for objects that represent a real value and implements functionality common to al...
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
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.
RooArgList is a container object that can hold multiple RooAbsArg objects.
RooAbsArg * at(Int_t idx) const
Return object at given index, or nullptr if index is out of range.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
RooArgSet * selectByAttrib(const char *name, bool value) const
Use RooAbsCollection::selectByAttrib(), but return as RooArgSet.
static std::unique_ptr< RooAbsPdf > create(RooAbsPdf &pdf, RooAbsData const &data, double precision)
Creates a wrapping RooBinSamplingPdf if appropriate.
Object to represent discrete states.
Named container for two doubles, two integers two object points and three string pointers that can be...
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.
Container class to hold unbinned data.
static Value & defaultValue()
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.
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
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.
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
RooCmdArg WeightVar(const char *name="weight", bool reinterpretAsWeight=false)
RooCmdArg Hesse(bool flag=true)
RooCmdArg ModularL(bool flag=false)
RooCmdArg PrintLevel(Int_t code)
RooCmdArg Use EvalBackend() instead of BatchMode().")
RVec< PromoteType< T > > log(const RVec< T > &v)
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)
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)
static std::size_t defaultNComponentTasks
static std::size_t defaultNEventTasks
Config argument to RooMinimizer constructor.
bool enableParallelDescent
bool enableParallelGradient