Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v634][PyROOT] Don't add gROOT and other globals manually to PyROOT via C++ #16916

Merged
merged 4 commits into from
Nov 13, 2024
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
1 change: 0 additions & 1 deletion bindings/pyroot/pythonizations/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ set(py_sources

set(cpp_sources
src/PyROOTModule.cxx
src/PyROOTWrapper.cxx
src/RPyROOTApplication.cxx
src/GenericPyz.cxx
src/TClassPyz.cxx
Expand Down
3 changes: 1 addition & 2 deletions bindings/pyroot/pythonizations/python/ROOT/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,15 +185,14 @@ def cleanup():
facade.__dict__["app"].process_root_events.join()

if "libROOTPythonizations" in sys.modules:
backend = sys.modules["libROOTPythonizations"]

from ROOT import PyConfig

if PyConfig.ShutDown:
# Hard teardown: run part of the gROOT shutdown sequence.
# Running it here ensures that it is done before any ROOT libraries
# are off-loaded, with unspecified order of static object destruction.
backend.gROOT.EndOfProcessCleanups()
facade.gROOT.EndOfProcessCleanups()


atexit.register(cleanup)
13 changes: 7 additions & 6 deletions bindings/pyroot/pythonizations/python/ROOT/_facade.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

import cppyy.ll

from libROOTPythonizations import gROOT

from ._application import PyROOTApplication
from ._numbadeclare import _NumbaDeclareDecorator

Expand All @@ -36,7 +34,7 @@ class _gROOTWrapper(object):

def __init__(self, facade):
self.__dict__["_facade"] = facade
self.__dict__["_gROOT"] = gROOT
self.__dict__["_gROOT"] = cppyy.gbl.ROOT.GetROOT()

def __getattr__(self, name):
if name != "SetBatch" and self._facade.__dict__["gROOT"] != self._gROOT:
Expand Down Expand Up @@ -158,7 +156,7 @@ def _fallback_getattr(self, name):
elif hasattr(cppyy.gbl.ROOT, name):
return getattr(cppyy.gbl.ROOT, name)
else:
res = gROOT.FindObject(name)
res = self.gROOT.FindObject(name)
if res:
return res
raise AttributeError("Failed to get attribute {} from ROOT".format(name))
Expand Down Expand Up @@ -204,7 +202,10 @@ def _register_converters_and_executors(self):

def _finalSetup(self):
# Prevent this method from being re-entered through the gROOT wrapper
self.__dict__["gROOT"] = gROOT
self.__dict__["gROOT"] = cppyy.gbl.ROOT.GetROOT()

# Make sure the interpreter is initialized once gROOT has been initialized
cppyy.gbl.TInterpreter.Instance()

# Setup interactive usage from Python
self.__dict__["app"] = PyROOTApplication(self.PyConfig, self._is_ipython)
Expand Down Expand Up @@ -387,7 +388,7 @@ def TMVA(self):
from ._pythonization import _tmva

ns = self._fallback_getattr("TMVA")
hasRDF = "dataframe" in gROOT.GetConfigFeatures()
hasRDF = "dataframe" in self.gROOT.GetConfigFeatures()
if hasRDF:
try:
from ._pythonization._tmva import inject_rbatchgenerator, _AsRTensor, SaveXGBoost
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

from .. import pythonization

from libROOTPythonizations import gROOT

from ._factory import Factory
from ._dataloader import DataLoader
from ._crossvalidation import CrossValidation
Expand Down Expand Up @@ -45,7 +43,7 @@ def inject_rbatchgenerator(ns):

from ._gnn import RModel_GNN, RModel_GraphIndependent

hasRDF = "dataframe" in gROOT.GetConfigFeatures()
hasRDF = "dataframe" in cppyy.gbl.ROOT.GetROOT().GetConfigFeatures()
if hasRDF:
from ._rtensor import get_array_interface, add_array_interface_property, RTensorGetitem, pythonize_rtensor, _AsRTensor

Expand Down
29 changes: 26 additions & 3 deletions bindings/pyroot/pythonizations/src/PyROOTModule.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@

// Bindings
#include "PyROOTPythonize.h"
#include "PyROOTWrapper.h"
#include "RPyROOTApplication.h"
#include "TMemoryRegulator.h"

// Cppyy
#include "CPyCppyy/API.h"
#include "../../cppyy/CPyCppyy/src/CallContext.h"
#include "../../cppyy/CPyCppyy/src/ProxyWrappers.h"

// ROOT
#include "TInterpreter.h"
#include "TROOT.h"
#include "TSystem.h"
#include "RConfigure.h"
Expand Down Expand Up @@ -62,6 +63,20 @@ PyObject *RegisterExecutorAlias(PyObject * /*self*/, PyObject *args)

} // namespace PyROOT

namespace {

PyROOT::RegulatorCleanup &GetRegulatorCleanup()
{
// The object is thread-local because it can happen that we call into
// C++ code (from the PyROOT CPython extension, from CPyCppyy or from cling)
// from different Python threads. A notable example is within a distributed
// RDataFrame application running on Dask.
thread_local PyROOT::RegulatorCleanup m;
return m;
}

} // namespace

// Methods offered by the interface
static PyMethodDef gPyROOTMethods[] = {
{(char *)"AddCPPInstancePickling", (PyCFunction)PyROOT::AddCPPInstancePickling, METH_VARARGS,
Expand Down Expand Up @@ -144,8 +159,16 @@ extern "C" PyObject *PyInit_libROOTPythonizations()
// keep gRootModule, but do not increase its reference count even as it is borrowed,
// or a self-referencing cycle would be created

// setup PyROOT
PyROOT::Init();
// Initialize and acquire the GIL to allow for threading in ROOT
#if PY_VERSION_HEX < 0x03090000
PyEval_InitThreads();
#endif

// Memory management
gROOT->GetListOfCleanups()->Add(&GetRegulatorCleanup());

// Make sure the interpreter is initialized once gROOT has been initialized
TInterpreter::Instance();

// signal policy: don't abort interpreter in interactive mode
CallContext::SetGlobalSignalPolicy(!gROOT->IsBatch());
Expand Down
67 changes: 0 additions & 67 deletions bindings/pyroot/pythonizations/src/PyROOTWrapper.cxx

This file was deleted.

24 changes: 0 additions & 24 deletions bindings/pyroot/pythonizations/src/PyROOTWrapper.h

This file was deleted.

2 changes: 1 addition & 1 deletion bindings/pyroot/pythonizations/test/numbadeclare.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def fn1(x):

self.assertTrue(hasattr(fn1, "__cpp_wrapper__"))
self.assertTrue(type(fn1.__cpp_wrapper__) == str)
self.assertEqual(sys.getrefcount(fn1.__cpp_wrapper__), 3)
self.assertLessEqual(sys.getrefcount(fn1.__cpp_wrapper__), 3)

self.assertTrue(hasattr(fn1, "__py_wrapper__"))
self.assertTrue(type(fn1.__py_wrapper__) == str)
Expand Down
13 changes: 13 additions & 0 deletions roofit/roofitcore/inc/RooFit/Detail/MathFuncs.h
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,19 @@ inline double bernsteinIntegral(double xlo, double xhi, double xmin, double xmax
return norm * (xmax - xmin);
}

inline double multiVarGaussian(int n, const double *x, const double *mu, const double *covI)
{
double result = 0.0;

// Compute the bilinear form (x-mu)^T * covI * (x-mu)
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
result += (x[i] - mu[i]) * covI[i * n + j] * (x[j] - mu[j]);
}
}
return std::exp(-0.5 * result);
}

} // namespace MathFuncs

} // namespace Detail
Expand Down
4 changes: 4 additions & 0 deletions roofit/roofitcore/inc/RooMultiVarGaussian.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ class RooMultiVarGaussian : public RooAbsPdf {

static void blockDecompose(const TMatrixD& input, const std::vector<int>& map1, const std::vector<int>& map2, TMatrixDSym& S11, TMatrixD& S12, TMatrixD& S21, TMatrixDSym& S22) ;

void translate(RooFit::Detail::CodeSquashContext &ctx) const override;
std::string
buildCallToAnalyticIntegral(Int_t code, const char *rangeName, RooFit::Detail::CodeSquashContext &ctx) const override;

protected:

void decodeCode(Int_t code, std::vector<int>& map1, std::vector<int>& map2) const;
Expand Down
19 changes: 18 additions & 1 deletion roofit/roofitcore/src/RooMultiVarGaussian.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,11 @@ double RooMultiVarGaussian::evaluate() const
return exp(-0.5*alpha) ;
}


void RooMultiVarGaussian::translate(RooFit::Detail::CodeSquashContext &ctx) const
{
std::span<const double> covISpan{_covI.GetMatrixArray(), static_cast<size_t>(_covI.GetNoElements())};
ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::multiVarGaussian", _x.size(), _x, _mu, covISpan));
}

////////////////////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -310,6 +314,19 @@ double RooMultiVarGaussian::analyticalIntegral(Int_t code, const char* /*rangeNa
}


std::string RooMultiVarGaussian::buildCallToAnalyticIntegral(Int_t code, const char *rangeName,
RooFit::Detail::CodeSquashContext & /*ctx*/) const
{
if (code != -1) {
std::stringstream errorMsg;
errorMsg << "Partial integrals over RooMultiVarGaussian are not supported.";
coutE(Minimization) << errorMsg.str() << std::endl;
throw std::runtime_error(errorMsg.str().c_str());
}

return std::to_string(analyticalIntegral(code, rangeName));
}


////////////////////////////////////////////////////////////////////////////////
/// Check if cache entry was previously created
Expand Down
Loading