From 2a2b0ccd59b6d0930d0dabd32dcd9a101586c80c Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Mon, 16 Mar 2026 18:53:11 +0100 Subject: [PATCH] [RF] Test RooFit Hessians with Clad --- .../cling/tools/plugins/clad/CMakeLists.txt | 2 +- roofit/histfactory/test/testHistFactory.cxx | 36 +++++++++++++------ roofit/roofitcore/test/testRooFuncWrapper.cxx | 12 +++++-- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/interpreter/cling/tools/plugins/clad/CMakeLists.txt b/interpreter/cling/tools/plugins/clad/CMakeLists.txt index 79e1cd41d23d1..f0d3d843397ba 100644 --- a/interpreter/cling/tools/plugins/clad/CMakeLists.txt +++ b/interpreter/cling/tools/plugins/clad/CMakeLists.txt @@ -74,7 +74,7 @@ if (DEFINED CLAD_SOURCE_DIR) list(APPEND _clad_extra_settings SOURCE_DIR ${CLAD_SOURCE_DIR}) else() list(APPEND _clad_extra_settings GIT_REPOSITORY https://github.com/vgvassilev/clad.git) - list(APPEND _clad_extra_settings GIT_TAG v2.2) + list(APPEND _clad_extra_settings GIT_TAG master) endif() ## list(APPEND _clad_patches_list "patch1.patch" "patch2.patch") diff --git a/roofit/histfactory/test/testHistFactory.cxx b/roofit/histfactory/test/testHistFactory.cxx index ec0aee3fc4dcf..aca73b38b302a 100644 --- a/roofit/histfactory/test/testHistFactory.cxx +++ b/roofit/histfactory/test/testHistFactory.cxx @@ -9,17 +9,19 @@ #include #include -#include -#include -#include #include -#include -#include -#include -#include +#include +#include +#include +#include #include +#include +#include #include -#include +#include +#include +#include +#include #include #include @@ -618,9 +620,21 @@ TEST_P(HFFixtureFit, Fit) } using namespace RooFit; - std::unique_ptr fitResult{simPdf->fitTo(*data, evalBackend, Optimize(constTermOptimization), - GlobalObservables(*mc->GetGlobalObservables()), Save(), - PrintLevel(verbose ? 1 : -1))}; + std::unique_ptr nll{simPdf->createNLL(*data, evalBackend, Optimize(constTermOptimization), + GlobalObservables(*mc->GetGlobalObservables()))}; + RooMinimizer::Config cfg; + if (evalBackend == RooFit::EvalBackend::Codegen()) { + // Make sure we use both analytical gradient and Hessian + static_cast(*nll).generateGradient(); + static_cast(*nll).generateHessian(); + cfg.useGradient = true; + cfg.useHessian = true; + } + RooMinimizer minim{*nll, cfg}; + minim.setPrintLevel(verbose ? 1 : -1); + minim.minimize("Minuit2", "Migrad"); + minim.hesse(); + std::unique_ptr fitResult{minim.save()}; ASSERT_NE(fitResult, nullptr); if (verbose) fitResult->Print("v"); diff --git a/roofit/roofitcore/test/testRooFuncWrapper.cxx b/roofit/roofitcore/test/testRooFuncWrapper.cxx index 9a5250e8b25b7..da4568b0a3ca1 100644 --- a/roofit/roofitcore/test/testRooFuncWrapper.cxx +++ b/roofit/roofitcore/test/testRooFuncWrapper.cxx @@ -129,14 +129,16 @@ class FactoryTest : public testing::TestWithParam { std::unique_ptr _changeMsgLvl; }; -std::unique_ptr runMinimizer(RooAbsReal &absReal, bool useGradient = true) +std::unique_ptr runMinimizer(RooAbsReal &absReal, bool useAD = true) { RooMinimizer::Config cfg; - cfg.useGradient = useGradient; + cfg.useGradient = useAD; + cfg.useHessian = useAD; RooMinimizer m{absReal, cfg}; m.setPrintLevel(-1); m.setStrategy(0); m.minimize("Minuit2"); + m.hesse(); // to use the analytical Hessian for error estimation return std::unique_ptr{m.save()}; } @@ -164,6 +166,9 @@ TEST_P(FactoryTest, NLLFit) // We want to use the generated code also for the nominal likelihood. Like // this, we make sure to validate also the NLL values of the generated code. static_cast(*nllFunc).setUseGeneratedFunctionCode(true); + // Let's also validate the Hessian + static_cast(*nllFunc).generateHessian(); + static_cast(*nllFunc).writeDebugMacro(_params._name); double tol = _params._fitResultTolerance; @@ -214,6 +219,9 @@ TEST_P(FactoryTest, NLLFit) // because for very small correlations it's usually not the same within the // relative tolerance because you would compare two small values that are // only different from zero because of noise. + // The error tolerance is also quite large, because the analytical Hessian + // gives numerically quite different results. + double errorTol = 0.1; EXPECT_TRUE(result->isIdenticalNoCov(*resultRef, tol, tol)); EXPECT_TRUE(resultAd->isIdenticalNoCov(*resultRef, tol, tol)); }