48#ifdef ROOFIT_LEGACY_EVAL_BACKEND
53using RooFit::Detail::RooNLLVarNew;
57constexpr int extendedFitDefault = 2;
74 logpdf.getObservables(
data.get(), obs);
82 <<
"RooAbsPdf::fitTo(" << pdf.
GetName()
83 <<
") WARNING: Asymptotic error correction is requested for a binned data set. "
84 "This method is not designed to handle binned data. A standard chi2 fit will likely be more suitable.";
88 std::unique_ptr<RooFitResult> rw(minimizer.
save());
92 <<
"RooAbsPdf::fitTo(" << pdf.
GetName()
93 <<
") Calculating covariance matrix according to the asymptotically correct approach. If you find this "
94 "method useful please consider citing https://arxiv.org/abs/1911.01303.\n";
97 int nFloatPars = rw->floatParsFinal().size();
99 for (
int k = 0; k < nFloatPars; k++) {
100 for (
int l = 0;
l < nFloatPars;
l++) {
106 std::vector<std::unique_ptr<RooDerivative>> derivatives;
107 const RooArgList &floated = rw->floatParsFinal();
109 logpdf.getParameters(
data.get(), allparams);
110 std::unique_ptr<RooArgSet> floatingparams{allparams.
selectByAttrib(
"Constant",
false)};
112 const double eps = 1.0e-4;
115 for (
const auto paramresult : floated) {
116 auto paraminternal =
static_cast<RooRealVar *
>(floatingparams->find(*paramresult));
118 double error =
static_cast<RooRealVar *
>(paramresult)->getError();
119 derivatives.emplace_back(logpdf.derivative(*paraminternal, obs, 1, eps * error));
124 std::vector<double> diffs_expected(floated.size(), 0.0);
126 for (std::size_t k = 0; k < floated.size(); k++) {
127 const auto paramresult =
static_cast<RooRealVar *
>(floated.at(k));
128 auto paraminternal =
static_cast<RooRealVar *
>(floatingparams->find(*paramresult));
130 *paraminternal = paramresult->
getVal();
131 double error = paramresult->getError();
132 paraminternal->setVal(paramresult->getVal() + eps * error);
134 paraminternal->setVal(paramresult->getVal() - eps * error);
136 *paraminternal = paramresult->getVal();
137 double diff = (expected_plus - expected_minus) / (2.0 * eps * error);
138 diffs_expected[k] = diff;
143 for (
int j = 0; j <
data.numEntries(); j++) {
147 std::vector<double> diffs(floated.size(), 0.0);
148 for (std::size_t k = 0; k < floated.size(); k++) {
149 const auto paramresult =
static_cast<RooRealVar *
>(floated.at(k));
150 auto paraminternal =
static_cast<RooRealVar *
>(floatingparams->find(*paramresult));
152 double diff = derivatives[k]->getVal();
154 *paraminternal = paramresult->getVal();
159 for (std::size_t k = 0; k < floated.size(); k++) {
160 for (std::size_t
l = 0;
l < floated.size();
l++) {
161 num(k,
l) +=
data.weightSquared() * (diffs[k] + diffs_expected[k]) * (diffs[
l] + diffs_expected[
l]);
165 num.Similarity(matV);
173 return rw->covQual();
191 std::unique_ptr<RooFitResult> rw{minimizer.
save()};
192 nll.applyWeightSquared(
true);
194 <<
") Calculating sum-of-weights-squared correction matrix for covariance matrix\n";
196 std::unique_ptr<RooFitResult> rw2{minimizer.
save()};
197 nll.applyWeightSquared(
false);
205 <<
") ERROR: Cannot apply sum-of-weights correction to covariance matrix: correction "
206 "matrix calculated with weight-squared is singular\n";
214 for (
int i = 0; i < matC.
GetNrows(); ++i) {
215 for (
int j = 0; j < i; ++j) {
216 matC(j, i) = matC(i, j);
224 return std::min(rw->covQual(), rw2->covQual());
229struct MinimizerConfig {
230 double recoverFromNaN = 10.;
244 int doAsymptotic = -1;
248 bool enableParallelGradient =
false;
249 bool enableParallelDescent =
false;
250 bool timingAnalysis =
false;
251 const RooArgSet *minosSet =
nullptr;
253 std::string minAlg =
"minuit";
256bool interpretExtendedCmdArg(
RooAbsPdf const &pdf,
int extendedCmdArg)
259 if (extendedCmdArg == extendedFitDefault) {
263 <<
"p.d.f. provides expected number of events, including extended term in likelihood." << std::endl;
272 if (extendedCmdArg == 0) {
274 std::string errMsg =
"You used the Extended(false) option on a pdf where the fit MUST be extended! "
275 "The parameters are not well defined and you're getting nonsensical results.";
276 oocoutE(&pdf, InputArguments) << errMsg << std::endl;
279 return extendedCmdArg;
284void resetFitrangeAttributes(
RooAbsArg &pdf,
RooAbsData const &
data, std::string
const &baseName,
const char *rangeName,
293 if (!rangeName || splitRange)
299 std::string fitrangeValue;
301 for (
auto const &subrange : subranges) {
302 if (subrange.empty())
304 std::string fitrangeValueSubrange = std::string(
"fit_") + baseName;
305 if (subranges.size() > 1) {
306 fitrangeValueSubrange +=
"_" + subrange;
308 fitrangeValue += fitrangeValueSubrange +
",";
311 if (arg->isCategory())
313 auto &observable =
static_cast<RooRealVar &
>(*arg);
315 observable.
setRange(fitrangeValueSubrange.c_str(), observable.getMin(subrange.c_str()),
316 observable.getMax(subrange.c_str()));
319 pdf.
setStringAttribute(
"fitrange", fitrangeValue.substr(0, fitrangeValue.size() - 1).c_str());
327template <
typename TermFactory>
328std::unique_ptr<RooAddition> createSimultaneousStat(
RooSimultaneous const &simPdf, std::string
const &rangeName,
329 std::string
const &combinedName, TermFactory &&makeTerm)
334 for (
auto const &catState : simCat) {
335 std::string
const &catName = catState.first;
340 if (!rangeName.empty()) {
341 auto simCatAsRooCategory =
dynamic_cast<RooCategory const *
>(&simCat);
342 if (simCatAsRooCategory && !simCatAsRooCategory->isStateInRange(rangeName.c_str(), catIndex)) {
351 std::unique_ptr<RooArgSet> observables{
352 std::unique_ptr<RooArgSet>(channelPdf->
getVariables())->selectByAttrib(
"__obs__",
true)};
353 std::unique_ptr<RooNLLVarNew> term = makeTerm(*channelPdf, *observables);
354 term->setPrefix(std::string(
"_") + catName +
"_");
358 auto combined = std::make_unique<RooAddition>(combinedName.c_str(), combinedName.c_str(), terms);
359 combined->addOwnedComponents(std::move(terms));
363std::unique_ptr<RooAbsArg> createSimultaneousChi2(
RooSimultaneous const &simPdf, std::string
const &rangeName,
367 createSimultaneousStat(simPdf, rangeName,
"simChi2", [&](
RooAbsPdf &channelPdf,
RooArgSet const &observables) {
368 RooNLLVarNew::Config cfg;
369 cfg.statistic = RooNLLVarNew::Statistic::Chi2;
371 cfg.chi2ErrorType = etype;
372 auto name = std::string(
"chi2_") + channelPdf.
GetName();
373 return std::make_unique<RooNLLVarNew>(
name.c_str(),
name.c_str(), channelPdf, observables, cfg);
376 chi2->setAttribute(
"Chi2EvaluationActive");
380std::unique_ptr<RooAbsArg> createSimultaneousNLL(
RooSimultaneous const &simPdf,
bool isSimPdfExtended,
384 createSimultaneousStat(simPdf, rangeName,
"mynll", [&](
RooAbsPdf &channelPdf,
RooArgSet const &observables) {
385 RooNLLVarNew::Config cfg;
389 auto name = std::string(
"nll_") + channelPdf.
GetName();
390 return std::make_unique<RooNLLVarNew>(
name.c_str(),
name.c_str(), channelPdf, observables, cfg);
393 const int simCount =
nll->list().size();
395 child->setSimCount(simCount);
412 ownedOut.
addOwned(std::move(wrapped));
422class NormRangeScope {
424 NormRangeScope(RooAbsPdf &pdf,
const char *rangeName,
bool splitRange) : _pdf{&pdf}
433 NormRangeScope(NormRangeScope
const &) =
delete;
434 NormRangeScope &
operator=(NormRangeScope
const &) =
delete;
437 _pdf->setAttribute(
"SplitRange",
false);
438 _pdf->setStringAttribute(
"RangeName",
nullptr);
439 _pdf->setNormRange(_oldNormRange.empty() ?
nullptr : _oldNormRange.c_str());
444 std::string _oldNormRange;
453std::unique_ptr<RooAbsPdf> compilePdfForFit(
RooAbsPdf &pdf,
RooArgSet const &normSet,
const char *rangeName,
454 bool splitRange,
const char *addCoefRangeName,
bool likelihoodMode)
456 NormRangeScope scope{pdf, rangeName, splitRange};
461 std::unique_ptr<RooAbsPdf> pdfClone{&
dynamic_cast<RooAbsPdf &
>(*head.release())};
463 if (addCoefRangeName && *addCoefRangeName) {
464 pdfClone->fixAddCoefRange(addCoefRangeName,
false);
469std::unique_ptr<RooAbsReal> createNLLNew(
RooAbsPdf &pdf,
RooAbsData &
data, std::unique_ptr<RooAbsReal> &&constraints,
470 std::string
const &rangeName,
RooArgSet const &projDeps,
bool isExtended,
481 observables.
remove(projDeps,
true,
true);
484 <<
") fixing normalization set for coefficient determination to observables in data"
489 RooAbsPdf &finalPdf = applyIntegrateBinsWrapping(pdf,
data, integrateOverBinsPrecision, binSamplingPdfs);
493 nllTerms.
addOwned(createSimultaneousNLL(*simPdf, isExtended, rangeName,
offset));
495 RooNLLVarNew::Config cfg;
496 cfg.extended = isExtended;
498 nllTerms.
addOwned(std::make_unique<RooNLLVarNew>(
"RooNLLVarNew",
"RooNLLVarNew", finalPdf, observables, cfg));
501 nllTerms.
addOwned(std::move(constraints));
504 std::string nllName = std::string(
"nll_") + pdf.
GetName() +
"_" +
data.GetName();
505 auto nll = std::make_unique<RooAddition>(nllName.c_str(), nllName.c_str(), nllTerms);
506 nll->addOwnedComponents(std::move(binSamplingPdfs));
507 nll->addOwnedComponents(std::move(nllTerms));
514namespace RooFit::FitHelpers {
516void defineMinimizationOptions(RooCmdConfig &pc)
520 MinimizerConfig minimizerDefaults;
522 pc.
defineDouble(
"RecoverFromUndefinedRegions",
"RecoverFromUndefinedRegions", 0, minimizerDefaults.recoverFromNaN);
523 pc.
defineInt(
"optConst",
"Optimize", 0, minimizerDefaults.optConst);
524 pc.
defineInt(
"verbose",
"Verbose", 0, minimizerDefaults.verbose);
525 pc.
defineInt(
"doSave",
"Save", 0, minimizerDefaults.doSave);
526 pc.
defineInt(
"doTimer",
"Timer", 0, minimizerDefaults.doTimer);
527 pc.
defineInt(
"printLevel",
"PrintLevel", 0, minimizerDefaults.printLevel);
528 pc.
defineInt(
"strategy",
"Strategy", 0, minimizerDefaults.strategy);
529 pc.
defineInt(
"initHesse",
"InitialHesse", 0, minimizerDefaults.initHesse);
530 pc.
defineInt(
"hesse",
"Hesse", 0, minimizerDefaults.hesse);
531 pc.
defineInt(
"minos",
"Minos", 0, minimizerDefaults.minos);
532 pc.
defineInt(
"numee",
"PrintEvalErrors", 0, minimizerDefaults.numee);
533 pc.
defineInt(
"doEEWall",
"EvalErrorWall", 0, minimizerDefaults.doEEWall);
534 pc.
defineInt(
"doWarn",
"Warnings", 0, minimizerDefaults.doWarn);
535 pc.
defineInt(
"doSumW2",
"SumW2Error", 0, minimizerDefaults.doSumW2);
536 pc.
defineInt(
"doAsymptoticError",
"AsymptoticError", 0, minimizerDefaults.doAsymptotic);
537 pc.
defineInt(
"maxCalls",
"MaxCalls", 0, minimizerDefaults.maxCalls);
538 pc.
defineInt(
"doOffset",
"OffsetLikelihood", 0, minimizerDefaults.doOffset);
539 pc.
defineInt(
"parallelize",
"Parallelize", 0, minimizerDefaults.parallelize);
540 pc.
defineInt(
"enableParallelGradient",
"ParallelGradientOptions", 0, minimizerDefaults.enableParallelGradient);
541 pc.
defineInt(
"enableParallelDescent",
"ParallelDescentOptions", 0, minimizerDefaults.enableParallelDescent);
542 pc.
defineInt(
"timingAnalysis",
"TimingAnalysis", 0, minimizerDefaults.timingAnalysis);
543 pc.
defineString(
"mintype",
"Minimizer", 0, minimizerDefaults.minType.c_str());
544 pc.
defineString(
"minalg",
"Minimizer", 1, minimizerDefaults.minAlg.c_str());
545 pc.
defineSet(
"minosSet",
"Minos", 0, minimizerDefaults.minosSet);
559std::unique_ptr<RooFitResult> minimize(RooAbsReal &pdf, RooAbsReal &nll, RooAbsData
const &
data, RooCmdConfig
const &pc)
562 cfg.recoverFromNaN = pc.
getDouble(
"RecoverFromUndefinedRegions");
563 cfg.optConst = pc.
getInt(
"optConst");
564 cfg.verbose = pc.
getInt(
"verbose");
565 cfg.doSave = pc.
getInt(
"doSave");
566 cfg.doTimer = pc.
getInt(
"doTimer");
567 cfg.printLevel = pc.
getInt(
"printLevel");
568 cfg.strategy = pc.
getInt(
"strategy");
569 cfg.initHesse = pc.
getInt(
"initHesse");
570 cfg.hesse = pc.
getInt(
"hesse");
571 cfg.minos = pc.
getInt(
"minos");
572 cfg.numee = pc.
getInt(
"numee");
573 cfg.doEEWall = pc.
getInt(
"doEEWall");
574 cfg.doWarn = pc.
getInt(
"doWarn");
575 cfg.doSumW2 = pc.
getInt(
"doSumW2");
576 cfg.doAsymptotic = pc.
getInt(
"doAsymptoticError");
577 cfg.maxCalls = pc.
getInt(
"maxCalls");
578 cfg.minosSet = pc.
getSet(
"minosSet");
579 cfg.minType = pc.
getString(
"mintype",
"");
580 cfg.minAlg = pc.
getString(
"minalg",
"minuit");
581 cfg.doOffset = pc.
getInt(
"doOffset");
582 cfg.parallelize = pc.
getInt(
"parallelize");
583 cfg.enableParallelGradient = pc.
getInt(
"enableParallelGradient");
584 cfg.enableParallelDescent = pc.
getInt(
"enableParallelDescent");
585 cfg.timingAnalysis = pc.
getInt(
"timingAnalysis");
588 bool weightedData =
data.isNonPoissonWeighted();
592 const bool isChi2 =
nll.getAttribute(
"Chi2EvaluationActive");
594 std::string msgPrefix = std::string{
"RooAbsPdf::fitTo("} + pdf.
GetName() +
"): ";
597 if (!isChi2 && weightedData && cfg.doSumW2 == -1 && cfg.doAsymptotic == -1) {
598 oocoutW(&pdf, InputArguments) << msgPrefix <<
599 R
"(WARNING: a likelihood fit is requested of what appears to be weighted data.
600 While the estimated values of the parameters will always be calculated taking the weights into account,
601 there are multiple ways to estimate the errors of the parameters. You are advised to make an
602 explicit choice for the error calculation:
603 - Either provide SumW2Error(true), to calculate a sum-of-weights-corrected HESSE error matrix
604 (error will be proportional to the number of events in MC).
605 - Or provide SumW2Error(false), to return errors from original HESSE error matrix
606 (which will be proportional to the sum of the weights, i.e., a dataset with <sum of weights> events).
607 - Or provide AsymptoticError(true), to use the asymptotically correct expression
608 (for details see https://arxiv.org/abs/1911.01303)."
612 if (cfg.minos && (cfg.doSumW2 == 1 || cfg.doAsymptotic == 1)) {
615 <<
" sum-of-weights and asymptotic error correction do not work with MINOS errors. Not fitting.\n";
618 if (cfg.doAsymptotic == 1 && cfg.minos) {
619 oocoutW(&pdf, InputArguments) << msgPrefix <<
"WARNING: asymptotic correction does not apply to MINOS errors\n";
623 if (cfg.doSumW2 == 1 && cfg.doAsymptotic == 1) {
624 oocoutE(&pdf, InputArguments) << msgPrefix
625 <<
"ERROR: Cannot compute both asymptotically correct and SumW2 errors.\n";
630 RooMinimizer::Config minimizerConfig;
636 RooMinimizer
m(nll, minimizerConfig);
638 m.setMinimizerType(cfg.minType);
639 m.setEvalErrorWall(cfg.doEEWall);
640 m.setRecoverFromNaNStrength(cfg.recoverFromNaN);
641 m.setPrintEvalErrors(cfg.numee);
642 if (cfg.maxCalls > 0)
643 m.setMaxFunctionCalls(cfg.maxCalls);
644 if (cfg.printLevel != 1)
645 m.setPrintLevel(cfg.printLevel);
647 m.optimizeConst(cfg.optConst);
652 if (cfg.strategy != 1)
653 m.setStrategy(cfg.strategy);
656 m.minimize(cfg.minType.c_str(), cfg.minAlg.c_str());
660 int corrCovQual = -1;
662 if (!isChi2 &&
m.getNPar() > 0) {
663 if (cfg.doAsymptotic == 1)
664 corrCovQual = calcAsymptoticCorrectedCovariance(pdf,
m,
data);
665 if (cfg.doSumW2 == 1)
666 corrCovQual = calcSumW2CorrectedCovariance(pdf,
m, nll);
670 cfg.minosSet ?
m.minos(*cfg.minosSet) :
m.minos();
673 std::unique_ptr<RooFitResult> ret;
675 auto name = std::string(
"fitresult_") + pdf.
GetName() +
"_" +
data.GetName();
676 auto title = std::string(
"Result of fit of p.d.f. ") + pdf.
GetName() +
" to dataset " +
data.GetName();
677 ret = std::unique_ptr<RooFitResult>{
m.save(
name.c_str(), title.c_str())};
678 if ((cfg.doSumW2 == 1 || cfg.doAsymptotic == 1) &&
m.getNPar() > 0)
679 ret->setCovQual(corrCovQual);
687std::unique_ptr<RooAbsReal> createNLL(RooAbsPdf &pdf, RooAbsData &
data,
const RooLinkedList &cmdList)
689 auto timingScope = std::make_unique<ROOT::Math::Util::TimingScope>(
690 [&pdf](std::string
const &msg) {
oocoutI(&pdf, Fitting) << msg << std::endl; },
"Creation of NLL object took");
692 auto baseName = std::string(
"nll_") + pdf.
GetName() +
"_" +
data.GetName();
695 RooCmdConfig pc(
"RooAbsPdf::createNLL(" + std::string(pdf.
GetName()) +
")");
697 pc.
defineString(
"rangeName",
"RangeWithName", 0,
"",
true);
699 pc.
defineString(
"globstag",
"GlobalObservablesTag", 0,
"");
700 pc.
defineString(
"globssource",
"GlobalObservablesSource", 0,
"data");
703 pc.
defineInt(
"splitRange",
"SplitRange", 0, 0);
704 pc.
defineInt(
"ext",
"Extended", 0, extendedFitDefault);
706 pc.
defineInt(
"interleave",
"NumCPU", 1, 0);
707 pc.
defineInt(
"verbose",
"Verbose", 0, 0);
708 pc.
defineInt(
"optConst",
"Optimize", 0, 0);
709 pc.
defineInt(
"cloneData",
"CloneData", 0, 2);
710 pc.
defineSet(
"projDepSet",
"ProjectedObservables", 0,
nullptr);
711 pc.
defineSet(
"cPars",
"Constrain", 0,
nullptr);
712 pc.
defineSet(
"glObs",
"GlobalObservables", 0,
nullptr);
713 pc.
defineInt(
"doOffset",
"OffsetLikelihood", 0, 0);
714 pc.
defineSet(
"extCons",
"ExternalConstraints", 0,
nullptr);
716 pc.
defineDouble(
"IntegrateBins",
"IntegrateBins", 0, -1.);
718 pc.
defineMutex(
"GlobalObservables",
"GlobalObservablesTag");
719 pc.
defineInt(
"ModularL",
"ModularL", 0, 0);
734 if (pc.
getInt(
"ModularL")) {
735 int lut[3] = {2, 1, 0};
740 RooArgSet extConsSet;
743 if (
auto tmp = pc.
getSet(
"cPars"))
746 if (
auto tmp = pc.
getSet(
"extCons"))
747 extConsSet.
add(*tmp);
749 if (
auto tmp = pc.
getSet(
"glObs"))
752 const std::string rangeName = pc.
getString(
"globstag",
"",
false);
754 RooFit::TestStatistics::NLLFactory builder{pdf,
data};
755 builder.Extended(ext)
756 .ConstrainedParameters(cParsSet)
757 .ExternalConstraints(extConsSet)
758 .GlobalObservables(glObsSet)
759 .GlobalObservablesTag(rangeName.c_str());
761 return std::make_unique<RooFit::TestStatistics::RooRealL>(
"likelihood",
"", builder.build());
765 const char *rangeName = pc.
getString(
"rangeName",
nullptr,
true);
766 const char *addCoefRangeName = pc.
getString(
"addCoefRange",
nullptr,
true);
767 const bool ext = interpretExtendedCmdArg(pdf, pc.
getInt(
"ext"));
769 int splitRange = pc.
getInt(
"splitRange");
770 int optConst = pc.
getInt(
"optConst");
771 int cloneData = pc.
getInt(
"cloneData");
775 if (cloneData == 2) {
776 cloneData = optConst;
780 double rangeLo = pc.
getDouble(
"rangeLo");
781 double rangeHi = pc.
getDouble(
"rangeHi");
788 rrv->setRange(
"fit", rangeLo, rangeHi);
796 resetFitrangeAttributes(pdf,
data, baseName, rangeName, splitRange);
799 auto tmp = pc.
getSet(
"projDepSet");
804 const std::string globalObservablesSource = pc.
getString(
"globssource",
"data",
false);
805 if (globalObservablesSource !=
"data" && globalObservablesSource !=
"model") {
806 std::string errMsg =
"RooAbsPdf::fitTo: GlobalObservablesSource can only be \"data\" or \"model\"!";
807 oocoutE(&pdf, InputArguments) << errMsg << std::endl;
808 throw std::invalid_argument(errMsg);
810 const bool takeGlobalObservablesFromData = globalObservablesSource ==
"data";
815 auto createConstr = [&]() -> std::unique_ptr<RooAbsReal> {
816 return createConstraintTerm(baseName +
"_constr",
823 takeGlobalObservablesFromData);
834 if (
dynamic_cast<RooSimultaneous
const *
>(&pdf)) {
835 for (
auto i : projDeps) {
836 auto res = normSet.
find(i->GetName());
837 if (res !=
nullptr) {
838 res->setAttribute(
"__conditional__");
845 std::unique_ptr<RooAbsPdf> pdfClone =
846 compilePdfForFit(pdf, normSet, rangeName, splitRange, addCoefRangeName,
true);
848 if (addCoefRangeName) {
850 <<
") fixing interpretation of coefficients of any component to range "
851 << addCoefRangeName <<
"\n";
854 std::unique_ptr<RooAbsReal> compiledConstr;
855 if (std::unique_ptr<RooAbsReal> constr = createConstr()) {
857 compiledConstr->addOwnedComponents(std::move(constr));
860 auto nll = createNLLNew(*pdfClone,
data, std::move(compiledConstr), rangeName ? rangeName :
"", projDeps, ext,
863 const double correction = pdfClone->getCorrection();
865 if (correction > 0) {
866 oocoutI(&pdf, Fitting) <<
"[FitHelpers] Detected correction term from RooAbsPdf::getCorrection(). "
867 <<
"Adding penalty to NLL." << std::endl;
870 auto penaltyTerm = std::make_unique<RooConstVar>((baseName +
"_Penalty").c_str(),
871 "Penalty term from getCorrection()", correction);
874 auto correctedNLL = std::make_unique<RooAddition>((baseName +
"_corrected").c_str(),
"NLL + penalty",
875 RooArgSet{*
nll, *penaltyTerm});
878 correctedNLL->addOwnedComponents(std::move(nll), std::move(penaltyTerm));
879 nll = std::move(correctedNLL);
882 auto nllWrapper = std::make_unique<RooFit::Experimental::RooEvaluatorWrapper>(
884 takeGlobalObservablesFromData);
892 nllWrapper->generateGradient();
895 nllWrapper->setUseGeneratedFunctionCode(
true);
898 nllWrapper->addOwnedComponents(std::move(nll));
899 nllWrapper->addOwnedComponents(std::move(pdfClone));
904 std::unique_ptr<RooAbsReal>
nll;
906#ifdef ROOFIT_LEGACY_EVAL_BACKEND
909 int numcpu = pc.
getInt(
"numcpu");
910 int numcpu_strategy = pc.
getInt(
"interleave");
912 if (numcpu_strategy == 3 && !pdf.
InheritsFrom(
"RooSimultaneous")) {
913 oocoutW(&pdf, Minimization) <<
"Cannot use a NumCpu Strategy = 3 when the pdf is not a RooSimultaneous, "
914 "falling back to default strategy = 0"
921 RooAbsPdf &actualPdf = binnedLInfo.binnedPdf ? *binnedLInfo.binnedPdf : pdf;
925 RooAbsTestStatistic::Configuration cfg;
926 cfg.addCoefRangeName = addCoefRangeName ? addCoefRangeName :
"";
928 cfg.interleave = interl;
930 cfg.splitCutRange =
static_cast<bool>(splitRange);
931 cfg.cloneInputData =
static_cast<bool>(cloneData);
932 cfg.integrateOverBinsPrecision = pc.
getDouble(
"IntegrateBins");
933 cfg.binnedL = binnedLInfo.isBinnedL;
934 cfg.takeGlobalObservablesFromData = takeGlobalObservablesFromData;
935 cfg.rangeName = rangeName ? rangeName :
"";
936 auto nllVar = std::make_unique<RooNLLVar>(baseName.c_str(),
"-log(likelihood)", actualPdf,
data, projDeps, ext, cfg);
938 nll = std::move(nllVar);
942 if (std::unique_ptr<RooAbsReal> constraintTerm = createConstr()) {
954 constraintTerm->setData(
data,
false);
960 auto orignll = std::move(nll);
961 nll = std::make_unique<RooAddition>((baseName +
"_with_constr").c_str(),
"nllWithCons",
962 RooArgSet(*orignll, *constraintTerm));
963 nll->addOwnedComponents(std::move(orignll), std::move(constraintTerm));
971 nll->enableOffsetting(
true);
974 if (
const double correction = pdf.
getCorrection(); correction > 0) {
975 oocoutI(&pdf, Fitting) <<
"[FitHelpers] Detected correction term from RooAbsPdf::getCorrection(). "
976 <<
"Adding penalty to NLL." << std::endl;
979 auto penaltyTerm = std::make_unique<RooConstVar>((baseName +
"_Penalty").c_str(),
980 "Penalty term from getCorrection()", correction);
982 auto correctedNLL = std::make_unique<RooAddition>(
984 (baseName +
"_corrected").c_str(),
"NLL + penalty", RooArgSet(*nll, *penaltyTerm));
987 correctedNLL->addOwnedComponents(std::move(nll), std::move(penaltyTerm));
988 nll = std::move(correctedNLL);
991 throw std::runtime_error(
"RooFit was not built with the legacy evaluation backend");
997std::unique_ptr<RooAbsReal> createChi2(RooAbsReal &real, RooDataHist &
data,
const RooLinkedList &cmdList)
999 RooCmdConfig pc(
"createChi2(" + std::string(real.
GetName()) +
")");
1003 pc.
defineInt(
"verbose",
"Verbose", 0, 0);
1004 pc.
defineString(
"rangeName",
"RangeWithName", 0,
"",
true);
1009 pc.
defineInt(
"extended",
"Extended", 0, extendedFitDefault);
1010 pc.
defineInt(
"splitRange",
"SplitRange", 0, 0);
1011 pc.
defineDouble(
"integrate_bins",
"IntegrateBins", 0, -1);
1012 pc.
defineString(
"addCoefRange",
"SumCoefRange", 0,
"");
1023 std::string baseName =
"chi2_" + std::string(real.
GetName()) +
"_" +
data.GetName();
1033 auto *pdf =
dynamic_cast<RooAbsPdf *
>(&real);
1034 const char *rangeName = pc.
getString(
"rangeName",
nullptr,
true);
1038 const double rangeLo = pc.
getDouble(
"rangeLo");
1039 const double rangeHi = pc.
getDouble(
"rangeHi");
1044 rrv->setRange(
"fit", rangeLo, rangeHi);
1053 const int splitRange = pc.
getInt(
"splitRange");
1054 resetFitrangeAttributes(real,
data, baseName, rangeName, splitRange);
1056 std::unique_ptr<RooFit::Experimental::RooEvaluatorWrapper> wrapper;
1061 RooArgSet observables;
1063 RooNLLVarNew::Config cfg;
1064 cfg.statistic = RooNLLVarNew::Statistic::Chi2;
1065 cfg.chi2ErrorType = etype;
1066 auto chi2 = std::make_unique<RooNLLVarNew>(baseName.c_str(), baseName.c_str(), real, observables, cfg);
1067 wrapper = std::make_unique<RooFit::Experimental::RooEvaluatorWrapper>(
1071 wrapper->addOwnedComponents(std::move(chi2));
1073 const bool extended = interpretExtendedCmdArg(*pdf, pc.
getInt(
"extended"));
1079 <<
") fixing normalization set for coefficient determination to observables in data\n";
1082 std::unique_ptr<RooAbsPdf> pdfClone =
1083 compilePdfForFit(*pdf, normSet, rangeName, splitRange, pc.
getString(
"addCoefRange",
nullptr,
true),
1086 RooArgList binSamplingPdfs;
1087 RooAbsPdf &finalPdf =
1088 applyIntegrateBinsWrapping(*pdfClone,
data, pc.
getDouble(
"integrate_bins"), binSamplingPdfs);
1090 std::unique_ptr<RooAbsReal> chi2;
1091 if (
auto *simPdfClone =
dynamic_cast<RooSimultaneous *
>(&finalPdf)) {
1092 chi2 = std::unique_ptr<RooAbsReal>{
dynamic_cast<RooAbsReal *
>(
1093 createSimultaneousChi2(*simPdfClone, rangeName ? rangeName :
"", extended, etype).release())};
1095 RooArgSet observables;
1097 RooNLLVarNew::Config cfg;
1098 cfg.statistic = RooNLLVarNew::Statistic::Chi2;
1099 cfg.extended = extended;
1100 cfg.chi2ErrorType = etype;
1101 chi2 = std::make_unique<RooNLLVarNew>(baseName.c_str(), baseName.c_str(), finalPdf, observables, cfg);
1104 wrapper = std::make_unique<RooFit::Experimental::RooEvaluatorWrapper>(
1107 wrapper->addOwnedComponents(std::move(binSamplingPdfs));
1108 wrapper->addOwnedComponents(std::move(chi2));
1109 wrapper->addOwnedComponents(std::move(pdfClone));
1113 wrapper->generateGradient();
1116 wrapper->setUseGeneratedFunctionCode(
true);
1123#ifdef ROOFIT_LEGACY_EVAL_BACKEND
1124 RooAbsTestStatistic::Configuration cfg;
1128 bool extended =
false;
1130 extended = interpretExtendedCmdArg(*pdf, pc.
getInt(
"extended"));
1133 const char *addCoefRangeName = pc.
getString(
"addCoefRange",
nullptr,
true);
1134 int splitRange = pc.
getInt(
"splitRange");
1137 resetFitrangeAttributes(real,
data, baseName, rangeName, splitRange);
1139 cfg.rangeName = rangeName ? rangeName :
"";
1140 cfg.nCPU = pc.
getInt(
"numcpu");
1142 cfg.verbose =
static_cast<bool>(pc.
getInt(
"verbose"));
1143 cfg.cloneInputData =
false;
1144 cfg.integrateOverBinsPrecision = pc.
getDouble(
"integrate_bins");
1145 cfg.addCoefRangeName = addCoefRangeName ? addCoefRangeName :
"";
1146 cfg.splitCutRange =
static_cast<bool>(splitRange);
1147 auto chi2 = std::make_unique<RooChi2Var>(baseName.c_str(), baseName.c_str(), real,
static_cast<RooDataHist &
>(
data),
1148 extended, etype, cfg);
1154 throw std::runtime_error(
"createChi2() is not supported without the legacy evaluation backend");
1159std::unique_ptr<RooFitResult> fitTo(RooAbsReal &real, RooAbsData &
data,
const RooLinkedList &cmdList,
bool chi2)
1161 const bool isDataHist =
dynamic_cast<RooDataHist
const *
>(&
data);
1163 RooCmdConfig pc(
"fitTo(" + std::string(real.
GetName()) +
")");
1165 RooLinkedList fitCmdList(cmdList);
1166 std::string nllCmdListString;
1168 nllCmdListString =
"ProjectedObservables,Extended,Range,"
1169 "RangeWithName,SumCoefRange,NumCPU,SplitRange,Constrained,Constrain,ExternalConstraints,"
1170 "CloneData,GlobalObservables,GlobalObservablesSource,GlobalObservablesTag,"
1171 "EvalBackend,IntegrateBins,ModularL";
1173 if (!cmdList.
FindObject(
"ModularL") ||
static_cast<RooCmdArg *
>(cmdList.
FindObject(
"ModularL"))->getInt(0) == 0) {
1174 nllCmdListString +=
",OffsetLikelihood";
1177 auto createChi2DataHistCmdArgs =
"Range,RangeWithName,NumCPU,Optimize,IntegrateBins,ProjectedObservables,"
1178 "AddCoefRange,SplitRange,DataError,Extended,EvalBackend";
1179 auto createChi2DataSetCmdArgs =
"YVar,Integrate,RangeWithName,NumCPU,Verbose";
1180 nllCmdListString += isDataHist ? createChi2DataHistCmdArgs : createChi2DataSetCmdArgs;
1183 RooLinkedList nllCmdList = pc.
filterCmdList(fitCmdList, nllCmdListString.c_str());
1186 defineMinimizationOptions(pc);
1196 oocoutW(&real, Minimization) <<
"The timingAnalysis feature was built for minimization with RooSimultaneous "
1197 "and is not implemented for other PDF's. Please create a RooSimultaneous to "
1198 "enable this feature."
1206 size_t nEvents =
static_cast<size_t>(prefit *
data.numEntries());
1207 if (prefit > 0.5 || nEvents < 100) {
1208 oocoutW(&real, InputArguments) <<
"PrefitDataFraction should be in suitable range."
1209 <<
"With the current PrefitDataFraction=" << prefit
1210 <<
", the number of events would be " << nEvents <<
" out of "
1211 <<
data.numEntries() <<
". Skipping prefit..." << std::endl;
1213 size_t step =
data.numEntries() / nEvents;
1217 for (
int i = 0; i <
data.numEntries(); i += step) {
1218 const RooArgSet *
event =
data.get(i);
1219 tiny.add(*event,
data.weight());
1221 RooLinkedList tinyCmdList(cmdList);
1222 pc.
filterCmdList(tinyCmdList,
"Prefit,Hesse,Minos,Verbose,Save,Timer");
1226 tinyCmdList.Add(&hesse_option);
1227 tinyCmdList.Add(&print_option);
1229 fitTo(real, tiny, tinyCmdList, chi2);
1233 RooCmdArg modularL_option;
1234 if (pc.
getInt(
"parallelize") != 0 || pc.
getInt(
"enableParallelGradient") || pc.
getInt(
"enableParallelDescent")) {
1237 nllCmdList.
Add(&modularL_option);
1240 std::unique_ptr<RooAbsReal>
nll;
1243 nll = std::unique_ptr<RooAbsReal>{real.
createChi2(
static_cast<RooDataHist &
>(
data), nllCmdList)};
1246 nll = std::unique_ptr<RooAbsReal>{
dynamic_cast<RooAbsPdf &
>(real).createNLL(
data, nllCmdList)};
1249 return RooFit::FitHelpers::minimize(real, *nll,
data, pc);
header file containing the templated implementation of matrix inversion routines for use with ROOT's ...
RInterface & operator=(const RInterface &)=default
Copy-assignment operator for RInterface.
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
TMatrixTSym< Double_t > TMatrixDSym
class to compute the Cholesky decomposition of a matrix
Common abstract base class for objects that represent a value and a "shape" in RooFit.
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,...
int value_type
The type used to denote a specific category state.
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...
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...
RooFit::OwningPtr< RooAbsReal > createChi2(RooDataHist &data, CmdArgs_t const &... cmdArgs)
Create a variable from a histogram and this function.
static void setEvalErrorLoggingMode(ErrorLoggingMode m)
Set evaluation error logging mode.
RooArgList is a container object that can hold multiple RooAbsArg objects.
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.
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.
void setLikelihoodMode(bool flag)
static Value & defaultValue()
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.
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)
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)
bool enableParallelDescent
bool enableParallelGradient