Skip to content

Commit

Permalink
peakfit: add 2D profile scan visualization and logging
Browse files Browse the repository at this point in the history
  • Loading branch information
mieskolainen committed Nov 3, 2024
1 parent c0c2a0a commit f7e9cf7
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 31 deletions.
20 changes: 11 additions & 9 deletions configs/peakfit/tune0.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,17 @@ techno:
minos: True # If True, Minuit MINOS uncertainties (slower but best), otherwise HESSE
migrad_first_step: 0.001 # First step size (relative percentage), set None for migrad heuristic

min_ndof: 1 # Minimum number of d.o.f required
max_chi2: 1200 # Maximum chi2/ndf for a succesful fit
min_count: 5 # Minimum number of total entries (sum of bin content) in the histogram
trials: 10 # Number of random restarts (all are executed and inspected, the best is kept)
rand_sigma: 0.5 # Random perturbation scale for initial values per trial
min_ndof: 1 # Minimum number of d.o.f required
max_chi2: 1200 # Maximum chi2/ndf for a succesful fit
min_count: 5 # Minimum number of total entries (sum of bin content) in the histogram
trials: 10 # Number of random restarts (all are executed and inspected, the best is kept)
rand_sigma: 0.5 # Random perturbation scale for initial values per trial

set_to_nan: True # Set parameters after the fit to NaN if not passing max_chi2 or min_count
set_to_nan: True # Set parameters after the fit to NaN if not passing max_chi2 or min_count

strategy: 2 # Default 1 (0 ~ fast, 1 ~ balanced, 2 ~ accurate)
tol: 0.1 # Default 0.1, https://iminuit.readthedocs.io/en/stable/reference.html#iminuit.Minuit.tol
strategy: 2 # Default 1 (0 ~ fast, 1 ~ balanced, 2 ~ accurate)
tol: 0.1 # Default 0.1, https://iminuit.readthedocs.io/en/stable/reference.html#iminuit.Minuit.tol

cov_eps: 0.0 # Covariance matrix post-regularization (added to diagonal) (set to 0 for none, can bias!)
cov_eps: 0.0 # Covariance matrix post-regularization (added to diagonal) (set to 0 for none, can bias!)

draw_mnmatrix: False # Draw MINOS profile likelihood scan 2D contours (very slow)
20 changes: 11 additions & 9 deletions configs/peakfit/tune2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,17 @@ techno:
minos: True # If True, Minuit MINOS uncertainties (slower but best), otherwise HESSE
migrad_first_step: 0.001 # First step size (relative percentage), set None for migrad heuristic

min_ndof: 1 # Minimum number of d.o.f required
max_chi2: 1200 # Maximum chi2/ndf for a succesful fit
min_count: 5 # Minimum number of total entries (sum of bin content) in the histogram
trials: 10 # Number of random restarts (all are executed and inspected, the best is kept)
rand_sigma: 0.5 # Random perturbation scale for initial values per trial
min_ndof: 1 # Minimum number of d.o.f required
max_chi2: 1200 # Maximum chi2/ndf for a succesful fit
min_count: 5 # Minimum number of total entries (sum of bin content) in the histogram
trials: 10 # Number of random restarts (all are executed and inspected, the best is kept)
rand_sigma: 0.5 # Random perturbation scale for initial values per trial

set_to_nan: True # Set parameters after the fit to NaN if not passing max_chi2 or min_count
set_to_nan: True # Set parameters after the fit to NaN if not passing max_chi2 or min_count

strategy: 2 # Default 1 (0 ~ fast, 1 ~ balanced, 2 ~ accurate)
tol: 0.1 # Default 0.1, https://iminuit.readthedocs.io/en/stable/reference.html#iminuit.Minuit.tol
strategy: 2 # Default 1 (0 ~ fast, 1 ~ balanced, 2 ~ accurate)
tol: 0.1 # Default 0.1, https://iminuit.readthedocs.io/en/stable/reference.html#iminuit.Minuit.tol

cov_eps: 0.0 # Covariance matrix post-regularization (added to diagonal) (set to 0 for none, can bias!)
cov_eps: 0.0 # Covariance matrix post-regularization (added to diagonal) (set to 0 for none, can bias!)

draw_mnmatrix: False # Draw MINOS profile likelihood scan 2D contours (very slow)
6 changes: 3 additions & 3 deletions icefit/icepeak.py
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,7 @@ def poiss_nll_loss(par):
cprint(f"[{param['fit_type']}] chi2 / ndf = {chi2:.2f} / {ndof} = {chi2/ndof:.2f} [{str}]", 'yellow')
print('')

return par, cov, var2pos
return par, cov, var2pos, best_m1

def generate_start_values(trial, param, techno):
"""
Expand Down Expand Up @@ -898,7 +898,7 @@ def analyze_1D_fit(hist, param: dict, techno: dict, fitfunc,
Returns:
output dictionary
"""
print(__name__ + f'.analyze_1D_fit:')
cprint(__name__ + f'.analyze_1D_fit:', 'magenta')

h = TH1_to_numpy(hist)
d = hist_decompose(h, param=param, techno=techno)
Expand Down Expand Up @@ -1071,7 +1071,7 @@ def analyze_1D_fit(hist, param: dict, techno: dict, fitfunc,
# chi2 / ndf
chi2_ndf = chi2 / ndof if ndof > 0 else -999
title = f"$\\chi^2 / n_\\mathrm{{dof}} = {chi2:.2f} / {ndof:0.0f} = {chi2_ndf:.2f}$"
print(f'plot title: {title}')
print(f"plot: {title.replace('$', '')} \n")
plt.title(title)

# ---------------------------------------------------------------
Expand Down
49 changes: 40 additions & 9 deletions icefit/peakfit.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,11 @@ def fit_task(f, inputparam, savepath, YEAR, GENTYPE):
fitfunc_ = {f'{key}': fitfunc}

# Fit and analyze
par,cov,var2pos = icepeak.binned_1D_fit(hist=hist_, param=param, fitfunc=fitfunc_,
par,cov,var2pos,m1 = icepeak.binned_1D_fit(hist=hist_, param=param, fitfunc=fitfunc_,
techno=techno, par_fixed=None)
output = icepeak.analyze_1D_fit(hist=hist, param=param, fitfunc=fitfunc,
techno=techno, par=par, cov=cov, par_fixed=None)

# Create savepath
total_savepath = f'{savepath}/Run{YEAR}/{GENTYPE}/{SYST}'
if not os.path.exists(total_savepath):
Expand All @@ -222,8 +222,23 @@ def fit_task(f, inputparam, savepath, YEAR, GENTYPE):

# Save the pull histogram
plt.figure(output['fig_pulls'])
plt.savefig(f'{total_savepath}/{tree}_pulls.pdf', bbox_inches='tight')
plt.savefig(f'{total_savepath}/{tree}_pulls.png', bbox_inches='tight', dpi=300)
plt.savefig(f'{total_savepath}/{tree}__pulls.pdf', bbox_inches='tight')
plt.savefig(f'{total_savepath}/{tree}__pulls.png', bbox_inches='tight', dpi=300)

# Save parameter outputs
with open(f'{total_savepath}/{tree}.log', "w") as file:
print(par, file=file)
print(m1.params, file=file)
print(cov, file=file)

# Draw MINOS contours
if techno['draw_mnmatrix']:
cprint('Draw MINOS profile likelihood scan 2D contours', 'yellow')

m1.draw_mnmatrix(figsize=(2.5*len(par), 2.5*len(par)))
plt.figure(plt.gcf())
plt.savefig(f'{total_savepath}/{tree}__mnmatrix.pdf', bbox_inches='tight')
plt.savefig(f'{total_savepath}/{tree}__mnmatrix.png', bbox_inches='tight', dpi=300)

# Save the fit numerical data
par_dict, cov_arr = icepeak.iminuit2python(par=par, cov=cov, var2pos=var2pos)
Expand Down Expand Up @@ -280,11 +295,11 @@ def fit_task_multi(f, inputparam, savepath, YEAR, GENTYPE):
# --------------------------------------------------------------------

# Simultaneous fit of both
par,cov,var2pos = icepeak.binned_1D_fit(hist=hist, param=param, fitfunc=fitfunc,
par,cov,var2pos,m1 = icepeak.binned_1D_fit(hist=hist, param=param, fitfunc=fitfunc,
techno=techno, par_fixed=par_fixed)

# Analyze and plot Pass, Fail seperately
for key in f.keys():
for idx, key in enumerate(f.keys()):

output = icepeak.analyze_1D_fit(hist=hist[key], param=param, fitfunc=fitfunc[key],
techno=techno, par=par, cov=cov, par_fixed=par_fixed)
Expand All @@ -297,15 +312,31 @@ def fit_task_multi(f, inputparam, savepath, YEAR, GENTYPE):
if not os.path.exists(total_savepath):
os.makedirs(total_savepath)

# Save the fit plot
# Save the fit plot
plt.figure(output['fig'])
plt.savefig(f'{total_savepath}/{tree}.pdf', bbox_inches='tight')
plt.savefig(f'{total_savepath}/{tree}.png', bbox_inches='tight', dpi=300)

# Save the pull histogram
plt.figure(output['fig_pulls'])
plt.savefig(f'{total_savepath}/{tree}_pulls.pdf', bbox_inches='tight')
plt.savefig(f'{total_savepath}/{tree}_pulls.png', bbox_inches='tight', dpi=300)
plt.savefig(f'{total_savepath}/{tree}__pulls.pdf', bbox_inches='tight')
plt.savefig(f'{total_savepath}/{tree}__pulls.png', bbox_inches='tight', dpi=300)

# Save parameter outputs
if (idx == 0):
with open(f'{total_savepath}/{tree}.log', "w") as file:
print(par, file=file)
print(m1.params, file=file)
print(cov, file=file)

# Draw MINOS contours
if techno['draw_mnmatrix'] and (idx == 0):
cprint('Draw MINOS profile likelihood scan 2D contours', 'yellow')

m1.draw_mnmatrix(figsize=(2.5*len(par), 2.5*len(par)))
plt.figure(plt.gcf())
plt.savefig(f'{total_savepath}/{tree}__mnmatrix.pdf', bbox_inches='tight')
plt.savefig(f'{total_savepath}/{tree}__mnmatrix.png', bbox_inches='tight', dpi=300)

# Save the fit numerical data
par_dict, cov_arr = icepeak.iminuit2python(par=par, cov=cov, var2pos=var2pos)
Expand Down
2 changes: 1 addition & 1 deletion requirements-aux.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jax==0.4.28
jaxlib==0.4.28

# IMINUIT
iminuit==2.25.2
iminuit==2.30.1

# MYSTIC
mystic==0.4.2
Expand Down

0 comments on commit f7e9cf7

Please sign in to comment.