cms-analysis / HiggsAnalysis-CombinedLimit

CMS Higgs Combination toolkit.
https://cms-analysis.github.io/HiggsAnalysis-CombinedLimit/latest
Apache License 2.0
75 stars 383 forks source link

RooBernsteinFast doesn't work like RooBernstein #986

Closed green-cabbage closed 3 months ago

green-cabbage commented 3 months ago

This is not a huge issue (I hope), but I am currently looking for any ROOT.RooBernstein replacements since ROOT.RooBernstein doesn't play nice with combine's MultiPdf, as mentioned in the reply of this CMS Talk post. I am hoping that comebine's RooBernsteinFast function would work, so I tried to use in in pyROOT as shown below:

import ROOT as rt

name ="coeff"
BernCoeff_list = rt.RooArgList(
    rt.RooRealVar(name,name, 1.0,-2.0, 2.0)
)
mass_name = "dimuon_mass"
mass =  rt.RooRealVar(mass_name,mass_name,120,110,150)
name = "bern model"
bern_model = rt.RooBernsteinFast(name, name, mass, BernCoeff_list)

and it gives me this error:

Traceback (most recent call last):

  File [/depot/cms/kernels/root632/lib/python3.12/site-packages/IPython/core/interactiveshell.py:3577](https://cms.geddes.rcac.purdue.edu/depot/cms/kernels/root632/lib/python3.12/site-packages/IPython/core/interactiveshell.py#line=3576) in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)

  Cell In[3], line 8
    bern_model = rt.RooBernsteinFast(name, name, mass, BernCoeff_list)

  File [/depot/cms/kernels/root632/lib/python3.12/site-packages/cppyy/_cpython_cppyy.py:143](https://cms.geddes.rcac.purdue.edu/depot/cms/kernels/root632/lib/python3.12/site-packages/cppyy/_cpython_cppyy.py#line=142) in __call__
    return self.__getitem__(*args)

  File [/depot/cms/kernels/root632/lib/python3.12/site-packages/cppyy/_cpython_cppyy.py:88](https://cms.geddes.rcac.purdue.edu/depot/cms/kernels/root632/lib/python3.12/site-packages/cppyy/_cpython_cppyy.py#line=87) in __getitem__
    pyclass = _backend.MakeCppTemplateClass(*newargs)

  File <string>
SyntaxError: could not construct C++ name from provided template argument.

my pyROOT version is 6.32.00, and combine version is v10.0.1. Thank you in advance!

amarini commented 3 months ago

Hi, RooBernsteinFast is a template class on the order. You need to specify the template both in C++ and python. IIRC, this berstein implementation solves an intrinsic degeneracy (remember that we need a separate normalization term) in the definition that in the past was present in the RooBerstein, by setting the first coefficient to 1. This is correct for falling spectra or for spectra that do not start from 0.

In python you can do something like:

bern = ROOT.RooBernsteinFast(order)("pdf_bern_cat","bernstein",mmm, coeff)
green-cabbage commented 3 months ago

Thank you for the prompt response; I really appreciate it. I have updated my reproducer code in this manner :

import ROOT as rt
import numpy as np
import awkward as ak

name ="coeff"
BernCoeff_list = rt.RooArgList(
    rt.RooRealVar(name,name, 0.25,0, 2.0),
    rt.RooRealVar(name,name, 0.25,0, 2.0)
)

mass_name = "dimuon_mass"
mass =  rt.RooRealVar(mass_name,mass_name,0.5,0.0,1.0)
# mass =  rt.RooRealVar(mass_name,mass_name,125,110,150)
mass.setBins(80)

# generate exp decay data
mass_arr = np.random.uniform(size=100)
mass_arr = np.exp(-100 * mass_arr)
roo_dataset = rt.RooDataSet.from_numpy({mass_name: mass_arr}, [mass])
roo_hist = rt.RooDataHist("data_hist","data_hist", rt.RooArgSet(mass), roo_dataset)

name = "bern model"

order = 3
bern_model =  rt.RooBernsteinFast(order)("pdf_bern_cat","bernstein",mass, BernCoeff_list)
rt.EnableImplicitMT()
bern_model.fitTo(roo_hist, EvalBackend="cpu", Save=True)

Running this script still returns this Segfault:

 *** Break *** segmentation violation
 Generating stack trace...
 0x00007f18c39d205e in RooAbsCollection::insert(RooAbsArg*) + 0xae from /depot/cms/kernels/root632/lib/libRooFitCore.so.6.32.00
 0x00007f18c39d2418 in RooAbsCollection::add(RooAbsArg const&, bool) + 0x38 from /depot/cms/kernels/root632/lib/libRooFitCore.so.6.32.00
 0x00007f18c39990e5 in <unknown> from /depot/cms/kernels/root632/lib/libRooFitCore.so.6.32.00
 0x00007f18be71faa4 in <unknown function>
 0x00007f18be71f255 in <unknown function>
 0x00007f18be71f077 in <unknown function>
 0x00007f1d20a01bfe in <unknown> from /depot/cms/kernels/root632/lib/python3.12/lib-dynload/../../libcppyy_backend.so
 0x00007f1d20a026dc in Cppyy::CallConstructor(long, unsigned long, unsigned long, void*) + 0x2c from /depot/cms/kernels/root632/lib/python3.12/lib-dynload/../../libcppyy_backend.so
 0x00007f1d00203e2a in <unknown> from /depot/cms/kernels/root632/lib/python3.12/site-packages/libcppyy.so
 0x00007f1d00204196 in CPyCppyy::CPPMethod::Execute(void*, long, CPyCppyy::CallContext*) + 0x56 from /depot/cms/kernels/root632/lib/python3.12/site-packages/libcppyy.so
 0x00007f1d001f6594 in CPyCppyy::CPPConstructor::Call(CPyCppyy::CPPInstance*&, _object* const*, unsigned long, _object*, CPyCppyy::CallContext*) + 0x364 from /depot/cms/kernels/root632/lib/python3.12/site-packages/libcppyy.so
 0x00007f1d0020b963 in <unknown> from /depot/cms/kernels/root632/lib/python3.12/site-packages/libcppyy.so
 0x000056477d47780d in _PyObject_FastCallDictTstate + 0x2ed from python
 0x000056477d4a2c53 in <unknown> from python
 0x000056477d474d5c in _PyObject_MakeTpCall + 0x2bc from python
 0x000056477d37bf20 in <unknown> from python
 0x000056477d52f6fe in PyEval_EvalCode + 0xae from python
 0x000056477d5537ba in <unknown> from python
 0x000056477d54ea9b in <unknown> from python
 0x000056477d5677b0 in <unknown> from python
 0x000056477d5672fe in _PyRun_SimpleFileObject + 0x1be from python
 0x000056477d566a44 in _PyRun_AnyFileObject + 0x44 from python
 0x000056477d55f1e2 in Py_RunMain + 0x2f2 from python
 0x000056477d517fa7 in Py_BytesMain + 0x37 from python
 0x00007f1d213277e5 in __libc_start_main + 0xe5 from /lib64/libc.so.6
 0x000056477d517e21 in <unknown> from python
 *** Break *** segmentation violation
 Generating stack trace...
 0x00007f18c39d205e in RooAbsCollection::insert(RooAbsArg*) + 0xae from /depot/cms/kernels/root632/lib/libRooFitCore.so.6.32.00
 0x00007f18c39d2418 in RooAbsCollection::add(RooAbsArg const&, bool) + 0x38 from /depot/cms/kernels/root632/lib/libRooFitCore.so.6.32.00
 0x00007f18c39990e5 in <unknown> from /depot/cms/kernels/root632/lib/libRooFitCore.so.6.32.00
 0x00007f18be71faa4 in <unknown function>
 0x00007f18be71f255 in <unknown function>
 0x00007f18be71f077 in <unknown function>
 0x00007f1d20a01bfe in <unknown> from /depot/cms/kernels/root632/lib/python3.12/lib-dynload/../../libcppyy_backend.so
 0x00007f1d20a026dc in Cppyy::CallConstructor(long, unsigned long, unsigned long, void*) + 0x2c from /depot/cms/kernels/root632/lib/python3.12/lib-dynload/../../libcppyy_backend.so
 0x00007f1d00203e2a in <unknown> from /depot/cms/kernels/root632/lib/python3.12/site-packages/libcppyy.so
 0x00007f1d00204196 in CPyCppyy::CPPMethod::Execute(void*, long, CPyCppyy::CallContext*) + 0x56 from /depot/cms/kernels/root632/lib/python3.12/site-packages/libcppyy.so
 0x00007f1d001f6594 in CPyCppyy::CPPConstructor::Call(CPyCppyy::CPPInstance*&, _object* const*, unsigned long, _object*, CPyCppyy::CallContext*) + 0x364 from /depot/cms/kernels/root632/lib/python3.12/site-packages/libcppyy.so
 0x00007f1d0020b963 in <unknown> from /depot/cms/kernels/root632/lib/python3.12/site-packages/libcppyy.so
 0x000056477d47780d in _PyObject_FastCallDictTstate + 0x2ed from python
 0x000056477d4a2c53 in <unknown> from python
 0x000056477d474d5c in _PyObject_MakeTpCall + 0x2bc from python
 0x000056477d37bf20 in <unknown> from python
 0x000056477d52f6fe in PyEval_EvalCode + 0xae from python
 0x000056477d5537ba in <unknown> from python
 0x000056477d54ea9b in <unknown> from python
 0x000056477d5677b0 in <unknown> from python
 0x000056477d5672fe in _PyRun_SimpleFileObject + 0x1be from python
 0x000056477d566a44 in _PyRun_AnyFileObject + 0x44 from python
 0x000056477d55f1e2 in Py_RunMain + 0x2f2 from python
 0x000056477d517fa7 in Py_BytesMain + 0x37 from python
 0x00007f1d213277e5 in __libc_start_main + 0xe5 from /lib64/libc.so.6
 0x000056477d517e21 in <unknown> from python

Is there something that I have missed? Thank you in advance!

amarini commented 3 months ago

Pay attention to the python-root interaction through the gc, and to the number of coefficients you put:

import ROOT as rt
import numpy as np
import awkward as ak

name ="coeff"

b1 = rt.RooRealVar(name + '_1',name, 0.25,0, 2.0)
b2 = rt.RooRealVar(name + '_2',name, 0.25,0, 2.0)
b3 = rt.RooRealVar(name + '_3',name, 0.25,0, 2.0)
BernCoeff_list = rt.RooArgList()
BernCoeff_list.add(b1)
BernCoeff_list.add(b2)
BernCoeff_list.add(b3)

mass_name = "dimuon_mass"
mass =  rt.RooRealVar(mass_name,mass_name,0.5,0.0,1.0)
# mass =  rt.RooRealVar(mass_name,mass_name,125,110,150)
mass.setBins(80)

# generate exp decay data
mass_arr = np.random.uniform(size=100)
mass_arr = np.exp(-100 * mass_arr)
roo_dataset = rt.RooDataSet.from_numpy({mass_name: mass_arr}, [mass])
roo_hist = rt.RooDataHist("data_hist","data_hist", rt.RooArgSet(mass), roo_dataset)

name = "bern model"

order = 3
bern_model =  rt.RooBernsteinFast(order)("pdf_bern_cat","bernstein",mass, BernCoeff_list)
rt.EnableImplicitMT()
bern_model.fitTo(roo_hist, EvalBackend="cpu", Save=True)