48#ifdef ROOFIT_LEGACY_EVAL_BACKEND
52#ifdef ROOFIT_MULTIPROCESS
59using RooFit::Detail::RooNLLVarNew;
63constexpr int extendedFitDefault = 2;
76 outer->branchNodeServerList(&outerBranches);
79 if (arg == outer || !nested || !nested->indexCatIsObservable(observables)) {
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 "
88 oocoutE(&top, InputArguments) << errMsg.str() << std::endl;
89 throw std::runtime_error(errMsg.str());
94#ifdef ROOFIT_LEGACY_EVAL_BACKEND
96void printLegacyEvalBackendWarning(
RooAbsReal const &topLevelArg)
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."
122 logpdf.getObservables(
data.get(), obs);
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.";
136 std::unique_ptr<RooFitResult> rw(minimizer.
save());
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";
145 int nFloatPars = rw->floatParsFinal().size();
147 for (
int k = 0; k < nFloatPars; k++) {
148 for (
int l = 0;
l < nFloatPars;
l++) {
154 std::vector<std::unique_ptr<RooDerivative>> derivatives;
155 const RooArgList &floated = rw->floatParsFinal();
157 logpdf.getParameters(
data.get(), allparams);
158 std::unique_ptr<RooArgSet> floatingparams{allparams.
selectByAttrib(
"Constant",
false)};
160 const double eps = 1.0e-4;
163 for (
const auto paramresult : floated) {
164 auto paraminternal =
static_cast<RooRealVar *
>(floatingparams->find(*paramresult));
166 double error =
static_cast<RooRealVar *
>(paramresult)->getError();
167 derivatives.emplace_back(logpdf.derivative(*paraminternal, obs, 1, eps * error));
172 std::vector<double> diffs_expected(floated.
size(), 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));
178 *paraminternal = paramresult->
getVal();
179 double error = paramresult->getError();
180 paraminternal->setVal(paramresult->getVal() + eps * error);
182 paraminternal->setVal(paramresult->getVal() - eps * error);
184 *paraminternal = paramresult->getVal();
185 double diff = (expected_plus - expected_minus) / (2.0 * eps * error);
186 diffs_expected[k] = diff;
191 for (
int j = 0; j <
data.numEntries(); j++) {
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));
200 double diff = derivatives[k]->getVal();
202 *paraminternal = paramresult->getVal();
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]);
213 num.Similarity(matV);
221 return rw->covQual();
239 std::unique_ptr<RooFitResult> rw{minimizer.
save()};
240 nll.applyWeightSquared(
true);
242 <<
") Calculating sum-of-weights-squared correction matrix for covariance matrix\n";
244 std::unique_ptr<RooFitResult> rw2{minimizer.
save()};
245 nll.applyWeightSquared(
false);
253 <<
") ERROR: Cannot apply sum-of-weights correction to covariance matrix: correction "
254 "matrix calculated with weight-squared is singular\n";
262 for (
int i = 0; i < matC.
GetNrows(); ++i) {
263 for (
int j = 0; j < i; ++j) {
264 matC(j, i) = matC(i, j);
272 return std::min(rw->covQual(), rw2->covQual());
277struct MinimizerConfig {
278 double recoverFromNaN = 10.;
291 int doAsymptotic = -1;
295 bool enableParallelGradient =
false;
296 bool enableParallelDescent =
false;
297 int parallelDescentNumSplits = 0;
298 int parallelDescentSplitStrategy = 0;
299 bool timingAnalysis =
false;
302 std::string minAlg =
"minuit";
314 if (evalBackend == Value::Cuda) {
315 oocoutW(&arg, Fitting) <<
"The NumCPU() option is ignored by the CUDA evaluation backend." << std::endl;
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."
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."
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;
336bool interpretExtendedCmdArg(
RooAbsPdf const &pdf,
int extendedCmdArg)
339 if (extendedCmdArg == extendedFitDefault) {
343 <<
"p.d.f. provides expected number of events, including extended term in likelihood." << std::endl;
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;
359 return extendedCmdArg;
364void resetFitrangeAttributes(
RooAbsArg &pdf,
RooAbsData const &
data, std::string
const &baseName,
const char *rangeName,
373 if (!rangeName || splitRange)
379 std::string fitrangeValue;
381 for (
auto const &subrange : subranges) {
382 if (subrange.empty())
384 std::string fitrangeValueSubrange = std::string(
"fit_") + baseName;
385 if (subranges.size() > 1) {
386 fitrangeValueSubrange +=
"_" + subrange;
388 fitrangeValue += fitrangeValueSubrange +
",";
393 auto &observable =
static_cast<RooRealVar &
>(*arg);
395 observable.
setRange(fitrangeValueSubrange.c_str(), observable.getMin(subrange.c_str()),
396 observable.getMax(subrange.c_str()));
399 pdf.
setStringAttribute(
"fitrange", fitrangeValue.substr(0, fitrangeValue.size() - 1).c_str());
407template <
typename TermFactory>
408std::unique_ptr<RooAddition> createSimultaneousStat(
RooSimultaneous const &simPdf, std::string
const &rangeName,
409 std::string
const &combinedName, TermFactory &&makeTerm)
414 for (
auto const &catState : simCat) {
415 std::string
const &catName = catState.
first;
420 if (!rangeName.empty()) {
421 auto simCatAsRooCategory =
dynamic_cast<RooCategory const *
>(&simCat);
422 if (simCatAsRooCategory && !simCatAsRooCategory->isStateInRange(rangeName.c_str(), catIndex)) {
431 std::unique_ptr<RooArgSet> observables{
433 std::unique_ptr<RooNLLVarNew> term = makeTerm(*channelPdf, *observables);
434 term->setPrefix(std::string(
"_") + catName +
"_");
438 auto combined = std::make_unique<RooAddition>(combinedName.c_str(), combinedName.c_str(), terms);
439 combined->addOwnedComponents(std::move(terms));
443std::unique_ptr<RooAbsArg> createSimultaneousChi2(
RooSimultaneous const &simPdf, std::string
const &rangeName,
447 createSimultaneousStat(simPdf, rangeName,
"simChi2", [&](
RooAbsPdf &channelPdf,
RooArgSet const &observables) {
448 RooNLLVarNew::Config cfg;
449 cfg.statistic = RooNLLVarNew::Statistic::Chi2;
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);
456 chi2->setAttribute(
"Chi2EvaluationActive");
460std::unique_ptr<RooAbsArg> createSimultaneousNLL(
RooSimultaneous const &simPdf,
bool isSimPdfExtended,
464 createSimultaneousStat(simPdf, rangeName,
"mynll", [&](
RooAbsPdf &channelPdf,
RooArgSet const &observables) {
465 RooNLLVarNew::Config cfg;
469 auto name = std::string(
"nll_") + channelPdf.
GetName();
470 return std::make_unique<RooNLLVarNew>(
name.c_str(),
name.c_str(), channelPdf, observables, cfg);
473 const int simCount =
nll->list().size();
475 child->setSimCount(simCount);
492 ownedOut.
addOwned(std::move(wrapped));
502class NormRangeScope {
504 NormRangeScope(
RooAbsPdf &pdf,
const char *rangeName,
bool splitRange) : _pdf{&pdf}
513 NormRangeScope(NormRangeScope
const &) =
delete;
514 NormRangeScope &operator=(NormRangeScope
const &) =
delete;
517 _pdf->setAttribute(
"SplitRange",
false);
518 _pdf->setStringAttribute(
"RangeName",
nullptr);
519 _pdf->setNormRange(_oldNormRange.empty() ?
nullptr : _oldNormRange.c_str());
524 std::string _oldNormRange;
533std::unique_ptr<RooAbsPdf> compilePdfForFit(
RooAbsPdf &pdf,
RooArgSet const &normSet,
const char *rangeName,
534 bool splitRange,
const char *addCoefRangeName,
bool likelihoodMode)
536 NormRangeScope scope{pdf, rangeName, splitRange};
539 ctx.setLikelihoodMode(likelihoodMode);
541 std::unique_ptr<RooAbsPdf> pdfClone{&
dynamic_cast<RooAbsPdf &
>(*head.release())};
543 if (addCoefRangeName && *addCoefRangeName) {
549std::unique_ptr<RooAbsReal> createNLLNew(
RooAbsPdf &pdf,
RooAbsData &
data, std::unique_ptr<RooAbsReal> &&constraints,
550 std::string
const &rangeName,
RooArgSet const &projDeps,
bool isExtended,
561 observables.
remove(projDeps,
true,
true);
564 <<
") fixing normalization set for coefficient determination to observables in data"
569 RooAbsPdf &finalPdf = applyIntegrateBinsWrapping(pdf,
data, integrateOverBinsPrecision, binSamplingPdfs);
578 nllTerms.
addOwned(createSimultaneousNLL(*simPdf, isExtended, rangeName,
offset));
580 RooNLLVarNew::Config cfg;
581 cfg.extended = isExtended;
583 nllTerms.
addOwned(std::make_unique<RooNLLVarNew>(
"RooNLLVarNew",
"RooNLLVarNew", finalPdf, observables, cfg));
586 nllTerms.
addOwned(std::move(constraints));
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));
599namespace RooFit::FitHelpers {
605 MinimizerConfig minimizerDefaults;
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);
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);
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");
676 bool weightedData =
data.isNonPoissonWeighted();
680 const bool isChi2 =
nll.getAttribute(
"Chi2EvaluationActive");
682 std::string msgPrefix = std::string{
"RooAbsPdf::fitTo("} + pdf.
GetName() +
"): ";
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)."
700 if (cfg.minos && (cfg.doSumW2 == 1 || cfg.doAsymptotic == 1)) {
703 <<
" sum-of-weights and asymptotic error correction do not work with MINOS errors. Not fitting.\n";
706 if (cfg.doAsymptotic == 1 && cfg.minos) {
707 oocoutW(&pdf, InputArguments) << msgPrefix <<
"WARNING: asymptotic correction does not apply to MINOS errors\n";
711 if (cfg.doSumW2 == 1 && cfg.doAsymptotic == 1) {
712 oocoutE(&pdf, InputArguments) << msgPrefix
713 <<
"ERROR: Cannot compute both asymptotically correct and SumW2 errors.\n";
720 if (cfg.parallelDescentNumSplits > 0) {
721#ifdef ROOFIT_MULTIPROCESS
722 if (cfg.parallelDescentSplitStrategy == 0) {
728 oocoutW(&pdf, InputArguments) <<
"Likelihood-splitting settings passed via ParallelDescentOptions() are "
729 "ignored, because ROOT was built without RooFit::MultiProcess support"
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);
755 if (cfg.strategy != 1)
756 m.setStrategy(cfg.strategy);
759 m.minimize(cfg.minType.c_str(), cfg.minAlg.c_str());
763 int corrCovQual = -1;
765 if (!isChi2 &&
m.getNPar() > 0) {
766 if (cfg.doAsymptotic == 1)
767 corrCovQual = calcAsymptoticCorrectedCovariance(pdf,
m,
data);
768 if (cfg.doSumW2 == 1)
769 corrCovQual = calcSumW2CorrectedCovariance(pdf,
m, nll);
773 cfg.minosSet ?
m.minos(*cfg.minosSet) :
m.minos();
776 std::unique_ptr<RooFitResult> ret;
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);
790 checkNestedSimultaneous(pdf, *
data.get());
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");
795 auto baseName = std::string(
"nll_") + pdf.
GetName() +
"_" +
data.GetName();
800 pc.
defineString(
"rangeName",
"RangeWithName", 0,
"",
true);
802 pc.
defineString(
"globstag",
"GlobalObservablesTag", 0,
"");
803 pc.
defineString(
"globssource",
"GlobalObservablesSource", 0,
"data");
806 pc.
defineInt(
"splitRange",
"SplitRange", 0, 0);
807 pc.
defineInt(
"ext",
"Extended", 0, extendedFitDefault);
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);
818 pc.
defineDouble(
"IntegrateBins",
"IntegrateBins", 0, -1.);
820 pc.
defineMutex(
"GlobalObservables",
"GlobalObservablesTag");
821 pc.
defineInt(
"ModularL",
"ModularL", 0, 0);
836 if (pc.
getInt(
"ModularL")) {
837 int lut[3] = {2, 1, 0};
845 if (
auto tmp = pc.
getSet(
"cPars"))
848 if (
auto tmp = pc.
getSet(
"extCons"))
849 extConsSet.
add(*tmp);
851 if (
auto tmp = pc.
getSet(
"glObs"))
854 const std::string rangeName = pc.
getString(
"globstag",
"",
false);
857 builder.Extended(ext)
858 .ConstrainedParameters(cParsSet)
859 .ExternalConstraints(extConsSet)
860 .GlobalObservables(glObsSet)
861 .GlobalObservablesTag(rangeName.c_str())
864 return std::make_unique<RooFit::TestStatistics::RooRealL>(
"likelihood",
"", builder.build());
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"));
872 int splitRange = pc.
getInt(
"splitRange");
873 int cloneData = pc.
getInt(
"cloneData");
877 double rangeLo = pc.
getDouble(
"rangeLo");
878 double rangeHi = pc.
getDouble(
"rangeHi");
885 rrv->setRange(
"fit", rangeLo, rangeHi);
893 resetFitrangeAttributes(pdf,
data, baseName, rangeName, splitRange);
896 auto tmp = pc.
getSet(
"projDepSet");
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);
907 const bool takeGlobalObservablesFromData = globalObservablesSource ==
"data";
912 auto createConstr = [&]() -> std::unique_ptr<RooAbsReal> {
913 return createConstraintTerm(baseName +
"_constr",
920 takeGlobalObservablesFromData);
932 if (simPdfForProjDeps && simPdfForProjDeps->indexCatIsObservable(normSet)) {
933 for (
auto i : projDeps) {
934 auto res = normSet.
find(i->GetName());
935 if (res !=
nullptr) {
943 std::unique_ptr<RooAbsPdf> pdfClone =
944 compilePdfForFit(pdf, normSet, rangeName, splitRange, addCoefRangeName,
true);
946 if (addCoefRangeName) {
948 <<
") fixing interpretation of coefficients of any component to range "
949 << addCoefRangeName <<
"\n";
952 std::unique_ptr<RooAbsReal> compiledConstr;
953 if (std::unique_ptr<RooAbsReal> constr = createConstr()) {
955 compiledConstr->addOwnedComponents(std::move(constr));
958 auto nll = createNLLNew(*pdfClone,
data, std::move(compiledConstr), rangeName ? rangeName :
"", projDeps, ext,
959 pc.getDouble(
"IntegrateBins"),
offset);
961 const double correction = pdfClone->getCorrection();
963 if (correction > 0) {
964 oocoutI(&pdf, Fitting) <<
"[FitHelpers] Detected correction term from RooAbsPdf::getCorrection(). "
965 <<
"Adding penalty to NLL." << std::endl;
968 auto penaltyTerm = std::make_unique<RooConstVar>((baseName +
"_Penalty").c_str(),
969 "Penalty term from getCorrection()", correction);
972 auto correctedNLL = std::make_unique<RooAddition>((baseName +
"_corrected").c_str(),
"NLL + penalty",
976 correctedNLL->addOwnedComponents(std::move(nll), std::move(penaltyTerm));
977 nll = std::move(correctedNLL);
980 const int nWorkers = effectiveNumWorkers(pdf, evalBackend, pc.
getInt(
"numcpu"));
982 auto nllWrapper = std::make_unique<RooFit::Experimental::RooEvaluatorWrapper>(
984 takeGlobalObservablesFromData, nWorkers);
992 nllWrapper->generateGradient();
995 nllWrapper->setUseGeneratedFunctionCode(
true);
998 nllWrapper->addOwnedComponents(std::move(nll));
999 nllWrapper->addOwnedComponents(std::move(pdfClone));
1004 std::unique_ptr<RooAbsReal>
nll;
1006#ifdef ROOFIT_LEGACY_EVAL_BACKEND
1007 printLegacyEvalBackendWarning(pdf);
1011 int numcpu = pc.
getInt(
"numcpu");
1012 int numcpu_strategy = pc.
getInt(
"interleave");
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"
1018 numcpu_strategy = 0;
1023 RooAbsPdf &actualPdf = binnedLInfo.binnedPdf ? *binnedLInfo.binnedPdf : pdf;
1027 RooAbsTestStatistic::Configuration cfg;
1028 cfg.addCoefRangeName = addCoefRangeName ? addCoefRangeName :
"";
1030 cfg.interleave = interl;
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);
1040 nll = std::move(nllVar);
1044 if (std::unique_ptr<RooAbsReal> constraintTerm = createConstr()) {
1056 constraintTerm->setData(
data,
false);
1062 auto orignll = std::move(nll);
1063 nll = std::make_unique<RooAddition>((baseName +
"_with_constr").c_str(),
"nllWithCons",
1065 nll->addOwnedComponents(std::move(orignll), std::move(constraintTerm));
1069 nll->enableOffsetting(
true);
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;
1077 auto penaltyTerm = std::make_unique<RooConstVar>((baseName +
"_Penalty").c_str(),
1078 "Penalty term from getCorrection()", correction);
1080 auto correctedNLL = std::make_unique<RooAddition>(
1082 (baseName +
"_corrected").c_str(),
"NLL + penalty",
RooArgSet(*nll, *penaltyTerm));
1085 correctedNLL->addOwnedComponents(std::move(nll), std::move(penaltyTerm));
1086 nll = std::move(correctedNLL);
1089 throw std::runtime_error(
"RooFit was not built with the legacy evaluation backend");
1097 checkNestedSimultaneous(real, *
data.get());
1103 pc.
defineInt(
"verbose",
"Verbose", 0, 0);
1104 pc.
defineString(
"rangeName",
"RangeWithName", 0,
"",
true);
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,
"");
1123 std::string baseName =
"chi2_" + std::string(real.
GetName()) +
"_" +
data.GetName();
1133 auto *pdf =
dynamic_cast<RooAbsPdf *
>(&real);
1134 const char *rangeName = pc.
getString(
"rangeName",
nullptr,
true);
1138 const double rangeLo = pc.
getDouble(
"rangeLo");
1139 const double rangeHi = pc.
getDouble(
"rangeHi");
1144 rrv->setRange(
"fit", rangeLo, rangeHi);
1153 const int splitRange = pc.
getInt(
"splitRange");
1154 resetFitrangeAttributes(real,
data, baseName, rangeName, splitRange);
1156 std::unique_ptr<RooFit::Experimental::RooEvaluatorWrapper> wrapper;
1158 const int nWorkers = effectiveNumWorkers(real, evalBackend, pc.
getInt(
"numcpu"));
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>(
1173 wrapper->addOwnedComponents(std::move(chi2));
1175 const bool extended = interpretExtendedCmdArg(*pdf, pc.
getInt(
"extended"));
1181 <<
") fixing normalization set for coefficient determination to observables in data\n";
1184 std::unique_ptr<RooAbsPdf> pdfClone =
1185 compilePdfForFit(*pdf, normSet, rangeName, splitRange, pc.
getString(
"addCoefRange",
nullptr,
true),
1190 applyIntegrateBinsWrapping(*pdfClone,
data, pc.
getDouble(
"integrate_bins"), binSamplingPdfs);
1192 std::unique_ptr<RooAbsReal> chi2;
1196 if (simPdfClone && simPdfClone->indexCatIsObservable(*
data.get())) {
1197 chi2 = std::unique_ptr<RooAbsReal>{
dynamic_cast<RooAbsReal *
>(
1198 createSimultaneousChi2(*simPdfClone, rangeName ? rangeName :
"", extended, etype).release())};
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);
1209 wrapper = std::make_unique<RooFit::Experimental::RooEvaluatorWrapper>(
1212 wrapper->addOwnedComponents(std::move(binSamplingPdfs));
1213 wrapper->addOwnedComponents(std::move(chi2));
1214 wrapper->addOwnedComponents(std::move(pdfClone));
1218 wrapper->generateGradient();
1221 wrapper->setUseGeneratedFunctionCode(
true);
1228#ifdef ROOFIT_LEGACY_EVAL_BACKEND
1229 printLegacyEvalBackendWarning(real);
1231 RooAbsTestStatistic::Configuration cfg;
1235 bool extended =
false;
1237 extended = interpretExtendedCmdArg(*pdf, pc.
getInt(
"extended"));
1240 const char *addCoefRangeName = pc.
getString(
"addCoefRange",
nullptr,
true);
1241 int splitRange = pc.
getInt(
"splitRange");
1244 resetFitrangeAttributes(real,
data, baseName, rangeName, splitRange);
1246 cfg.rangeName = rangeName ? rangeName :
"";
1247 cfg.nCPU = pc.
getInt(
"numcpu");
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);
1261 throw std::runtime_error(
"createChi2() is not supported without the legacy evaluation backend");
1273 std::string nllCmdListString;
1281 auto cmdEnabled = [&cmdList](
const char *cmdName) {
1283 return arg && arg->getInt(0) != 0;
1285 const bool parallelRequested =
1286 cmdEnabled(
"Parallelize") || cmdEnabled(
"ParallelGradientOptions") || cmdEnabled(
"ParallelDescentOptions");
1289 nllCmdListString =
"ProjectedObservables,Extended,Range,"
1290 "RangeWithName,SumCoefRange,NumCPU,SplitRange,Constrained,Constrain,ExternalConstraints,"
1291 "CloneData,GlobalObservables,GlobalObservablesSource,GlobalObservablesTag,"
1292 "EvalBackend,IntegrateBins,ModularL";
1294 if (!parallelRequested && !cmdEnabled(
"ModularL")) {
1295 nllCmdListString +=
",OffsetLikelihood";
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;
1307 defineMinimizationOptions(pc);
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."
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;
1334 size_t step =
data.numEntries() / nEvents;
1338 for (
int i = 0; i <
data.numEntries(); i += step) {
1343 pc.
filterCmdList(tinyCmdList,
"Prefit,Hesse,Minos,Verbose,Save,Timer");
1347 tinyCmdList.Add(&hesse_option);
1348 tinyCmdList.Add(&print_option);
1350 fitTo(real, tiny, tinyCmdList, chi2);
1355 if (parallelRequested) {
1358 nllCmdList.
Add(&modularL_option);
1361 std::unique_ptr<RooAbsReal>
nll;
1367 nll = std::unique_ptr<RooAbsReal>{
dynamic_cast<RooAbsPdf &
>(real).createNLL(
data, nllCmdList)};
1371 oocoutE(&real, InputArguments) <<
"RooFit::FitHelpers::fitTo(" << real.
GetName()
1372 <<
") could not create the test statistic, no fit performed" << std::endl;
1376 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.
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.
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)
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