Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions roofit/roofitcore/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ ROOT_ADD_GTEST(testRooTruthModel testRooTruthModel.cxx LIBRARIES RooFitCore RooF
COPY_TO_BUILDDIR ${CMAKE_CURRENT_SOURCE_DIR}/rooAbsAnaConvPdf_classV3.root)

if (roofit_multiprocess)
ROOT_ADD_GTEST(testTestStatisticsPlot TestStatistics/testPlot.cxx LIBRARIES RooFitMultiProcess RooFitCore RooFit
COPY_TO_BUILDDIR ${CMAKE_CURRENT_SOURCE_DIR}/TestStatistics/TestStatistics_ref.root)
ROOT_ADD_GTEST(testTestStatisticsPlot TestStatistics/testPlot.cxx LIBRARIES RooFitMultiProcess RooFitCore RooFit)
ROOT_ADD_GTEST(testLikelihoodGradientJob TestStatistics/testLikelihoodGradientJob.cxx LIBRARIES RooFitMultiProcess RooFitCore m ROOT::TestSupport)
target_include_directories(testLikelihoodGradientJob PRIVATE ${RooFitCore_MultiProcess_TestStatistics_INCLUDE_DIR})
ROOT_ADD_GTEST(testLikelihoodJob TestStatistics/testLikelihoodJob.cxx LIBRARIES RooFitMultiProcess RooFitCore m)
Expand Down
Binary file not shown.
142 changes: 79 additions & 63 deletions roofit/roofitcore/test/TestStatistics/testPlot.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -11,83 +11,99 @@
*/

#include <RooAbsPdf.h>
#include <RooCurve.h>
#include <RooDataSet.h>
#include <RooFit/MultiProcess/Config.h>
#include <RooFit/TestStatistics/RooRealL.h>
#include <RooFit/TestStatistics/buildLikelihood.h>
#include <RooGlobalFunc.h>
#include <RooHelpers.h>
#include <RooMinimizer.h>
#include <RooPlot.h>
#include <RooRealVar.h>
#include <RooUnitTest.h>
#include <RooWorkspace.h>

#include <TFile.h>

#include <gtest/gtest.h>

#include <cmath>
#include <memory>

using namespace RooFit;

class TestRooRealLPlot : public RooUnitTest {
public:
TestRooRealLPlot(TFile &refFile, bool writeRef, int verbose)
: RooUnitTest("Plotting and minimization with RooFit::TestStatistics", &refFile, writeRef, verbose){};
bool testCode() override
{

// C r e a t e m o d e l a n d d a t a
// ---------------------------------------
// Constructing a workspace with pdf and dataset
RooWorkspace w("w");
w.factory("expr::Nexp('mu*S+B',mu[1,-1,10],S[10],B[20])");
w.factory("Poisson::model(Nobs[0,100],Nexp)");
w.var("Nobs")->setBins(4);
RooDataSet d("d", "d", *w.var("Nobs"));
w.var("Nobs")->setVal(25);
d.add(*w.var("Nobs"));

// P e r f o r m a p a r a l l e l l i k e l i h o o d m i n i m i z a t i o n
// --------------------------------------------------------------------------------

// Creating a RooAbsL likelihood
std::unique_ptr<RooAbsReal> likelihood{w.pdf("model")->createNLL(d, ModularL(true))};

// Creating a minimizer and explicitly setting type of parallelization
std::size_t nWorkers = 1;
RooMinimizer::Config cfg;
cfg.parallelize = nWorkers;
cfg.enableParallelDescent = false;
cfg.enableParallelGradient = true;
RooMinimizer m(*likelihood, cfg);

// Minimize
m.migrad();

// C o n v e r t t o R o o R e a l L a n d p l o t
// ---------------------------------------------------
RooPlot *xframe = w.var("mu")->frame(-1, 10);
likelihood->plotOn(xframe, RooFit::Precision(1));

// --- Post processing for RooUnitTest ---
regPlot(xframe, "TestRooRealLPlot_plot");

return true;
}
};

/// Plotting and minimization with RooFit::TestStatistics: minimize a
/// RooFit::TestStatistics likelihood with the parallel gradient and plot it as
/// a function of the parameter. The results are validated against analytic
/// expectations and against direct evaluations of the likelihood, instead of
/// the RooUnitTest reference file that was used before.
TEST(TestStatisticsPlot, RooRealL)
{
// Run the RooUnitTest and assert that it succeeds with gtest

RooUnitTest::setMemDir(gDirectory);

gErrorIgnoreLevel = kWarning;

TFile fref("TestStatistics_ref.root");
RooHelpers::LocalChangeMsgLevel changeMsgLvl{RooFit::WARNING};

// C r e a t e m o d e l a n d d a t a
// ---------------------------------------
// Constructing a workspace with pdf and dataset
RooWorkspace w("w");
w.factory("expr::Nexp('mu*S+B',mu[1,-1,10],S[10],B[20])");
w.factory("Poisson::model(Nobs[0,100],Nexp)");
w.var("Nobs")->setBins(4);
RooDataSet d("d", "d", *w.var("Nobs"));
w.var("Nobs")->setVal(25);
d.add(*w.var("Nobs"));

RooRealVar &mu = *w.var("mu");

// P e r f o r m a p a r a l l e l l i k e l i h o o d m i n i m i z a t i o n
// --------------------------------------------------------------------------------

// Creating a RooAbsL likelihood
std::unique_ptr<RooAbsReal> likelihood{w.pdf("model")->createNLL(d, ModularL(true))};

// Creating a minimizer and explicitly setting type of parallelization
std::size_t nWorkers = 1;
RooMinimizer::Config cfg;
cfg.parallelize = nWorkers;
cfg.enableParallelDescent = false;
cfg.enableParallelGradient = true;
RooMinimizer m(*likelihood, cfg);

// Minimize
m.setPrintLevel(-1);
m.migrad();

// The analytic maximum likelihood estimate is at Nexp = Nobs, i.e.
// mu = (Nobs - B) / S. The tolerance is at the scale of the Minuit
// convergence criterion, given that sigma(mu) = sqrt(Nobs) / S = 0.5.
EXPECT_NEAR(mu.getVal(), 0.5, 0.05 * 0.5);

// C o n v e r t t o R o o R e a l L a n d p l o t
// ---------------------------------------------------
std::unique_ptr<RooPlot> xframe{mu.frame(-1, 10)};
likelihood->plotOn(xframe.get(), RooFit::Precision(1));
RooCurve *curve = xframe->getCurve();
ASSERT_NE(curve, nullptr);
ASSERT_GT(curve->GetN(), 1);

// Every point of the plotted curve must match a direct evaluation of the
// likelihood at that parameter value
for (int i = 0; i < curve->GetN(); ++i) {
const double muVal = curve->GetPointX(i);
if (muVal < mu.getMin() || muVal > mu.getMax())
continue;
mu.setVal(muVal);
const double directVal = likelihood->getVal();
EXPECT_NEAR(curve->GetPointY(i), directVal, 1e-6 * std::max(1.0, std::abs(directVal)))
<< "curve point " << i << " at mu = " << muVal;
}

TestRooRealLPlot plotTest{fref, false, 0};
bool result = plotTest.runTest();
ASSERT_TRUE(result);
// The likelihood must also match the analytically known Poisson -log L,
// which is defined up to a mu-independent constant. The comparison is
// restricted to moderate Nexp values, where the truncation of the Poisson
// normalization to the observable range is negligible.
auto analyticNll = [](double muVal) {
const double nexp = 10 * muVal + 20;
return nexp - 25 * std::log(nexp);
};
mu.setVal(0.5);
const double nllOffset = likelihood->getVal() - analyticNll(0.5);
for (double muVal : {0.0, 1.0, 2.0, 3.0}) {
mu.setVal(muVal);
EXPECT_NEAR(likelihood->getVal(), analyticNll(muVal) + nllOffset, 1e-4) << "at mu = " << muVal;
}
}
23 changes: 11 additions & 12 deletions roofit/roostats/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,19 @@ ROOT_ADD_GTEST(testHypoTestInvResult testHypoTestInvResult.cxx
ROOT_ADD_GTEST(testSPlot testSPlot.cxx LIBRARIES RooStats)

#--stressRooStats----------------------------------------------------------------------------------
ROOT_EXECUTABLE(stressRooStats stressRooStats.cxx LIBRARIES RooStats Gpad Net)
# Googletest version of the old RooStats S.T.R.E.S.S. suite, parameterized
# over the RooFit evaluation backends. Like in the original suite, the tests
# are also run with the Minuit2 minimizer (the default minimizer of the suite
# is Minuit2).
ROOT_ADD_GTEST(stressRooStats stressRooStats.cxx LIBRARIES RooStats LABELS longtest TIMEOUT 3600)
if(mathmore)
target_compile_definitions(stressRooStats PRIVATE ROOFITMORE)
endif()

configure_file(stressRooStats_ref.root stressRooStats_ref.root COPYONLY)
if(roofit_legacy_eval_backend)
ROOT_ADD_TEST(test-stressroostats-legacy COMMAND stressRooStats -b legacy FAILREGEX "FAILED|Error in" LABELS longtest)
endif()
ROOT_ADD_TEST(test-stressroostats-cpu COMMAND stressRooStats -b cpu FAILREGEX "FAILED|Error in" LABELS longtest)
if(cuda)
ROOT_ADD_TEST(test-stressroostats-cuda COMMAND stressRooStats -b cuda FAILREGEX "FAILED|Error in" LABELS longtest RESOURCE_LOCK GPU)
endif()
if(roofit_legacy_eval_backend)
ROOT_ADD_TEST(test-stressroostats-legacy-minuit2 COMMAND stressRooStats -minim Minuit2 -b legacy FAILREGEX "FAILED|Error in" LABELS longtest)
set_tests_properties(gtest-roofit-roostats-stressRooStats PROPERTIES RESOURCE_LOCK GPU)
endif()
ROOT_ADD_TEST(test-stressroostats-cpu-minuit2 COMMAND stressRooStats -minim Minuit2 -b cpu FAILREGEX "FAILED|Error in" LABELS longtest)
# Like the non-default-minimizer variant in the original suite, the Minuit
# variant only runs the legacy and cpu backends (that is also why it doesn't
# need to lock the GPU resource).
ROOT_ADD_TEST(test-stressroostats-minuit COMMAND stressRooStats --gtest_filter=-*EvalBackendcuda*
ENVIRONMENT STRESSROOSTATS_MINIMIZER=Minuit LABELS longtest TIMEOUT 3600)
Loading
Loading