# Fitting with cruijff function

import ROOT
import numpy as np

# Crystal Ball function for PDF

def pdf(x, para):
A, mean, sigmaL, alphaL, sigmaR, alphaR = para

x = np.asarray(x)
if x.ndim == 0:
x = np.array([x])

left = x < mean
right = np.logical_not(left)

top = np.square(x - mean)

bottomL = 2 * (sigmaL * sigmaL + alphaL * top[left])
bottomR = 2 * (sigmaR * sigmaR + alphaR * top[right])

answer[left] = A * np.exp(-np.divide(top[left], bottomL))
answer[right] = A * np.exp(-np.divide(top[right], bottomR))

# Function to guess initial parameters

def popt_guesses(bin_centers, bin_heights, prev_guess):
mean_guess = bin_centers[np.argmax(bin_heights)]
sigma_guess = np.sqrt(np.average((bin_centers - mean_guess) ** 2, weights=bin_heights))
sigmaL_guess = sigma_guess
sigmaR_guess = sigma_guess
if prev_guess is None:
alphaL_guess = 0.07 # Adjusted from 7e-2 to 0.07
alphaR_guess = 0.07
else:
alphaL_guess = prev_guess[3]
alphaR_guess = prev_guess[5]

A_guess = np.max(bin_heights) / pdf(0, [1, mean_guess, sigmaL_guess, alphaL_guess, sigmaR_guess, alphaR_guess])
p0 = [A_guess[0], mean_guess, sigmaL_guess, alphaL_guess, sigmaR_guess, alphaR_guess]
return p0

# Function to fit histograms

def fit_histograms(input_file_name, output_file_name, output_txt_file):
# Open the input ROOT file
if input_file.IsZombie():
print(f"Error: Could not open the input file {input_file_name}")
return

# Create a canvas for drawing
canvas = ROOT.TCanvas("canvas", "canvas", 800, 600)

# Prepare the output text file
with open(output_txt_file, 'w') as txt_file:
txt_file.write("bin_low bin_high mean sigma mean_error sigma_error\n")

# Get list of keys in the input file
keys = input_file.GetListOfKeys()

# Loop over all keys in the file
for key in keys:
# Check if the object is a histogram and has the expected name format
if isinstance(obj, ROOT.TH1) and obj.GetName().startswith("response_"):
# Extract bin centers and heights
bin_centers = np.array([obj.GetBinCenter(i) for i in range(1, obj.GetNbinsX() + 1)])
bin_heights = np.array([obj.GetBinContent(i) for i in range(1, obj.GetNbinsX() + 1)])
p0 = popt_guesses(bin_centers, bin_heights, None)

# Create a TF1 object for fitting
fit_func = ROOT.TF1("fit_func", pdf, bin_centers[0], bin_centers[-1], len(p0))
for i, p in enumerate(p0):
fit_func.SetParameter(i, p)

# Perform the fit
fit_result = obj.Fit("fit_func", "S")

# Extract the fitted parameters and their errors
popt = [fit_func.GetParameter(i) for i in range(len(p0))]
perr = [fit_func.GetParError(i) for i in range(len(p0))]

# Extract bin range from histogram name
name_parts = obj.GetName().split('_')
bin_low = float(name_parts[1])
bin_high = float(name_parts[2])

# Write the results to the text file
txt_file.write(f"{bin_low} {bin_high} {popt[1]} {popt[2]} {perr[1]} {perr[2]}\n")

# Write the histogram to the output ROOT file
output_file.cd()
obj.Write()

# Draw the histogram and fit result on the canvas
obj.Draw()
fit_func.Draw("same")

# Save the canvas as an image file
image_file_name = f"{obj.GetName()}.png"
canvas.SaveAs(image_file_name)

# Close the input and output ROOT files
input_file.Close()
output_file.Close()

if name == “main”:
import sys

if len(sys.argv) != 4:
print("Usage: python fit_histograms.py <input_file> <output_file> <output_txt_file>")
sys.exit(1)

input_file_name = sys.argv[1]
output_file_name = sys.argv[2]
output_txt_file = sys.argv[3]

# Create the output ROOT file
output_file = ROOT.TFile(output_file_name, "RECREATE")
if output_file.IsZombie():
print(f"Error: Could not create the output file {output_file_name}")
sys.exit(1)

fit_histograms(input_file_name, output_file_name, output_txt_file)
print(f"Results written to {output_txt_file}")

this is the error

Traceback (most recent call last):
File “/Users/gursharansingh/Desktop/project/fit_with_cruijff.py”, line 128, in
fit_histograms(input_file_name, output_file_name, output_txt_file)
File “/Users/gursharansingh/Desktop/project/fit_with_cruijff.py”, line 80, in fit_histograms
fit_result = obj.Fit(“fit_func”, “S”)
^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: none of the 2 overloaded methods succeeded. Full details:
TFitResultPtr TH1::Fit(TF1* f1, const char* option = “”, const char* goption = “”, double xmin = 0, double xmax = 0) =>
TypeError: could not convert argument 1
TFitResultPtr TH1::Fit(const char* formula, const char* option = “”, const char* goption = “”, double xmin = 0, double xmax = 0) =>
AbortSignal: abort from C++; program state was reset
(myrootwork) gursharansingh@Gursharans-MacBook-Air project % python3 fit_with_cruijff.py response_histograms.root hello.root hello.txt
Traceback (most recent call last):
File “/Users/gursharansingh/Desktop/project/fit_with_cruijff.py”, line 128, in
fit_histograms(input_file_name, output_file_name, output_txt_file)
File “/Users/gursharansingh/Desktop/project/fit_with_cruijff.py”, line 75, in fit_histograms
fit_func = ROOT.TF1(“fit_func”, pdf(), bin_centers[0], bin_centers[-1], len(p0))
^^^^^
TypeError: pdf() missing 2 required positional arguments: ‘x’ and ‘para’

Hi,

Could you please propose a minimal reproducer in a well formatted post?

Thanks!
Best,
D

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.