diff --git a/roofit/xroofit/inc/RooFit/xRooFit/xRooHypoSpace.h b/roofit/xroofit/inc/RooFit/xRooFit/xRooHypoSpace.h index 69242f195780e..e82b2b7286e8e 100644 --- a/roofit/xroofit/inc/RooFit/xRooFit/xRooHypoSpace.h +++ b/roofit/xroofit/inc/RooFit/xRooFit/xRooHypoSpace.h @@ -24,11 +24,8 @@ BEGIN_XROOFIT_NAMESPACE -class xRooHypoSpace : public xRooNLLVar::xRooHypoSpace { -public: - using xRooNLLVar::xRooHypoSpace::xRooHypoSpace; - ClassDefOverride(xRooHypoSpace, 0) -}; +// xRooHypoSpace class is now defined in xRooNLLVar.h, +// to avoid incomplete type errors in an #include "xRooNLLVar.h" call END_XROOFIT_NAMESPACE diff --git a/roofit/xroofit/inc/RooFit/xRooFit/xRooNLLVar.h b/roofit/xroofit/inc/RooFit/xRooFit/xRooNLLVar.h index c83b180097f2a..9a84ab5e093d0 100644 --- a/roofit/xroofit/inc/RooFit/xRooFit/xRooNLLVar.h +++ b/roofit/xroofit/inc/RooFit/xRooFit/xRooNLLVar.h @@ -287,7 +287,7 @@ class xRooNLLVar : public std::shared_ptr { xValueWithError pX_toys(bool alt, double nSigma = std::numeric_limits::quiet_NaN()); size_t addToys(bool alt, int nToys, int initialSeed = 0, double target = std::numeric_limits::quiet_NaN(), double target_nSigma = std::numeric_limits::quiet_NaN(), bool targetCLs = false, - double relErrThreshold = 2., size_t maxToys = 10000); + double relErrThreshold = 2., size_t maxToys = -1); }; // use alt_value = nan to skip the asimov calculations @@ -512,6 +512,13 @@ class xRooNLLVar : public std::shared_ptr { bool kReuseNLL = true; }; +// define xRooHypoSpace class here, since inherits from above so need declaration +class xRooHypoSpace : public xRooNLLVar::xRooHypoSpace { +public: + using xRooNLLVar::xRooHypoSpace::xRooHypoSpace; + ClassDefOverride(xRooHypoSpace, 0) +}; + END_XROOFIT_NAMESPACE diff --git a/roofit/xroofit/src/xRooFit.cxx b/roofit/xroofit/src/xRooFit.cxx index 6a526d549b289..0821b1ecee5c9 100644 --- a/roofit/xroofit/src/xRooFit.cxx +++ b/roofit/xroofit/src/xRooFit.cxx @@ -362,7 +362,12 @@ xRooFit::generateFrom(RooAbsPdf &pdf, const RooFitResult &_fr, bool expected, in std::abs(boundaries.back() - rr) > 1e-5 * boundaries.back()) boundaries.push_back(rr); } // sometimes get virtual duplicates of boundaries - r->setBinning(RooBinning(boundaries.size() - 1, &boundaries[0])); + + // only replace the binning if necessary, i.e. if binning changed ... + // this ensures we don't replace a RooUniformBinning with a RooBinning, even if should be compatible + if(boundaries.size() < res->size()) { + r->setBinning(RooBinning(boundaries.size() - 1, &boundaries[0])); + } delete res; } else if (r->numBins(r->getBinning().GetName()) == 0 && expected) { // no bins ... in order to generate expected we need to have some bins @@ -482,6 +487,10 @@ std::shared_ptr xRooFit::defaultNLLOptions() delete l; }); sDefaultNLLOptions->Add(RooFit::Offset().Clone()); +#if ROOT_VERSION_CODE < ROOT_VERSION(6, 41, 00) + // disable const-optimization at the construction step ... can happen in the minimization though + sDefaultNLLOptions->Add(RooFit::Optimize(0).Clone()); +#endif return sDefaultNLLOptions; } @@ -512,6 +521,10 @@ std::shared_ptr xRooFit::defaultFitConfig() fitConfig.MinimizerOptions().SetExtraOptions(ROOT::Math::GenAlgoOptions()); // have to const cast to set extra options auto extraOpts = const_cast(fitConfig.MinimizerOptions().ExtraOptions()); +#if ROOT_VERSION_CODE < ROOT_VERSION(6, 41, 00) + extraOpts->SetValue("OptimizeConst", 2); // if 0 will disable constant term optimization and cache-and-track of the + // NLL. 1 = just caching, 2 = cache and track +#endif #if ROOT_VERSION_CODE >= ROOT_VERSION(6, 29, 00) extraOpts->SetValue( "StrategySequence", @@ -619,7 +632,12 @@ class ProgressMonitor : public RooAbsReal { { fFunc->printMultiline(os, contents, verbose, indent); } - +#if ROOT_VERSION_CODE < ROOT_VERSION(6, 41, 00) + void constOptimizeTestStatistic(ConstOpCode opcode, bool doAlsoTrackingOpt) override + { + fFunc->constOptimizeTestStatistic(opcode, doAlsoTrackingOpt); + } +#endif double evaluate() const override { if (fInterrupt) { @@ -1012,7 +1030,27 @@ std::shared_ptr xRooFit::minimize(RooAbsReal &nll, TString actualFirstMinimizer = _minimizer->fitter()->Config().MinimizerType(); int status = 0; - +#if ROOT_VERSION_CODE < ROOT_VERSION(6, 41, 00) + int constOptimize = 2; + _minimizer->fitter()->Config().MinimizerOptions().ExtraOptions()->GetValue("OptimizeConst", constOptimize); + if (constOptimize) { + _minimizer->optimizeConst(constOptimize); + // for safety force a refresh of the cache (and tracking) in the nll + // DO NOT do a ConfigChange ... this is just a deactivate-reactivate of caching + // but it seems like doing this breaks the const optimization and function is badly behaved + // so once its turned on never turn it off. + // nll.constOptimizeTestStatistic(RooAbsArg::ConfigChange, constOptimize>1 /* do tracking too if >1 */); // + // trigger a re-evaluate of which nodes to cache-and-track + // the next line seems safe to do but wont bother doing it because not bothering with above + // need to understand why turning the cache off and on again breaks it?? + // nll.constOptimizeTestStatistic(RooAbsArg::ValueChange, constOptimize>1); // update the cache values -- is + // this needed?? + } else { + // disable const optimization + // warning - if the nll was previously activated then it seems like deactivating may break it. + nll.constOptimizeTestStatistic(RooAbsArg::DeActivate); + } +#endif int sIdx = -1; TString minim = _minimizer->fitter()->Config().MinimizerType(); TString algo = _minimizer->fitter()->Config().MinimizerAlgoType(); @@ -1303,6 +1341,7 @@ std::shared_ptr xRooFit::minimize(RooAbsReal &nll, } } + // signal(SIGINT,gOldHandlerr); out = std::unique_ptr{_minimizer->save(fitName, resultTitle)}; diff --git a/roofit/xroofit/src/xRooFitVersion.h b/roofit/xroofit/src/xRooFitVersion.h index 27854f6e95f07..55ad182cc14e2 100644 --- a/roofit/xroofit/src/xRooFitVersion.h +++ b/roofit/xroofit/src/xRooFitVersion.h @@ -12,5 +12,5 @@ #pragma once -#define GIT_COMMIT_HASH "v0.0.4" -#define GIT_COMMIT_DATE "2026-06-19 16:32:00 +0100" +#define GIT_COMMIT_HASH "v0.0.4-29-g67d433e" +#define GIT_COMMIT_DATE "2026-10-23 11:19:53 +0100" diff --git a/roofit/xroofit/src/xRooHypoSpace.cxx b/roofit/xroofit/src/xRooHypoSpace.cxx index aae34bbd95f73..6aabc40cb21f3 100644 --- a/roofit/xroofit/src/xRooHypoSpace.cxx +++ b/roofit/xroofit/src/xRooHypoSpace.cxx @@ -424,16 +424,18 @@ int xRooNLLVar::xRooHypoSpace::scan(const char *type, size_t nPoints, double low } } } else if (sType.Contains("ts")) { - // add a point at the current poi value - // use that to determine ufit value and use uncertainty to set an approx range - AddPoint(TString::Format("%s=%g", poi().first()->GetName(), poi().getRealValue(poi().first()->GetName()))); - graphs(sType); // triggers computation + if(size()==0) { + // add a point at the current poi value + // use that to determine ufit value and use uncertainty to set an approx range + AddPoint(TString::Format("%s=%g", poi().first()->GetName(), poi().getRealValue(poi().first()->GetName()))); + graphs(sType); // triggers computation + } if (back().status() != 0) { out += 1; } else { // fit was ok, so use the values to determine an appropriate range - low = std::max(low, back().mu_hat().getVal() - back().mu_hat().getError() * 3); - high = std::min(high, back().mu_hat().getVal() + back().mu_hat().getError() * 3); + low = std::max(std::isnan(low) ? p->getMin() : low, back().mu_hat().getVal() - back().mu_hat().getError() * 3); + high = std::min(std::isnan(high) ? p->getMax() : high, back().mu_hat().getVal() + back().mu_hat().getError() * 3); nPoints = 20; double step = (high - low) / (nPoints - 1); for (size_t i = 0; i < nPoints; i++) { @@ -938,6 +940,27 @@ std::shared_ptr xRooNLLVar::xRooHypoSpace::graph( TStopwatch s; s.Start(); size_t nDone = 0; + + size_t nToys = 0; + size_t nToysAlt = 0; + if(sOpt.Contains("toys")) { + if (sOpt.Contains("toys=")) { + // extract number of toys required ... format is "nullToys.altToysFraction" if altToysFraction=0 then use + // same for both, unless explicitly set (i.e. N.0) then means we want no alt toys + // e.g. if doing just pnull significance + TString toyNum = sOpt(sOpt.Index("toys=") + 5, sOpt.Length()); + nToys = toyNum.Atoi(); + nToysAlt = (toyNum.Atof() - nToys) * nToys; + if (nToysAlt == 0 && !toyNum.Contains('.') && !sOpt.Contains("pnull")) + nToysAlt = nToys; + } else { + nToys = gEnv->GetValue("XRooFit.MaxToys",10000); + nToysAlt = 100; + // should really also set nToysAlt?? + } + } + + for (auto &p : *this) { if (s.RealTime() > 5) { if (visualize) { @@ -967,7 +990,11 @@ std::shared_ptr xRooNLLVar::xRooHypoSpace::graph( auto pval = const_cast(p).getVal(sOpt); auto idx = out->GetN() - nPointsDown; - if (std::isnan(pval.first)) { + double target=0.05; double relErrThreshold = 2; + double diff = (target < 0) ? pval.first : std::abs(pval.first - target); + // need logic that will treat points as bad where if running not readonly would get more toys + + if (std::isnan(pval.first) || (pval.second != 0 && (p.nullToys.size() < nToys || p.altToys.size() < nToysAlt) && (sOpt.Contains("toys=") || (sOpt.Contains("toys") && !sOpt.Contains("toys=") && doCLs && pval.second > 1e-4 && diff <= relErrThreshold * pval.second))) ) { if (p.status() != 0) { // if status is 0 then bad pval is really just absence of fits, not bad fits badPoints()->SetPoint(badPoints()->GetN(), _x, 0); } @@ -980,7 +1007,8 @@ std::shared_ptr xRooNLLVar::xRooHypoSpace::graph( TString sOpt2 = sOpt; sOpt2.ReplaceAll("exp", "exp-"); pval = const_cast(p).getVal(sOpt2); - if (std::isnan(pval.first)) { + diff = (target < 0) ? pval.first : std::abs(pval.first - target); + if (std::isnan(pval.first) || (pval.second != 0 && (p.nullToys.size() < nToys || p.altToys.size() < nToysAlt) && (sOpt.Contains("toys=") || (sOpt.Contains("toys") && !sOpt.Contains("toys=") && doCLs && pval.second > 1e-4 && diff <= relErrThreshold * pval.second))) ) { if (p.status() != 0) { // if status is 0 then bad pval is really just absence of fits, not bad fits badPoints()->SetPoint(badPoints()->GetN(), _x, 0); } @@ -1248,12 +1276,15 @@ xRooNLLVar::xValueWithError xRooNLLVar::xRooHypoSpace::GetLimit(const TGraph &pV (!above && gr->GetPointY(gr->GetN() - 1) >= gr->GetPointY(0))) { // extrapolating above based on last two points // in fact, if 2nd last point is a p=1 (log(p)=0) then go back + // also go back if m <= 0 int offset = 2; - while (offset < gr->GetN() && gr->GetPointY(gr->GetN() - offset) == 0) + double x1,y1,m; + do { + x1 = gr->GetPointX(gr->GetN() - offset); + y1 = gr->GetPointY(gr->GetN() - offset); + m = (gr->GetPointY(gr->GetN() - 1) - y1) / (gr->GetPointX(gr->GetN() - 1) - x1); offset++; - double x1 = gr->GetPointX(gr->GetN() - offset); - double y1 = gr->GetPointY(gr->GetN() - offset); - double m = (gr->GetPointY(gr->GetN() - 1) - y1) / (gr->GetPointX(gr->GetN() - 1) - x1); + } while(offset < gr->GetN() && (y1==0 || m<=0) ); if (m == 0.) return std::pair(std::numeric_limits::infinity(), std::numeric_limits::infinity()); return std::pair((alpha - y1) / m + x1, std::numeric_limits::infinity()); @@ -1287,7 +1318,8 @@ xRooNLLVar::xRooHypoSpace::findlimit(const char *opt, double relUncert, unsigned sOpt.ReplaceAll("visualize", ""); std::shared_ptr gr = graph(sOpt + " readonly"); if (visualize) { - auto gra = graphs(sOpt.Contains("toys") ? "pcls readonly toys" : "pcls readonly"); + TString toyConf = sOpt.Contains("toys") ? sOpt(sOpt.Index("toys"),(sOpt.Index(" ",sOpt.Index("toys"))==-1 ? sOpt.Length() : sOpt.Index(" ",sOpt.Index("toys")))-sOpt.Index("toys")) : TString(""); + auto gra = graphs(TString("pcls readonly") + toyConf); if (gra) { if (!gPad) gra->Draw(); // in 6.28 DrawClone wont make the gPad defined :( ... so Draw then clear and Draw Clone @@ -1324,7 +1356,7 @@ xRooNLLVar::xRooHypoSpace::findlimit(const char *opt, double relUncert, unsigned if (!gr || gr->GetN() < 1) { if (maxTries == 0 || std::isnan(AddPoint(TString::Format("%s=%g", v->GetName(), muMin)).getVal(sOpt).first)) { // first point failed ... give up - ::Error("findlimit", "Problem evaluating First Point %s @ %s=%g", sOpt.Data(), v->GetName(), muMin); + ::Error("findlimit", "Problem evaluating First Point %s @ %s=%g (maxTries=%d)", sOpt.Data(), v->GetName(), muMin,maxTries); return std::pair(std::numeric_limits::quiet_NaN(), 0.); } gr.reset(); diff --git a/roofit/xroofit/src/xRooNLLVar.cxx b/roofit/xroofit/src/xRooNLLVar.cxx index 7066b2c0df865..a40375f26032d 100644 --- a/roofit/xroofit/src/xRooNLLVar.cxx +++ b/roofit/xroofit/src/xRooNLLVar.cxx @@ -98,6 +98,7 @@ This xRooNLLVar object has several special methods, e.g. for fitting and toy dat #include "TKey.h" #include "TRegexp.h" #include "TStopwatch.h" +#include "TEnv.h" BEGIN_XROOFIT_NAMESPACE @@ -336,7 +337,7 @@ void xRooNLLVar::Print(Option_t *) std::cout << " MinimizerOptions: " << std::endl; fFitConfig->MinimizerOptions().Print(); } - std::cout << "Last Rebuild Log Output: " << fFuncCreationLog << std::endl; + std::cout << "Last Rebuild Log Output: " << std::endl << fFuncCreationLog << std::endl; } void xRooNLLVar::reinitialize() @@ -1268,10 +1269,17 @@ std::shared_ptr xRooNLLVar::func() const if (!(*this)) { const_cast(this)->reinitialize(); } else if (auto f = std::unique_ptr(fConstVars->selectByAttrib("Constant", false)); !f->empty()) { - // have to reinitialize if const par values have changed + // have to reinitialize if const par values have changed - const optimization forces this // TODO: currently changes to globs also triggers this since the vars includes globs (vars are the non-obs pars) // std::cout << "Reinitializing because of change of const parameters:" << f->contentsString() << std::endl; const_cast(this)->reinitialize(); + + // note ... it may be sufficient here to do: + // nll.constOptimizeTestStatistic(RooAbsArg::ConfigChange, constOptimize>1 /* do tracking too if >1 */); // + // trigger a re-evaluate of which nodes to cache-and-track nll.constOptimizeTestStatistic(RooAbsArg::ValueChange, + // constOptimize>1); // update the cache values -- is this needed?? + // this forces the optimization to be redone + // for now leave as a reinitialize though, until had a chance to test this properly } if (fGlobs && fFuncGlobs) { *fFuncGlobs = *fGlobs; @@ -1300,6 +1308,13 @@ void xRooNLLVar::SetOption(const RooCmdArg &opt) } else if (strcmp(opt.GetName(), "PrintLevel") == 0) { fitConfig()->MinimizerOptions().SetPrintLevel(opt.getInt(0)); } else { +#if ROOT_VERSION_CODE < ROOT_VERSION(6, 41, 00) + if (strcmp(opt.GetName(), "Optimize") == 0) { + // this flag will trigger constOptimizeTestStatistic to be called on the nll in createNLL method + // we should ensure that the fitconfig setting is consistent with it ... + fitConfigOptions()->SetValue("OptimizeConst", opt.getInt(0)); + } +#endif if (auto prevObject = fOpts->FindObject(opt.GetName()); prevObject) { // replace previous option fOpts->Replace(prevObject, opt.Clone(nullptr)); @@ -1446,35 +1461,48 @@ xRooNLLVar::xValueWithError xRooNLLVar::xRooHypoPoint::getVal(const char *what) bool readOnly = sWhat.Contains("readonly"); - if (!readOnly) { - if (toys) { - sigma_mu(); // means we will be able to evaluate the asymptotic values too - } + if (toys && !readOnly) { + sigma_mu(); // means we will be able to evaluate the asymptotic values too // only add toys if actually required - if (getVal(sWhat + " readonly").second != 0) { - if (sWhat.Contains("toys=")) { - // extract number of toys required ... format is "nullToys.altToysFraction" if altToysFraction=0 then use - // same for both, unless explicitly set (i.e. N.0) then means we want no alt toys - // e.g. if doing just pnull significance - TString toyNum = sWhat(sWhat.Index("toys=") + 5, sWhat.Length()); - size_t nToys = toyNum.Atoi(); - size_t nToysAlt = (toyNum.Atof() - nToys) * nToys; - if (nToysAlt == 0 && !toyNum.Contains('.') && !doNull) - nToysAlt = nToys; - if (nullToys.size() < nToys) { - addNullToys(nToys - nullToys.size()); - } - if (altToys.size() < nToysAlt) { - addAltToys(nToysAlt - altToys.size()); + + size_t nToys = 0; + size_t nToysAlt = 0; + bool autoToys = !sWhat.Contains("toys="); + if(!autoToys) { + // extract number of toys required ... format is "nullToys.altToysFraction" if altToysFraction=0 then use + // same for both, unless explicitly set (i.e. N.0) then means we want no alt toys + // e.g. if doing just pnull significance + TString toyNum = sWhat(sWhat.Index("toys=") + 5, sWhat.Length()); + nToys = toyNum.Atoi(); + nToysAlt = (toyNum.Atof() - nToys) * nToys; + if (nToysAlt == 0 && !toyNum.Contains('.') && !doNull) + nToysAlt = nToys; + if (nullToys.size() < nToys) { + addNullToys(nToys - nullToys.size()); + } + if (altToys.size() < nToysAlt) { + addAltToys(nToysAlt - altToys.size()); + } + } else { + // auto toys + if(doCLs) { + auto obs = getVal(sWhat + " readonly"); + double target=0.05; double relErrThreshold = 2; + double diff = (target < 0) ? obs.first : std::abs(obs.first - target); + double err = obs.second; + size_t maxToys = gEnv->GetValue("XRooFit.MaxToys",10000); + size_t nAltToys = 100; + // target mode is only used in auto toy generation + if((nullToys.size() < maxToys || altToys.size() 1e-4 && diff <= relErrThreshold * err))) { + // auto toy-generating for limits .. do in blocks of 100 + addCLsToys(nAltToys, 0/*seed*/, 0.05, nSigma); } - } else if (doCLs && toys) { - // auto toy-generating for limits .. do in blocks of 100 - addCLsToys(100, 0, 0.05, nSigma); - } else if (toys) { + } else { throw std::runtime_error("Auto-generating toys for anything other than CLs not yet supported, please " "specify number of toys with 'toys=N' "); } } + } struct RestoreNll { @@ -1768,8 +1796,8 @@ std::shared_ptr xRooNLLVar::xRooHypoPoint::asimov(boo // at some value of mu. Normally we would use mu=0 but if we have a bin // with only signal contribution (no bkg) will get asimov data in that bin // and no prediction ... the cfit(mu=0) will never succeed on this - // so lets move to half the alt value instead (the value used to generate) - v->setVal(theFit->constPars().getRealValue(v->GetName()) * 0.5); + // so lets move to 0.1% the alt value instead (the value used to generate) + v->setVal(theFit->constPars().getRealValue(v->GetName()) * gEnv->GetValue("XRooFit.AsimovNullValFactor",1e-3)); } } } @@ -2369,6 +2397,8 @@ size_t xRooNLLVar::xRooHypoPoint::addToys(bool alt, int nToys, int initialSeed, throw std::runtime_error("Cannot add toys, invalid conditional fit"); } + maxToys = std::min(maxToys,(size_t)gEnv->GetValue("XRooFit.MaxToys",10000)); + auto condition = [&]() { // returns true if need more toys if (std::isnan(target)) return false; @@ -2387,6 +2417,8 @@ size_t xRooNLLVar::xRooHypoPoint::addToys(bool alt, int nToys, int initialSeed, alt = (pAlt.second * pNull.first > pNull.second * pAlt.first); if ((alt ? pAlt.second : pNull.second) < 1e-4) return false; // stop if error gets too small + if( ((alt) ? altToys.size() : nullToys.size()) >= maxToys ) + return false; // stop if hit maxToys } return true; } @@ -2555,52 +2587,6 @@ void xRooNLLVar::xRooHypoPoint::addCLsToys(int nToys, int seed, double target, d { addToys(false, nToys, seed, target, target_nSigma, true); return; - // - // auto condition = [&](bool doingAlt=false) { // returns true if need more toys - // if(std::isnan(target)) return false; - // auto pval = pCLs_toys(target_nSigma); - // if (!std::isnan(pval.first)) { - // double diff = std::abs(pval.first - target); - // double err = pval.second; - // if (err > 1e-4 && diff <= 2 * pval.second) { - // return true; // more toys needed - // // decide which type we'd want to generate - // // if it matches the type we are generating, then return true - // auto pNull = pNull_toys(target_nSigma); - // auto pAlt = pAlt_toys(target_nSigma); - // if ((doingAlt ? pAlt.second : pNull.second) < 1e-4) return false; // stop if error gets too small - // bool doAlt = (pAlt.second * pNull.first > pNull.second * pAlt.first); - // return doAlt == doingAlt; - // } - // } - // return false; - // }; - // while(condition()) { - // bool doAlt = false; - // double relErrThreshold = 2; - // if(nullToys.size() pNull.second*pAlt.first); - // if( (doAlt ? pAlt.second : pNull.second) < 1e-4 ) break; // stop if error gets too small - // auto pCLs = pCLs_toys(target_nSigma); - // relErrThreshold = (doAlt) ? (pNull.second/pNull.first) : (pAlt.second/pAlt.first); - // relErrThreshold = std::min(2.,std::abs(relErrThreshold)); - // std::cout << "Current pCLs = " << pCLs.first << " +/- " << pCLs.second - // << " (pNull = " << pNull.first << " +/- " << pNull.second - // << " , pAlt = " << pAlt.first << " +/- " << pAlt.second << ") ... generating more " << (doAlt ? - // "alt" : "null") << " toys " << relErrThreshold << std::endl; - // - // } - // if( addToys(doAlt, nToys/*, seed, -1, target_nSigma,relErrThreshold*/) == 0) { - // break; // no toys got added, so stop looping - // } - // } } xRooNLLVar::xRooHypoPoint @@ -2855,6 +2841,7 @@ void xRooNLLVar::xRooHypoPoint::Draw(Option_t *opt) h->SetLineColor(isAlt ? kRed : kBlue); h->SetLineWidth(2); h->SetMarkerSize(0); + h->SetStats(false); h->SetBit(kCanDelete); return h; }; diff --git a/roofit/xroofit/src/xRooNode.cxx b/roofit/xroofit/src/xRooNode.cxx index 1e8a56f25fa8f..db76eafc9c511 100644 --- a/roofit/xroofit/src/xRooNode.cxx +++ b/roofit/xroofit/src/xRooNode.cxx @@ -4248,6 +4248,19 @@ void xRooNode::_fit_(const char *constParValues, const char *options) for (unsigned int i = 0; i < fr->numStatusHistory(); i++) { statusCodes += TString::Format("\n%s = %d", fr->statusLabelHistory(i), fr->statusCodeHistory(i)); } + // add poi to list of statusCodes too if was good fit + if(fr->status() == 0) { + auto _poi = poi(); + if (!_poi.empty()) { + statusCodes += "\n\nPOI Post Fit Values\n-------------"; + for (auto p : _poi) { + auto arg = dynamic_cast(fr->floatParsFinal().find(p->GetName())); + if (!arg) + continue; // must have been held constant + statusCodes += TString::Format("\n%s : %g +/- %g", arg->GetName(), arg->getVal(), arg->getError()); + } + } + } const TGWindow *w = (gROOT->GetListOfBrowsers()->At(0)) ? dynamic_cast(static_cast(gROOT->GetListOfBrowsers()->At(0))->GetBrowserImp()) @@ -8262,24 +8275,26 @@ std::vector new_getPropagatedErrors(const RooAbsReal &f, const RooFitRes std::vector plusVar(nBins), minusVar(nBins); + double ERROR_FACTOR = 1.; for (size_t ivar = 0; ivar < nPars; ivar++) { auto &rrv = static_cast((*_pars)[ivar]); auto *frrrv = static_cast(fr.floatParsFinal().find(rrv)); double cenVal = rrv.getVal(); + ERROR_FACTOR = 1;//(1e-2)*std::max(1.,std::abs(cenVal)); if (asymHi || asymLo) { double errValHi = frrrv->getErrorHi(); - rrv.setVal(errValHi > 0 ? std::min(cenVal + errValHi, rrv.getMax()) - : std::max(cenVal + errValHi, rrv.getMin())); + rrv.setVal(errValHi > 0 ? std::min(cenVal + errValHi*ERROR_FACTOR, rrv.getMax()) + : std::max(cenVal + errValHi*ERROR_FACTOR, rrv.getMin())); for (size_t k = 0; k < nBins; k++) { setBin(bins[k]); plusVar[k] = f.getVal(nset); } double errValLo = frrrv->getErrorLo(); - rrv.setVal(errValLo > 0 ? std::min(cenVal + errValLo, rrv.getMax()) - : std::max(cenVal + errValLo, rrv.getMin())); + rrv.setVal(errValLo > 0 ? std::min(cenVal + errValLo*ERROR_FACTOR, rrv.getMax()) + : std::max(cenVal + errValLo*ERROR_FACTOR, rrv.getMin())); for (size_t k = 0; k < nBins; k++) { setBin(bins[k]); minusVar[k] = f.getVal(nset); @@ -8297,25 +8312,25 @@ std::vector new_getPropagatedErrors(const RooAbsReal &f, const RooFitRes lo = std::min(plusVar[k], minusVar[k]); hi = 2 * nomVals[k] - lo; // symmetrizes } - F[k][ivar] = (hi - lo) * 0.5; + F[k][ivar] = (hi - lo) * 0.5 / ERROR_FACTOR; } } else { - double errVal = sqrt(V(ivar, ivar)); + double errVal = sqrt(V(ivar, ivar));//frrrv->getError(); //sqrt(V(ivar, ivar)); // Make Plus variation - rrv.setVal(std::min(cenVal + errVal, rrv.getMax())); + rrv.setVal(std::min(cenVal + errVal*ERROR_FACTOR, rrv.getMax())); for (size_t k = 0; k < nBins; k++) { setBin(bins[k]); plusVar[k] = f.getVal(nset); } // Make Minus variation - rrv.setVal(std::max(cenVal - errVal, rrv.getMin())); + rrv.setVal(std::max(cenVal - errVal*ERROR_FACTOR, rrv.getMin())); for (size_t k = 0; k < nBins; k++) { setBin(bins[k]); minusVar[k] = f.getVal(nset); } rrv.setVal(cenVal); for (size_t k = 0; k < nBins; k++) { - F[k][ivar] = (plusVar[k] - minusVar[k]) * 0.5; + F[k][ivar] = (plusVar[k] - minusVar[k]) * 0.5 / ERROR_FACTOR; } } } @@ -8691,7 +8706,7 @@ xRooNode xRooNode::histo(const xRooNode &vars, const xRooNode &fr, bool content, { if (!vars.fComp && strlen(vars.GetName())) { - return histo(xRooNode::vars().reduced(vars.GetName()), fr, content, errors); + return histo(xRooNode::vars().reduced(vars.GetName()), fr, content, errors,stack,errorsHi,errorsLo,nErrorToys); } xRooNode out(TString::Format("%s.histo", GetName()), nullptr, *this); @@ -9354,7 +9369,7 @@ TH1 *xRooNode::BuildHistogram(RooAbsLValue *v, bool empty, bool errors, int binS h->SetBinError(i, (upVal - downVal) * 0.5); } } - +#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 41, 00) // We evaluated the above with `normSet`, which lives on this function's stack. // RooFit proxies only cache a bare pointer to the last normSet and re-use it // later (e.g. RooProduct::evaluate reads back _compRSet.nset()), so before it @@ -9362,6 +9377,8 @@ TH1 *xRooNode::BuildHistogram(RooAbsLValue *v, bool empty, bool errors, int binS // otherwise a later evaluation dereferences freed stack ("use of uninitialised // value" in valgrind). sterilize() only walks clients, but getVal() propagates // the normSet to the servers of the evaluated function, so reset those here. + // setProxyNormSet made public in 6.41 + { RooArgSet evaluatedNodes; for (RooAbsArg *treeRoot : {static_cast(rar), static_cast(p), @@ -9373,7 +9390,7 @@ TH1 *xRooNode::BuildHistogram(RooAbsLValue *v, bool empty, bool errors, int binS node->setProxyNormSet(nullptr); } } - +#endif if (oldrar) { std::vector extra; if (auto s = dynamic_cast(rar)) { diff --git a/test/PostInstall/check-headers.sh b/test/PostInstall/check-headers.sh index 1ed4ffbd4e58c..2f0599c8a8025 100644 --- a/test/PostInstall/check-headers.sh +++ b/test/PostInstall/check-headers.sh @@ -30,7 +30,6 @@ fi # Check all installed headers for include errors. Some headers cannot be used standalone: suppressions="RField[A-Z]\|RtypesImp.h\|TAtomicCount[A-Z]\|CladDerivator.h\|TBranchProxyTemplate" # Not to be used standalone suppressions+="\|TWin32" # Why are these installed in Linux? -suppressions+="\|xRooHypoSpace.h\|xRooFit" # Uses macros to declare namespaces suppressions+="\|RIoUring.hxx" # Might not be installed suppressions+="\|TCudnn.h" # Might not be installed suppressions+="\|cpyrt/DispatchPtr.h\|cpyrt/API.h" # Would need to include Python.h