Skip to content

Commit 5c79d8b

Browse files
authored
[PWGHF] Cut variation: make analysis more flexible and output more informative (#11985)
1 parent 0ad6a87 commit 5c79d8b

File tree

2 files changed

+140
-8
lines changed

2 files changed

+140
-8
lines changed

PWGHF/D2H/Macros/compute_fraction_cutvar.py

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ def main(config):
5555
hist_effnp[-1].SetDirectory(0)
5656
infile_eff.Close()
5757

58+
pt_bin_to_process = cfg.get("pt_bin_to_process", -1)
59+
if not isinstance(pt_bin_to_process, int):
60+
sys.exit("Fatal error: pt_bin_to_process must be an integer value. Exit.")
61+
if (pt_bin_to_process != -1 and pt_bin_to_process < 1) or pt_bin_to_process > hist_rawy[0].GetNbinsX():
62+
sys.exit("Fatal error: pt_bin_to_process must be a positive value up to number of bins in raw yield histogram. Exit.")
63+
5864
if cfg["central_efficiency"]["computerawfrac"]:
5965
infile_name = os.path.join(cfg["central_efficiency"]["inputdir"], cfg["central_efficiency"]["inputfile"])
6066
infile_central_eff = ROOT.TFile.Open(infile_name)
@@ -80,6 +86,8 @@ def main(config):
8086
hist_covariance = hist_rawy[0].Clone("hCovPromptNonPrompt")
8187
hist_corrfrac_prompt = hist_rawy[0].Clone("hCorrFracPrompt")
8288
hist_corrfrac_nonprompt = hist_rawy[0].Clone("hCorrFracNonPrompt")
89+
for histo in hist_corry_prompt, hist_corry_nonprompt, hist_covariance, hist_corrfrac_prompt, hist_corrfrac_nonprompt:
90+
histo.Reset()
8391
hist_corry_prompt.GetYaxis().SetTitle("corrected yields prompt")
8492
hist_corry_nonprompt.GetYaxis().SetTitle("corrected yields non-prompt")
8593
hist_covariance.GetYaxis().SetTitle("#sigma(prompt, non-prompt)")
@@ -113,6 +121,8 @@ def main(config):
113121
if cfg["central_efficiency"]["computerawfrac"]:
114122
hist_frac_raw_prompt = hist_rawy[0].Clone("hRawFracPrompt")
115123
hist_frac_raw_nonprompt = hist_rawy[0].Clone("hRawFracNonPrompt")
124+
for histo in hist_frac_raw_prompt, hist_frac_raw_nonprompt:
125+
histo.Reset()
116126
hist_frac_raw_prompt.GetYaxis().SetTitle("raw fraction prompt")
117127
hist_frac_raw_nonprompt.GetYaxis().SetTitle("raw fraction non-prompt")
118128
set_object_style(
@@ -129,12 +139,20 @@ def main(config):
129139
markerstyle=ROOT.kFullSquare,
130140
)
131141

132-
output = ROOT.TFile(os.path.join(cfg["output"]["directory"], cfg["output"]["file"]), "recreate")
142+
pt_bin_to_process_name_suffix = ""
143+
if pt_bin_to_process != -1:
144+
pt_bin_to_process_name_suffix = "_bin_" + str(pt_bin_to_process)
145+
146+
output_name_template = cfg['output']['file'].replace(".root", "") + pt_bin_to_process_name_suffix + ".root"
147+
output = ROOT.TFile(os.path.join(cfg["output"]["directory"], output_name_template), "recreate")
133148
n_sets = len(hist_rawy)
134149
pt_axis_title = hist_rawy[0].GetXaxis().GetTitle()
135150
for ipt in range(hist_rawy[0].GetNbinsX()):
151+
if pt_bin_to_process !=-1 and ipt+1 != pt_bin_to_process:
152+
continue
136153
pt_min = hist_rawy[0].GetXaxis().GetBinLowEdge(ipt + 1)
137154
pt_max = hist_rawy[0].GetXaxis().GetBinUpEdge(ipt + 1)
155+
print(f"\n\nINFO: processing pt range {ipt+1} from {pt_min} to {pt_max} {pt_axis_title}")
138156

139157
rawy, effp, effnp, unc_rawy, unc_effp, unc_effnp = (np.zeros(n_sets) for _ in range(6))
140158
for iset, (hrawy, heffp, heffnp) in enumerate(zip(hist_rawy, hist_effp, hist_effnp)):
@@ -145,6 +163,14 @@ def main(config):
145163
unc_effp[iset] = heffp.GetBinError(ipt + 1)
146164
unc_effnp[iset] = heffnp.GetBinError(ipt + 1)
147165

166+
if cfg["minimisation"]["correlated"]:
167+
if not (np.all(rawy[1:] > rawy[:-1]) or np.all(rawy[1:] < rawy[:-1])):
168+
print("WARNING! main(): the raw yield vector is not monotonous. Check the input for stability.")
169+
print(f"raw yield vector elements = {rawy}\n")
170+
if not (np.all(unc_rawy[1:] > unc_rawy[:-1]) or np.all(unc_rawy[1:] < unc_rawy[:-1])):
171+
print("WARNING! main(): the raw yield uncertainties vector is not monotonous. Check the input for stability.")
172+
print(f"raw yield uncertainties vector elements = {unc_rawy}\n")
173+
148174
minimiser = CutVarMinimiser(rawy, effp, effnp, unc_rawy, unc_effp, unc_effnp)
149175
minimiser.minimise_system(cfg["minimisation"]["correlated"])
150176

@@ -180,6 +206,12 @@ def main(config):
180206
for _, hist in histos_rawy.items():
181207
hist.Write()
182208

209+
canv_unc, histos_unc, leg_unc = minimiser.plot_uncertainties(f"_pt{pt_min}_{pt_max}", hist_bin_title)
210+
output.cd()
211+
canv_unc.Write()
212+
for _, hist in histos_unc.items():
213+
hist.Write()
214+
183215
canv_eff, histos_eff, leg_e = minimiser.plot_efficiencies(f"_pt{pt_min}_{pt_max}", hist_bin_title)
184216
output.cd()
185217
canv_eff.Write()
@@ -208,13 +240,16 @@ def main(config):
208240
canv_combined.cd(4)
209241
canv_cov.DrawClonePad()
210242

211-
output_name_rawy_pdf = f"Distr_{cfg['output']['file'].replace('.root', '.pdf')}"
212-
output_name_eff_pdf = f"Eff_{cfg['output']['file'].replace('.root', '.pdf')}"
213-
output_name_frac_pdf = f"Frac_{cfg['output']['file'].replace('.root', '.pdf')}"
214-
output_name_covmat_pdf = f"CovMatrix_{cfg['output']['file'].replace('.root', '.pdf')}"
215-
output_name_pdf = f"{cfg['output']['file'].replace('.root', '.pdf')}"
243+
output_name_template = output_name_template.replace('.root', '.pdf')
244+
245+
output_name_rawy_pdf = f"Distr_{output_name_template}"
246+
output_name_eff_pdf = f"Eff_{output_name_template}"
247+
output_name_frac_pdf = f"Frac_{output_name_template}"
248+
output_name_covmat_pdf = f"CovMatrix_{output_name_template}"
249+
output_name_unc_pdf = f"Unc_{output_name_template}"
250+
output_name_pdf = f"{output_name_template}"
216251

217-
if hist_rawy[0].GetNbinsX() == 1:
252+
if hist_rawy[0].GetNbinsX() == 1 or pt_bin_to_process != -1:
218253
print_bracket = ""
219254
elif ipt == 0:
220255
print_bracket = "("
@@ -227,6 +262,7 @@ def main(config):
227262
canv_frac.Print(f"{os.path.join(cfg['output']['directory'], output_name_frac_pdf)}{print_bracket}")
228263
canv_cov.Print(f"{os.path.join(cfg['output']['directory'], output_name_covmat_pdf)}{print_bracket}")
229264
canv_combined.Print(f"{os.path.join(cfg['output']['directory'], output_name_pdf)}{print_bracket}")
265+
canv_unc.Print(f"{os.path.join(cfg['output']['directory'], output_name_unc_pdf)}{print_bracket}")
230266

231267
output.cd()
232268
hist_corry_prompt.Write()

PWGHF/D2H/Macros/cut_variation.py

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def minimise_system(self, correlated=True, precision=1.0e-8, max_iterations=100)
136136
self.m_eff = np.matrix(self.m_eff)
137137
m_corr_yields_old = np.zeros(shape=(2, 1))
138138

139-
for _ in range(max_iterations):
139+
for iteration in range(max_iterations):
140140
for i_row, (rw_unc_row, effp_unc_row, effnp_unc_row) in enumerate(
141141
zip(self.unc_raw_yields, self.unc_eff_prompt, self.unc_eff_nonprompt)
142142
):
@@ -189,6 +189,13 @@ def minimise_system(self, correlated=True, precision=1.0e-8, max_iterations=100)
189189

190190
m_corr_yields_old = np.copy(self.m_corr_yields)
191191

192+
print(f"INFO: number of processed iterations = {iteration+1}\n")
193+
if correlated:
194+
m_cov_sets_diag = np.diag(self.m_cov_sets)
195+
if not (np.all(m_cov_sets_diag[1:] > m_cov_sets_diag[:-1]) or np.all(m_cov_sets_diag[1:] < m_cov_sets_diag[:-1])):
196+
print("WARNING! minimise_system(): the residual vector uncertainties elements are not monotonous. Check the input for stability.")
197+
print(f"residual vector uncertainties elements = {np.sqrt(m_cov_sets_diag)}\n")
198+
192199
# chi2
193200
self.chi_2 = float(np.transpose(self.m_res) * self.m_weights * self.m_res)
194201

@@ -432,6 +439,8 @@ def plot_result(self, suffix="", title=""):
432439
-----------------------------------------------------
433440
- suffix: str
434441
suffix to be added in the name of the output objects
442+
- title: str
443+
title to be written at the top margin of the output objects
435444
436445
Returns
437446
-----------------------------------------------------
@@ -553,6 +562,8 @@ def plot_cov_matrix(self, correlated=True, suffix="", title=""):
553562
correlation between cut sets
554563
- suffix: str
555564
suffix to be added in the name of the output objects
565+
- title: str
566+
title to be written at the top margin of the output objects
556567
557568
Returns
558569
-----------------------------------------------------
@@ -612,6 +623,8 @@ def plot_efficiencies(self, suffix="", title=""):
612623
-----------------------------------------------------
613624
- suffix: str
614625
suffix to be added in the name of the output objects
626+
- title: str
627+
title to be written at the top margin of the output objects
615628
616629
Returns
617630
-----------------------------------------------------
@@ -701,6 +714,8 @@ def plot_fractions(self, suffix="", title=""):
701714
-----------------------------------------------------
702715
- suffix: str
703716
suffix to be added in the name of the output objects
717+
- title: str
718+
title to be written at the top margin of the output objects
704719
705720
Returns
706721
-----------------------------------------------------
@@ -774,3 +789,84 @@ def plot_fractions(self, suffix="", title=""):
774789
canvas.Update()
775790

776791
return canvas, histos, leg
792+
793+
# pylint: disable=no-member
794+
def plot_uncertainties(self, suffix="", title=""):
795+
"""
796+
Helper function to plot uncertainties as a function of cut set
797+
798+
Parameters
799+
-----------------------------------------------------
800+
- suffix: str
801+
suffix to be added in the name of the output objects
802+
- title: str
803+
title to be written at the top margin of the output objects
804+
805+
Returns
806+
-----------------------------------------------------
807+
- canvas: ROOT.TCanvas
808+
canvas with plot
809+
- histos: dict
810+
dictionary of ROOT.TH1F with uncertainties distributions for
811+
raw yield and residual vector
812+
- leg: ROOT.TLegend
813+
needed otherwise it is destroyed
814+
"""
815+
816+
set_global_style(padleftmargin=0.16, padbottommargin=0.12, padtopmargin=0.075, titleoffsety=1.6)
817+
818+
hist_raw_yield_unc = ROOT.TH1F(
819+
f"hRawYieldUncVsCut{suffix}",
820+
";cut set;runc.",
821+
self.n_sets,
822+
-0.5,
823+
self.n_sets - 0.5,
824+
)
825+
826+
hist_residual_unc = ROOT.TH1F(
827+
f"hResidualUncVsCut{suffix}",
828+
";cut set;unc.",
829+
self.n_sets,
830+
-0.5,
831+
self.n_sets - 0.5,
832+
)
833+
834+
m_cov_sets_diag = np.diag(self.m_cov_sets)
835+
m_cov_sets_diag = np.sqrt(m_cov_sets_diag)
836+
837+
for i_bin, (unc_rawy, unc_res) in enumerate(zip(self.unc_raw_yields, m_cov_sets_diag)):
838+
hist_raw_yield_unc.SetBinContent(i_bin + 1, unc_rawy)
839+
hist_residual_unc.SetBinContent(i_bin+1, unc_res)
840+
841+
set_object_style(hist_raw_yield_unc, color=ROOT.kRed + 1, fillstyle=0)
842+
set_object_style(hist_residual_unc, color=ROOT.kAzure + 4, fillstyle=0)
843+
844+
canvas = ROOT.TCanvas(f"cUncVsCut{suffix}", "", 500, 500)
845+
canvas.DrawFrame(
846+
-0.5,
847+
0.0,
848+
self.n_sets - 0.5,
849+
hist_residual_unc.GetMaximum() * 1.2,
850+
";cut set;unc.",
851+
)
852+
leg = ROOT.TLegend(0.6, 0.75, 0.8, 0.85)
853+
leg.SetBorderSize(0)
854+
leg.SetFillStyle(0)
855+
leg.SetTextSize(0.04)
856+
leg.AddEntry(hist_raw_yield_unc, "raw yield", "l")
857+
leg.AddEntry(hist_residual_unc, "residual vector", "l")
858+
leg.Draw()
859+
hist_raw_yield_unc.Draw("histsame")
860+
hist_residual_unc.Draw("histsame")
861+
tex = ROOT.TLatex()
862+
tex.SetTextSize(0.04)
863+
tex.DrawLatexNDC(0.05, 0.95, title)
864+
canvas.Modified()
865+
canvas.Update()
866+
867+
histos = {
868+
"rawy": hist_raw_yield_unc,
869+
"residual": hist_residual_unc,
870+
}
871+
872+
return canvas, histos, leg

0 commit comments

Comments
 (0)