Skip to content
Merged
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
54 changes: 24 additions & 30 deletions bindings/pyroot/pythonizations/test/tf_pycallables.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
Cppyy that creates a C++ wrapper to invoke the Python callable.
"""

import unittest
import math
import unittest

import ROOT

Expand All @@ -23,14 +23,17 @@ class pyf_tf1_callable:
def __call__(self, x, p):
return p[0] * x[0] + p[1]


def pyf_func(x, pars):
return pars[0] * x[0] * x[2] + x[1] * pars[1]


def pyf_tf1_gauss(x, p):
return p[0] * 1.0 / math.sqrt(2.0 * math.pi * p[2]**2) * math.exp(-(x[0] - p[1])**2 / 2.0 / p[2]**2)
return p[0] * 1.0 / math.sqrt(2.0 * math.pi * p[2] ** 2) * math.exp(-((x[0] - p[1]) ** 2) / 2.0 / p[2] ** 2)


def pyf_tf1_coulomb(x, p):
return p[1] * x[0] * x[1] / (p[0]**2) * math.exp(-p[2] / p[0])
return p[1] * x[0] * x[1] / (p[0] ** 2) * math.exp(-p[2] / p[0])


class TF1(unittest.TestCase):
Expand Down Expand Up @@ -73,24 +76,23 @@ def test_callable(self):
for x in [0.0, -1.0, 42.0]:
self.assertEqual(f.Eval(x), pycallable([x], [par1, par2]))


def test_fitgauss(self):
"""
Test fitting a histogram to a Python function
"""
# Gaus function
f = ROOT.TF1("tf1_fitgauss", pyf_tf1_gauss, -4, 4, 3)
f.SetParameter(0, 10.0) # scale
f.SetParameter(1, -1.0) # mean
f.SetParameter(2, 2.0) # standard deviation
f.SetParameter(0, 10.0) # scale
f.SetParameter(1, -1.0) # mean
f.SetParameter(2, 2.0) # standard deviation

# Sample gauss in histogram
h = ROOT.TH1F("h", "test", 100, -4, 4)
h.FillRandom("gaus", 100000)
h.Scale(1.0 / 100000.0 * 100.0 / 8.0) # Normalize as density
h.Scale(1.0 / 100000.0 * 100.0 / 8.0) # Normalize as density

# Fit to histogram and get parameters
h.Fit( f, "0Q" )
h.Fit(f, "0Q")
scale = f.GetParameter(0)
mean = f.GetParameter(1)
std = f.GetParameter(2)
Expand All @@ -108,27 +110,23 @@ def test_evalpar(self):
rtf1_coulomb = ROOT.TF1("my_func", pyf_tf1_coulomb, -10, 10)

# x dataset: 5 pairs of particle charges
x = np.array([
[1.0, 10, 2.0],
[1.5, 10, 2.5],
[2.0, 10, 3.0],
[2.5, 10, 3.5],
[3.0, 10, 4.0]
])

params = np.array([
[1.0], # Distance between charges r
[8.99e9], # Coulomb constant k (in N·m²/C²)
[0.1] # Additional factor for modulation
])
x = np.array([[1.0, 10, 2.0], [1.5, 10, 2.5], [2.0, 10, 3.0], [2.5, 10, 3.5], [3.0, 10, 4.0]])

params = np.array(
[
1.0, # Distance between charges r
8.99e9, # Coulomb constant k (in N·m²/C²)
0.1, # Additional factor for modulation
]
)

# Slice to avoid the dummy column of 10's
res = rtf1_coulomb.EvalPar(x[:, ::2], params)

for i in range(len(x)):
expected_value = pyf_tf1_coulomb(x[i, ::2], params)
self.assertEqual(res[i], expected_value)

def test_evalpar_dynamic(self):
"""
Test the 2D NumPy pythonizations with dynamic TF1 data dimensions
Expand All @@ -139,12 +137,9 @@ def test_evalpar_dynamic(self):
rtf1_func = ROOT.TF1("my_func", pyf_func, -10, 10)

# x dataset with ndims 3
x = np.array([[2., 2, 1],
[1., 2, 3],
[2., 2, 1],
[4., 3, 2]])
x = np.array([[2.0, 2, 1], [1.0, 2, 3], [2.0, 2, 1], [4.0, 3, 2]])

pars = np.array([2., 3.])
pars = np.array([2.0, 3.0])
res = rtf1_func.EvalPar(x, pars)

for i in range(len(x)):
Expand Down Expand Up @@ -204,6 +199,5 @@ def test_params(self):
self.assertEqual(f.Eval(*x), pyf_tf2_params(x, [par1, par2, par3, par4]))


if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

Loading