
import ROOT, math

m1 = m2 = 0.983 # protons

# range
mleft = m1 + m2
mright = m1 + m2 + 0.3

# create a function
def my_function(x, par):
   # mass variable
    xx = x[0]

    ## polynome parameters
    a1 = par[0]
    a2 = par[1]
    a3 = par[2]

    ## phase space numerator: sqrt of triangle function
    numr = math.pi*math.sqrt(xx**4+m1**4+m2**4 - 2.*xx*xx*m1*m1 - 2.*m1*m1*m2*m2 - 2*m2*m2*xx*xx)

    ## phase space denominator
    denr = 2*xx*xx

    ## second order polynome
    pol2 = a1*xx*xx + a2*xx + a3

    ## return
    return (pol2*numr/denr)

## name, function, left limit, right limit, number of parameters
f_ps_pol2 = ROOT.TF1("f_ps_pol2", my_function, mleft, mright, 3)

## turn into RooFit
# mass var
m_x  = ROOT.RooRealVar("m_x", "m_x", mleft, mright)

## 2nd order polynome coefficients with random values
a1 = ROOT.RooRealVar("a1" , "a1" , 3, -100, 100)
a2 = ROOT.RooRealVar("a2" , "a2" , 4, -100, 100)
a3 = ROOT.RooRealVar("a3" , "a3" , 5, -100, 100)
pars = ROOT.RooArgSet(a1, a2, a3)

roo_ps_func = ROOT.RooFit.bindFunction(f_ps_pol2, m_x, pars)
roo_ps_pdf1 = ROOT.RooFit.bindPdf("roo_ps_pdf1",f_ps_pol2, m_x, a1, a2, a3)
roo_ps_pdf2 = ROOT.RooFit.bindPdf(f_ps_pol2, m_x)

## get dataset and try to fit
fil = ROOT.TFile('ds_bkg.root')
ds = fil.Get('background')

## bound as a function
roo_ps_func.fitTo(ds)

## leads to an error
"""
 AttributeError: 'RooTFnBinding' object has no attribute 'fitTo'
"""

# bound as a pdf
roo_ps_pdf1.fitTo(ds)

## leads to an error
"""
File /snap/root-framework/954/usr/local/lib/ROOT/_pythonization/_roofit/_rooabspdf.py:64, in RooAbsPdf.fitTo(self, *args, **kwargs)
    60 The RooAbsPdf::fitTo() function is pythonized with the command argument pythonization.
    61 The keywords must correspond to the CmdArgs of the function.
    62 
    63 # Redefinition of `RooAbsPdf.fitTo` for keyword arguments.
--> 64 return self._fitTo["RooLinkedList const&"](args[0], _pack_cmd_args(*args[1:], **kwargs))

TypeError: Could not find "fitTo<RooLinkedList const&>" (set cppyy.set_debug() for C++ errors):
  Template method resolution failed:
  math domain error
  math domain error
  Failed to instantiate "operator()(double,double,double,double)"
"""

## other way of binding pdf
roo_ps_pdf2.fitTo(ds)

## does not seem to see the parameters:
"""
[#1] INFO:Fitting -- RooAbsPdf::fitTo(f_ps_pol2_over_f_ps_pol2_Int[m_x]) fixing normalization set for coefficient determination to observables in data
[#1] INFO:Fitting -- Creation of NLL object took 9.0357 ms
[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_f_ps_pol2_over_f_ps_pol2_Int[m_x]_background) Summation contains a RooNLLVar, using its error level
[#1] INFO:Minimization -- RooAbsMinimizerFcn::setOptimizeConst: activating const optimization
[#0] ERROR:Minimization -- RooMinimizer::fitFCN(): FCN function has zero parameters
[#0] ERROR:Minimization -- RooMinimizer: all function calls during minimization gave invalid NLL values!
[#0] WARNING:Minimization -- RooMinimizer::hesse: Error, run Migrad before Hesse!
[#1] INFO:Minimization -- RooAbsMinimizerFcn::setOptimizeConst: deactivating const optimization
"""
