From 036ed78243dabd2c677a585e3f71940b9f31d969 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Fri, 29 May 2026 18:00:30 +0200 Subject: [PATCH 01/13] fix Megalinter error Multiple statements on one line (colon) --- PWGHF/D2H/Macros/compute_fraction_cutvar.py | 39 ++++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/PWGHF/D2H/Macros/compute_fraction_cutvar.py b/PWGHF/D2H/Macros/compute_fraction_cutvar.py index 0e5ced6f8a5..0d6e8e12314 100644 --- a/PWGHF/D2H/Macros/compute_fraction_cutvar.py +++ b/PWGHF/D2H/Macros/compute_fraction_cutvar.py @@ -205,14 +205,16 @@ def main(config): ) pt_bin_to_process_name_suffix = "" - if pt_bin_to_process != -1: pt_bin_to_process_name_suffix = "_bin_" + str(pt_bin_to_process) + if pt_bin_to_process != -1: + pt_bin_to_process_name_suffix = "_bin_" + str(pt_bin_to_process) output_name_template = cfg['output']['file'].replace(".root", "") + pt_bin_to_process_name_suffix + ".root" output = ROOT.TFile(os.path.join(cfg["output"]["directory"], output_name_template), "recreate") n_sets = len(hist_rawy) pt_axis_title = hist_rawy[0].GetXaxis().GetTitle() for ipt in range(hist_rawy[0].GetNbinsX()): - if pt_bin_to_process !=-1 and ipt+1 != pt_bin_to_process: continue + if pt_bin_to_process !=-1 and ipt+1 != pt_bin_to_process: + continue all_vectors_monotonous = MinimisationStatus.Success pt_min = hist_rawy[0].GetXaxis().GetBinLowEdge(ipt + 1) pt_max = hist_rawy[0].GetXaxis().GetBinUpEdge(ipt + 1) @@ -280,45 +282,56 @@ def main(config): hist_bin_title_rawy = hist_bin_title if is_draw_title[PlotType.Rawy] else "" canv_rawy, histos_rawy, leg_r = minimiser.plot_result(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_rawy) output.cd() - if is_save_to_root_file[ObjectToSave.Canvas]: canv_rawy.Write() + if is_save_to_root_file[ObjectToSave.Canvas]: + canv_rawy.Write() if is_save_to_root_file[ObjectToSave.RawYield]: for _, hist in histos_rawy.items(): hist.Write() - if is_save_canvas_as_macro[PlotType.Rawy]: canv_rawy.SaveAs(f"canv_rawy_{ipt+1}.C") + if is_save_canvas_as_macro[PlotType.Rawy]: + canv_rawy.SaveAs(f"canv_rawy_{ipt+1}.C") hist_bin_title_unc = hist_bin_title if is_draw_title[PlotType.Unc] else "" canv_unc, histos_unc, leg_unc = minimiser.plot_uncertainties(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_unc) output.cd() - if is_save_to_root_file[ObjectToSave.Canvas]: canv_unc.Write() + if is_save_to_root_file[ObjectToSave.Canvas]: + canv_unc.Write() if is_save_to_root_file[ObjectToSave.Uncertainty]: for _, hist in histos_unc.items(): hist.Write() - if is_save_canvas_as_macro[PlotType.Unc]: canv_unc.SaveAs(f"canv_unc_{ipt+1}.C") + if is_save_canvas_as_macro[PlotType.Unc]: + canv_unc.SaveAs(f"canv_unc_{ipt+1}.C") hist_bin_title_eff = hist_bin_title if is_draw_title[PlotType.Eff] else "" canv_eff, histos_eff, leg_e = minimiser.plot_efficiencies(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_eff) output.cd() - if is_save_to_root_file[ObjectToSave.Canvas]: canv_eff.Write() + if is_save_to_root_file[ObjectToSave.Canvas]: + canv_eff.Write() if is_save_to_root_file[ObjectToSave.Efficiency]: for _, hist in histos_eff.items(): hist.Write() - if is_save_canvas_as_macro[PlotType.Eff]: canv_eff.SaveAs(f"canv_eff_{ipt+1}.C") + if is_save_canvas_as_macro[PlotType.Eff]: + canv_eff.SaveAs(f"canv_eff_{ipt+1}.C") hist_bin_title_frac = hist_bin_title if is_draw_title[PlotType.Frac] else "" canv_frac, histos_frac, leg_f = minimiser.plot_fractions(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_frac) output.cd() - if is_save_to_root_file[ObjectToSave.Canvas]: canv_frac.Write() + if is_save_to_root_file[ObjectToSave.Canvas]: + canv_frac.Write() if is_save_to_root_file[ObjectToSave.Fraction]: for _, hist in histos_frac.items(): hist.Write() - if is_save_canvas_as_macro[PlotType.Frac]: canv_frac.SaveAs(f"canv_frac_{ipt+1}.C") + if is_save_canvas_as_macro[PlotType.Frac]: + canv_frac.SaveAs(f"canv_frac_{ipt+1}.C") hist_bin_title_cov = hist_bin_title if is_draw_title[PlotType.Cov] else "" canv_cov, histo_cov = minimiser.plot_cov_matrix(True, f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_cov) output.cd() - if is_save_to_root_file[ObjectToSave.Canvas]: canv_cov.Write() - if is_save_to_root_file[ObjectToSave.CorrelationMatrix]: histo_cov.Write() - if is_save_canvas_as_macro[PlotType.Cov]: canv_cov.SaveAs(f"canv_cov_{ipt+1}.C") + if is_save_to_root_file[ObjectToSave.Canvas]: + canv_cov.Write() + if is_save_to_root_file[ObjectToSave.CorrelationMatrix]: + histo_cov.Write() + if is_save_canvas_as_macro[PlotType.Cov]: + canv_cov.SaveAs(f"canv_cov_{ipt+1}.C") else: print(f"Minimization for pT {pt_min}, {pt_max} not successful") hist_minimisation_status.SetBinContent(ipt + 1, MinimisationStatus.Fail) From 5905005f0d3053ddd858329bd7e1b4eee6b19fcd Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Fri, 29 May 2026 18:14:58 +0200 Subject: [PATCH 02/13] right-align plots' titles --- PWGHF/D2H/Macros/cut_variation.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/PWGHF/D2H/Macros/cut_variation.py b/PWGHF/D2H/Macros/cut_variation.py index 6d45ac25607..cea61ee4882 100644 --- a/PWGHF/D2H/Macros/cut_variation.py +++ b/PWGHF/D2H/Macros/cut_variation.py @@ -580,7 +580,8 @@ def plot_result(self, suffix="", title=""): hist_raw_yield_sum.Draw("histsame") tex = ROOT.TLatex() tex.SetTextSize(0.04) - tex.DrawLatexNDC(0.05, 0.95, title) + tex.SetTextAlign(31) + tex.DrawLatexNDC(0.95, 0.95, title) canvas.Modified() canvas.Update() @@ -651,7 +652,8 @@ def plot_cov_matrix(self, correlated=True, suffix="", title=""): hist_corr_matrix.Draw("colz") tex = ROOT.TLatex() tex.SetTextSize(0.04) - tex.DrawLatexNDC(0.05, 0.95, title) + tex.SetTextAlign(31) + tex.DrawLatexNDC(0.95, 0.95, title) canvas.Modified() canvas.Update() @@ -743,7 +745,8 @@ def plot_efficiencies(self, suffix="", title=""): leg.Draw() tex = ROOT.TLatex() tex.SetTextSize(0.04) - tex.DrawLatexNDC(0.05, 0.95, title) + tex.SetTextAlign(31) + tex.DrawLatexNDC(0.95, 0.95, title) canvas.Modified() canvas.Update() @@ -828,7 +831,8 @@ def plot_fractions(self, suffix="", title=""): leg.Draw() tex = ROOT.TLatex() tex.SetTextSize(0.04) - tex.DrawLatexNDC(0.05, 0.95, title) + tex.SetTextAlign(31) + tex.DrawLatexNDC(0.95, 0.95, title) canvas.Modified() canvas.Update() @@ -905,7 +909,8 @@ def plot_uncertainties(self, suffix="", title=""): hist_residual_unc.Draw("histsame") tex = ROOT.TLatex() tex.SetTextSize(0.04) - tex.DrawLatexNDC(0.05, 0.95, title) + tex.SetTextAlign(31) + tex.DrawLatexNDC(0.95, 0.95, title) canvas.Modified() canvas.Update() From 8dbeac01fcc5fa7ca2b2aa8203656c6c3442d716 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Wed, 2 Sep 2026 21:26:52 +0200 Subject: [PATCH 03/13] add plot_relative_uncertainties() --- PWGHF/D2H/Macros/cut_variation.py | 94 +++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/PWGHF/D2H/Macros/cut_variation.py b/PWGHF/D2H/Macros/cut_variation.py index cea61ee4882..c8bc4027907 100644 --- a/PWGHF/D2H/Macros/cut_variation.py +++ b/PWGHF/D2H/Macros/cut_variation.py @@ -920,3 +920,97 @@ def plot_uncertainties(self, suffix="", title=""): } return canvas, histos, leg + + + # pylint: disable=no-member + def plot_relative_uncertainties(self, suffix="", title=""): + """ + Helper function to plot uncertainties as a function of cut set + + Parameters + ----------------------------------------------------- + - suffix: str + suffix to be added in the name of the output objects + - title: str + title to be written at the top margin of the output objects + + Returns + ----------------------------------------------------- + - canvas: ROOT.TCanvas + canvas with plot + - histos: dict + dictionary of ROOT.TH1F with relative uncertainties distributions + for raw yield and efficiencies + - leg: ROOT.TLegend + needed otherwise it is destroyed + """ + suffix = suffix.replace(".", "_") + + set_global_style(padleftmargin=0.16, padbottommargin=0.12, padtopmargin=0.075, titleoffsety=1.6) + + hist_raw_yield_rel_unc = ROOT.TH1F( + f"hRawYieldRelUncVsCut{suffix}", + ";cut set;relative unc.", + self.n_sets, + -0.5, + self.n_sets - 0.5, + ) + + hist_eff_prompt_rel_unc = ROOT.TH1F( + f"hEffPromptRelUncVsCut{suffix}", + ";cut set;relative unc.", + self.n_sets, + -0.5, + self.n_sets - 0.5, + ) + + hist_eff_nonprompt_rel_unc = ROOT.TH1F( + f"hEffNonPromptRelUncVsCut{suffix}", + ";cut set;relative unc.", + self.n_sets, + -0.5, + self.n_sets - 0.5, + ) + + for i_bin, (unc_rawy, rawy, unc_eff_prompt, eff_prompt, unc_eff_nonprompt, eff_nonprompt) in enumerate(zip(self.unc_raw_yields, self.raw_yields, self.unc_eff_prompts, self.eff_prompts, self.unc_eff_nonprompts, self.eff_nonprompts)): + hist_raw_yield_rel_unc.SetBinContent(i_bin + 1, unc_rawy / rawy) + hist_eff_prompt_rel_unc.SetBinContent(i_bin+1, unc_eff_prompt / eff_prompt) + hist_eff_nonprompt_rel_unc.SetBinContent(i_bin+1, unc_eff_nonprompt / eff_nonprompt) + + set_object_style(hist_raw_yield_rel_unc, color=ROOT.kBlack, fillstyle=0) + set_object_style(hist_eff_prompt_rel_unc, color=ROOT.kRed + 1, fillstyle=0) + set_object_style(hist_eff_nonprompt_rel_unc, color=ROOT.kAzure + 4, fillstyle=0) + + canvas = ROOT.TCanvas(f"cRelUncVsCut{suffix}", "", 500, 500) + canvas.DrawFrame( + -0.5, + 0.0, + self.n_sets - 0.5, + hist_raw_yield_rel_unc.GetMaximum() * 1.2, + ";cut set;relative unc.", + ) + leg = ROOT.TLegend(0.6, 0.75, 0.8, 0.85) + leg.SetBorderSize(0) + leg.SetFillStyle(0) + leg.SetTextSize(0.04) + leg.AddEntry(hist_raw_yield_rel_unc, "raw yield", "l") + leg.AddEntry(hist_eff_prompt_rel_unc, "efficiency prompt", "l") + leg.AddEntry(hist_eff_nonprompt_rel_unc, "efficiency nonprompt", "l") + leg.Draw() + hist_raw_yield_rel_unc.Draw("histsame") + hist_eff_prompt_rel_unc.Draw("histsame") + hist_eff_nonprompt_rel_unc.Draw("histsame") + tex = ROOT.TLatex() + tex.SetTextSize(0.04) + tex.SetTextAlign(31) + tex.DrawLatexNDC(0.95, 0.95, title) + canvas.Modified() + canvas.Update() + + histos = { + "rawy": hist_raw_yield_rel_unc, + "prompt": hist_eff_prompt_rel_unc, + "nonprompt": hist_eff_nonprompt_rel_unc + } + + return canvas, histos, leg From 411106e07d49e9df199b65bd02dbda6ace6e1e18 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Wed, 2 Sep 2026 21:50:41 +0200 Subject: [PATCH 04/13] plot_relative_uncertainties(): fix typo, improve plotting --- PWGHF/D2H/Macros/cut_variation.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PWGHF/D2H/Macros/cut_variation.py b/PWGHF/D2H/Macros/cut_variation.py index c8bc4027907..da60f44a19e 100644 --- a/PWGHF/D2H/Macros/cut_variation.py +++ b/PWGHF/D2H/Macros/cut_variation.py @@ -972,7 +972,7 @@ def plot_relative_uncertainties(self, suffix="", title=""): self.n_sets - 0.5, ) - for i_bin, (unc_rawy, rawy, unc_eff_prompt, eff_prompt, unc_eff_nonprompt, eff_nonprompt) in enumerate(zip(self.unc_raw_yields, self.raw_yields, self.unc_eff_prompts, self.eff_prompts, self.unc_eff_nonprompts, self.eff_nonprompts)): + for i_bin, (unc_rawy, rawy, unc_eff_prompt, eff_prompt, unc_eff_nonprompt, eff_nonprompt) in enumerate(zip(self.unc_raw_yields, self.raw_yields, self.unc_eff_prompt, self.eff_prompt, self.unc_eff_nonprompt, self.eff_nonprompt)): hist_raw_yield_rel_unc.SetBinContent(i_bin + 1, unc_rawy / rawy) hist_eff_prompt_rel_unc.SetBinContent(i_bin+1, unc_eff_prompt / eff_prompt) hist_eff_nonprompt_rel_unc.SetBinContent(i_bin+1, unc_eff_nonprompt / eff_nonprompt) @@ -986,10 +986,10 @@ def plot_relative_uncertainties(self, suffix="", title=""): -0.5, 0.0, self.n_sets - 0.5, - hist_raw_yield_rel_unc.GetMaximum() * 1.2, + max(hist_raw_yield_rel_unc.GetMaximum(), hist_eff_prompt_rel_unc.GetMaximum(), hist_eff_nonprompt_rel_unc.GetMaximum()) * 1.2, ";cut set;relative unc.", ) - leg = ROOT.TLegend(0.6, 0.75, 0.8, 0.85) + leg = ROOT.TLegend(0.2, 0.75, 0.4, 0.85) leg.SetBorderSize(0) leg.SetFillStyle(0) leg.SetTextSize(0.04) From 58c8cbd153b650c71642afd559a6cfcf1562e315 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Wed, 2 Sep 2026 21:51:40 +0200 Subject: [PATCH 05/13] use plot_relative_uncertainties() --- PWGHF/D2H/Macros/compute_fraction_cutvar.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/PWGHF/D2H/Macros/compute_fraction_cutvar.py b/PWGHF/D2H/Macros/compute_fraction_cutvar.py index 0d6e8e12314..72af071ecb3 100644 --- a/PWGHF/D2H/Macros/compute_fraction_cutvar.py +++ b/PWGHF/D2H/Macros/compute_fraction_cutvar.py @@ -28,6 +28,7 @@ class PlotType(IntEnum): Frac = auto() Cov = auto() Unc = auto() + RelUnc = auto() N = auto() class ObjectToSave(IntEnum): @@ -89,6 +90,7 @@ def main(config): is_draw_title[PlotType.Frac] = cfg.get("is_draw_title", {}).get("frac", False) is_draw_title[PlotType.Cov] = cfg.get("is_draw_title", {}).get("cov", False) is_draw_title[PlotType.Unc] = cfg.get("is_draw_title", {}).get("unc", True) + is_draw_title[PlotType.RelUnc] = cfg.get("is_draw_title", {}).get("relunc", True) is_save_canvas_as_macro = [False] * PlotType.N is_save_canvas_as_macro[PlotType.Rawy] = cfg.get("is_save_canvas_as_macro", {}).get("rawy", False) @@ -96,6 +98,7 @@ def main(config): is_save_canvas_as_macro[PlotType.Frac] = cfg.get("is_save_canvas_as_macro", {}).get("frac", False) is_save_canvas_as_macro[PlotType.Cov] = cfg.get("is_save_canvas_as_macro", {}).get("cov", False) is_save_canvas_as_macro[PlotType.Unc] = cfg.get("is_save_canvas_as_macro", {}).get("unc", False) + is_save_canvas_as_macro[PlotType.RelUnc] = cfg.get("is_save_canvas_as_macro", {}).get("relunc", False) is_save_to_root_file = [False] * ObjectToSave.N is_save_to_root_file[ObjectToSave.Canvas] = cfg.get("is_save_to_root_file", {}).get("canvas", True) @@ -301,6 +304,17 @@ def main(config): if is_save_canvas_as_macro[PlotType.Unc]: canv_unc.SaveAs(f"canv_unc_{ipt+1}.C") + hist_bin_title_rel_unc = hist_bin_title if is_draw_title[PlotType.RelUnc] else "" + canv_rel_unc, histos_rel_unc, leg_rel_unc = minimiser.plot_relative_uncertainties(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_rel_unc) + output.cd() + if is_save_to_root_file[ObjectToSave.Canvas]: + canv_rel_unc.Write() + if is_save_to_root_file[ObjectToSave.Uncertainty]: + for _, hist in histos_rel_unc.items(): + hist.Write() + if is_save_canvas_as_macro[PlotType.RelUnc]: + canv_rel_unc.SaveAs(f"canv_rel_unc_{ipt+1}.C") + hist_bin_title_eff = hist_bin_title if is_draw_title[PlotType.Eff] else "" canv_eff, histos_eff, leg_e = minimiser.plot_efficiencies(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_eff) output.cd() @@ -340,6 +354,7 @@ def main(config): canv_frac = ROOT.TCanvas("c_frac_minimization_error", "Minimization error", 500, 500) canv_cov = ROOT.TCanvas("c_conv_minimization_error", "Minimization error", 500, 500) canv_unc = ROOT.TCanvas("c_unc_minimization_error", "Minimization error", 500, 500) + canv_rel_unc = ROOT.TCanvas("c_rel_unc_minimization_error", "Minimization error", 500, 500) canv_combined = ROOT.TCanvas(f"canv_combined_{ipt}", "", 1000, 1000) canv_combined.Divide(2, 2) @@ -359,6 +374,7 @@ def main(config): output_name_frac_pdf = f"Frac_{output_name_template}" output_name_covmat_pdf = f"CovMatrix_{output_name_template}" output_name_unc_pdf = f"Unc_{output_name_template}" + output_name_rel_unc_pdf = f"RelUnc_{output_name_template}" output_name_pdf = f"{output_name_template}" if hist_rawy[0].GetNbinsX() == 1 or pt_bin_to_process != -1: @@ -375,6 +391,7 @@ def main(config): canv_cov.Print(f"{os.path.join(cfg['output']['directory'], output_name_covmat_pdf)}{print_bracket}") canv_combined.Print(f"{os.path.join(cfg['output']['directory'], output_name_pdf)}{print_bracket}") canv_unc.Print(f"{os.path.join(cfg['output']['directory'], output_name_unc_pdf)}{print_bracket}") + canv_rel_unc.Print(f"{os.path.join(cfg['output']['directory'], output_name_rel_unc_pdf)}{print_bracket}") output.cd() if is_save_to_root_file[ObjectToSave.CorrectedYield]: From b037acda359ceb4e251192f26c48de3143e9ecbb Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Wed, 2 Sep 2026 21:56:37 +0200 Subject: [PATCH 06/13] adapt config.json to plot_relative_uncertainties() --- PWGHF/D2H/Macros/config_cutvar_example.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/PWGHF/D2H/Macros/config_cutvar_example.json b/PWGHF/D2H/Macros/config_cutvar_example.json index f13a2d53d7f..a5878b62578 100644 --- a/PWGHF/D2H/Macros/config_cutvar_example.json +++ b/PWGHF/D2H/Macros/config_cutvar_example.json @@ -62,14 +62,16 @@ "frac": false, "eff": false, "cov": false, - "unc": true + "unc": true, + "relunc": true }, "is_save_canvas_as_macro": { "rawy": false, "frac": false, "eff": false, "cov": false, - "unc": false + "unc": false, + "relunc": false }, "is_save_to_root_file": { "canvas": true, From e2ed8a6624e12342ff5223612d1345536d5d4867 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Thu, 3 Sep 2026 18:54:41 +0200 Subject: [PATCH 07/13] make covariance-rho statements less bulky --- PWGHF/D2H/Macros/cut_variation.py | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/PWGHF/D2H/Macros/cut_variation.py b/PWGHF/D2H/Macros/cut_variation.py index da60f44a19e..d60bb4fd033 100644 --- a/PWGHF/D2H/Macros/cut_variation.py +++ b/PWGHF/D2H/Macros/cut_variation.py @@ -161,17 +161,10 @@ def minimise_system(self, correlated=True, precision=1.0e-8, max_iterations=100) ) if correlated and unc_row > 0 and unc_col > 0: - if unc_row < unc_col: - rho = unc_row / unc_col - else: - rho = unc_col / unc_row + self.m_cov_sets[i_row, i_col] = min(unc_row **2, unc_col ** 2) else: - if i_row == i_col: - rho = 1.0 - else: - rho = 0.0 - cov_row_col = rho * unc_row * unc_col - self.m_cov_sets[i_row, i_col] = cov_row_col + self.m_cov_sets[i_row, i_col] = unc_row ** 2 if i_row == i_col else 0.0 + self.m_cov_sets = np.matrix(self.m_cov_sets) try: @@ -637,15 +630,9 @@ def plot_cov_matrix(self, correlated=True, suffix="", title=""): for i_row, unc_row in enumerate(self.unc_raw_yields): for i_col, unc_col in enumerate(self.unc_raw_yields): if correlated and unc_row > 0 and unc_col > 0: - if unc_row < unc_col: - rho = unc_row / unc_col - else: - rho = unc_col / unc_row + rho = min(unc_row / unc_col, unc_col / unc_row) else: - if i_row == i_col: - rho = 1.0 - else: - rho = 0.0 + rho = 1.0 if i_row == i_col else 0.0 hist_corr_matrix.SetBinContent(i_row + 1, i_col + 1, rho) canvas = ROOT.TCanvas(f"cCorrMatrixCutSets{suffix}", "", 500, 500) From 3679f030820bc9f6bf112d31f679361c802d094a Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Wed, 9 Sep 2026 14:25:19 +0200 Subject: [PATCH 08/13] enable zeroing eff(p,np) uncertainties on request --- PWGHF/D2H/Macros/compute_fraction_cutvar.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/PWGHF/D2H/Macros/compute_fraction_cutvar.py b/PWGHF/D2H/Macros/compute_fraction_cutvar.py index 72af071ecb3..53d2c689326 100644 --- a/PWGHF/D2H/Macros/compute_fraction_cutvar.py +++ b/PWGHF/D2H/Macros/compute_fraction_cutvar.py @@ -55,6 +55,8 @@ def main(config): with open(config, encoding="utf8") as fil: cfg = json.load(fil) + zero_eff_unc = cfg.get("zero_eff_unc", False) + hist_rawy, hist_effp, hist_effnp = ([] for _ in range(3)) for filename_rawy, filename_eff in zip(cfg["rawyields"]["inputfiles"], cfg["efficiencies"]["inputfiles"]): infile_rawy = ROOT.TFile.Open(os.path.join(cfg["rawyields"]["inputdir"], filename_rawy)) @@ -76,6 +78,10 @@ def main(config): sys.exit(f"\33[31mFatal error: Histogram with efficiency for nonprompt \"{hist_effnp}\" is absent. Exit.\33[0m") hist_effp[-1].SetDirectory(0) hist_effnp[-1].SetDirectory(0) + if zero_eff_unc: + for i_bin in range(1, hist_effp[-1].GetNbinsX() + 1): + hist_effp[-1].SetBinError(i_bin, 0.0) + hist_effnp[-1].SetBinError(i_bin, 0.0) infile_eff.Close() pt_bin_to_process = cfg.get("pt_bin_to_process", -1) From 7b9dbb1d29c9ace147c942dc721ee6e356ebd4a1 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Tue, 15 Sep 2026 22:56:02 +0200 Subject: [PATCH 09/13] enable shift eff central value by n sigma --- PWGHF/D2H/Macros/compute_fraction_cutvar.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/PWGHF/D2H/Macros/compute_fraction_cutvar.py b/PWGHF/D2H/Macros/compute_fraction_cutvar.py index 53d2c689326..87915403b09 100644 --- a/PWGHF/D2H/Macros/compute_fraction_cutvar.py +++ b/PWGHF/D2H/Macros/compute_fraction_cutvar.py @@ -56,6 +56,8 @@ def main(config): cfg = json.load(fil) zero_eff_unc = cfg.get("zero_eff_unc", False) + effp_shift_nsigma = cfg.get("effp_shift_nsigma", 0.0) + effnp_shift_nsigma = cfg.get("effnp_shift_nsigma", 0.0) hist_rawy, hist_effp, hist_effnp = ([] for _ in range(3)) for filename_rawy, filename_eff in zip(cfg["rawyields"]["inputfiles"], cfg["efficiencies"]["inputfiles"]): @@ -78,8 +80,10 @@ def main(config): sys.exit(f"\33[31mFatal error: Histogram with efficiency for nonprompt \"{hist_effnp}\" is absent. Exit.\33[0m") hist_effp[-1].SetDirectory(0) hist_effnp[-1].SetDirectory(0) - if zero_eff_unc: - for i_bin in range(1, hist_effp[-1].GetNbinsX() + 1): + for i_bin in range(1, hist_effp[-1].GetNbinsX() + 1): + hist_effp[-1].SetBinContent(i_bin, hist_effp[-1].GetBinContent(i_bin) + effp_shift_nsigma*hist_effp[-1].GetBinError(i_bin)) + hist_effnp[-1].SetBinContent(i_bin, hist_effnp[-1].GetBinContent(i_bin) + effnp_shift_nsigma*hist_effnp[-1].GetBinError(i_bin)) + if zero_eff_unc: hist_effp[-1].SetBinError(i_bin, 0.0) hist_effnp[-1].SetBinError(i_bin, 0.0) infile_eff.Close() From b81e3cadda20a64417e61d398573561265cc9060 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Tue, 15 Sep 2026 22:58:59 +0200 Subject: [PATCH 10/13] provide default json args for shift eff and zero its error --- PWGHF/D2H/Macros/config_cutvar_example.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/PWGHF/D2H/Macros/config_cutvar_example.json b/PWGHF/D2H/Macros/config_cutvar_example.json index a5878b62578..d645db1a6d6 100644 --- a/PWGHF/D2H/Macros/config_cutvar_example.json +++ b/PWGHF/D2H/Macros/config_cutvar_example.json @@ -97,5 +97,8 @@ "output": { "directory": ".", "file": "CutVarDplus_pp13TeV_MB.root" - } + }, + "zero_eff_unc": false, + "effp_shift_nsigma": 0, + "effnp_shift_nsigma": 0 } From c6080b1a0e566ed9e9d1b9f01593859940c23c08 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Tue, 15 Sep 2026 23:40:54 +0200 Subject: [PATCH 11/13] fix MegaLinter errors --- PWGHF/D2H/Macros/compute_fraction_cutvar.py | 20 ++++++------- PWGHF/D2H/Macros/cut_variation.py | 31 +++++++++++++++++---- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/PWGHF/D2H/Macros/compute_fraction_cutvar.py b/PWGHF/D2H/Macros/compute_fraction_cutvar.py index 87915403b09..e432bff001c 100644 --- a/PWGHF/D2H/Macros/compute_fraction_cutvar.py +++ b/PWGHF/D2H/Macros/compute_fraction_cutvar.py @@ -293,56 +293,56 @@ def main(config): hist_bin_title = f"bin # {ipt+1}; {pt_axis_title}#in ({pt_min}; {pt_max})" hist_bin_title_rawy = hist_bin_title if is_draw_title[PlotType.Rawy] else "" - canv_rawy, histos_rawy, leg_r = minimiser.plot_result(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_rawy) + canv_rawy, histos_rawy, _leg_r = minimiser.plot_result(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_rawy) output.cd() if is_save_to_root_file[ObjectToSave.Canvas]: canv_rawy.Write() if is_save_to_root_file[ObjectToSave.RawYield]: - for _, hist in histos_rawy.items(): + for _, hist in histos_rawy.values(): hist.Write() if is_save_canvas_as_macro[PlotType.Rawy]: canv_rawy.SaveAs(f"canv_rawy_{ipt+1}.C") hist_bin_title_unc = hist_bin_title if is_draw_title[PlotType.Unc] else "" - canv_unc, histos_unc, leg_unc = minimiser.plot_uncertainties(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_unc) + canv_unc, histos_unc, _leg_unc = minimiser.plot_uncertainties(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_unc) output.cd() if is_save_to_root_file[ObjectToSave.Canvas]: canv_unc.Write() if is_save_to_root_file[ObjectToSave.Uncertainty]: - for _, hist in histos_unc.items(): + for _, hist in histos_unc.values(): hist.Write() if is_save_canvas_as_macro[PlotType.Unc]: canv_unc.SaveAs(f"canv_unc_{ipt+1}.C") hist_bin_title_rel_unc = hist_bin_title if is_draw_title[PlotType.RelUnc] else "" - canv_rel_unc, histos_rel_unc, leg_rel_unc = minimiser.plot_relative_uncertainties(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_rel_unc) + canv_rel_unc, histos_rel_unc, _leg_rel_unc = minimiser.plot_relative_uncertainties(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_rel_unc) output.cd() if is_save_to_root_file[ObjectToSave.Canvas]: canv_rel_unc.Write() if is_save_to_root_file[ObjectToSave.Uncertainty]: - for _, hist in histos_rel_unc.items(): + for _, hist in histos_rel_unc.values(): hist.Write() if is_save_canvas_as_macro[PlotType.RelUnc]: canv_rel_unc.SaveAs(f"canv_rel_unc_{ipt+1}.C") hist_bin_title_eff = hist_bin_title if is_draw_title[PlotType.Eff] else "" - canv_eff, histos_eff, leg_e = minimiser.plot_efficiencies(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_eff) + canv_eff, histos_eff, _leg_e = minimiser.plot_efficiencies(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_eff) output.cd() if is_save_to_root_file[ObjectToSave.Canvas]: canv_eff.Write() if is_save_to_root_file[ObjectToSave.Efficiency]: - for _, hist in histos_eff.items(): + for _, hist in histos_eff.values(): hist.Write() if is_save_canvas_as_macro[PlotType.Eff]: canv_eff.SaveAs(f"canv_eff_{ipt+1}.C") hist_bin_title_frac = hist_bin_title if is_draw_title[PlotType.Frac] else "" - canv_frac, histos_frac, leg_f = minimiser.plot_fractions(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_frac) + canv_frac, histos_frac, _leg_f = minimiser.plot_fractions(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_frac) output.cd() if is_save_to_root_file[ObjectToSave.Canvas]: canv_frac.Write() if is_save_to_root_file[ObjectToSave.Fraction]: - for _, hist in histos_frac.items(): + for _, hist in histos_frac.values(): hist.Write() if is_save_canvas_as_macro[PlotType.Frac]: canv_frac.SaveAs(f"canv_frac_{ipt+1}.C") diff --git a/PWGHF/D2H/Macros/cut_variation.py b/PWGHF/D2H/Macros/cut_variation.py index d60bb4fd033..670517c7269 100644 --- a/PWGHF/D2H/Macros/cut_variation.py +++ b/PWGHF/D2H/Macros/cut_variation.py @@ -46,13 +46,32 @@ class CutVarMinimiser: def __init__( # pylint: disable=too-many-arguments self, - raw_yields=np.zeros(0), - eff_prompt=np.zeros(0), - eff_nonprompt=np.zeros(0), - unc_raw_yields=np.zeros(0), - unc_eff_prompt=np.zeros(0), - unc_eff_nonprompt=np.zeros(0), + raw_yields=None, + eff_prompt=None, + eff_nonprompt=None, + unc_raw_yields=None, + unc_eff_prompt=None, + unc_eff_nonprompt=None, ): + inputs = ( + raw_yields, + eff_prompt, + eff_nonprompt, + unc_raw_yields, + unc_eff_prompt, + unc_eff_nonprompt, + ) + + if all(value is None for value in inputs): + raw_yields = np.zeros(0) + eff_prompt = np.zeros(0) + eff_nonprompt = np.zeros(0) + unc_raw_yields = np.zeros(0) + unc_eff_prompt = np.zeros(0) + unc_eff_nonprompt = np.zeros(0) + elif any(value is None for value in inputs): + raise ValueError("Either all input arrays or none must be provided.") + self.raw_yields = raw_yields self.eff_prompt = eff_prompt self.eff_nonprompt = eff_nonprompt From 539ef7b8003486362dbf1c547b72f6f717be9bc7 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Tue, 15 Sep 2026 23:56:50 +0200 Subject: [PATCH 12/13] fix MegaLinter errors (x2) --- PWGHF/D2H/Macros/cut_variation.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/PWGHF/D2H/Macros/cut_variation.py b/PWGHF/D2H/Macros/cut_variation.py index 670517c7269..52a2164d4d0 100644 --- a/PWGHF/D2H/Macros/cut_variation.py +++ b/PWGHF/D2H/Macros/cut_variation.py @@ -53,24 +53,18 @@ def __init__( # pylint: disable=too-many-arguments unc_eff_prompt=None, unc_eff_nonprompt=None, ): - inputs = ( - raw_yields, - eff_prompt, - eff_nonprompt, - unc_raw_yields, - unc_eff_prompt, - unc_eff_nonprompt, - ) - - if all(value is None for value in inputs): + if raw_yields is None: raw_yields = np.zeros(0) + if eff_prompt is None: eff_prompt = np.zeros(0) + if eff_nonprompt is None: eff_nonprompt = np.zeros(0) + if unc_raw_yields is None: unc_raw_yields = np.zeros(0) + if unc_eff_prompt is None: unc_eff_prompt = np.zeros(0) + if unc_eff_nonprompt is None: unc_eff_nonprompt = np.zeros(0) - elif any(value is None for value in inputs): - raise ValueError("Either all input arrays or none must be provided.") self.raw_yields = raw_yields self.eff_prompt = eff_prompt From 5be7fd8fea41c2d74a64d8bb6bbc61f915845144 Mon Sep 17 00:00:00 2001 From: ALICE Builder Date: Wed, 16 Sep 2026 00:07:49 +0200 Subject: [PATCH 13/13] MegaLinter fixes (#17) --- PWGHF/D2H/Macros/compute_fraction_cutvar.py | 10 +++++----- PWGHF/D2H/Macros/cut_variation.py | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/PWGHF/D2H/Macros/compute_fraction_cutvar.py b/PWGHF/D2H/Macros/compute_fraction_cutvar.py index e432bff001c..74432688725 100644 --- a/PWGHF/D2H/Macros/compute_fraction_cutvar.py +++ b/PWGHF/D2H/Macros/compute_fraction_cutvar.py @@ -11,13 +11,13 @@ import json import os import sys +from enum import IntEnum, auto import numpy as np # pylint: disable=import-error import ROOT # pylint: disable=import-error -from enum import IntEnum, auto + sys.path.insert(0, '..') -from cut_variation import CutVarMinimiser -from cut_variation import MinimisationStatus +from cut_variation import CutVarMinimiser, MinimisationStatus from style_formatter import set_object_style # pylint: disable=no-member,too-many-locals,too-many-statements @@ -252,9 +252,9 @@ def main(config): print("\0\33[33mWARNING! main(): the raw yield uncertainties vector is not monotonous. Check the input for stability.\0\33[0m") print(f"raw yield uncertainties vector elements = {unc_rawy}\n") if not (np.all(effp[1:] > effp[:-1]) or np.all(effp[1:] < effp[:-1])): - sys.exit(f"\33[31mFatal error: the prompt efficiency vector is not monotonous. Check the input. Exit.\33[0m") + sys.exit("\33[31mFatal error: the prompt efficiency vector is not monotonous. Check the input. Exit.\33[0m") if not (np.all(effnp[1:] > effnp[:-1]) or np.all(effnp[1:] < effnp[:-1])): - sys.exit(f"\33[31mFatal error: the nonprompt efficiency vector is not monotonous. Check the input. Exit.\33[0m") + sys.exit("\33[31mFatal error: the nonprompt efficiency vector is not monotonous. Check the input. Exit.\33[0m") minimiser = CutVarMinimiser(rawy, effp, effnp, unc_rawy, unc_effp, unc_effnp) status = minimiser.minimise_system(cfg["minimisation"]["correlated"]) diff --git a/PWGHF/D2H/Macros/cut_variation.py b/PWGHF/D2H/Macros/cut_variation.py index 52a2164d4d0..8a6c31a96b4 100644 --- a/PWGHF/D2H/Macros/cut_variation.py +++ b/PWGHF/D2H/Macros/cut_variation.py @@ -8,13 +8,15 @@ """ import sys +from enum import IntEnum, auto import numpy as np # pylint: disable=import-error import ROOT # pylint: disable=import-error -from enum import IntEnum, auto + sys.path.insert(0, '..') from style_formatter import set_global_style, set_object_style + class MinimisationStatus(IntEnum): Undefined = 0 Success = auto()