7 Call this "python3 fei/latexReporting.py summary.tex"
8 in a directory containing the monitoring output of the FEI
9 It will create a latex document containing a summary and plots
10 and tries to compile this summary.tex into a PDF file summary.pdf
12 You can improve / modify this script
13 E.g. If you want to add new plots:
14 Add your plot in the monitoring.py file
15 Add your plot below using b2latex.Graphics
20 from ROOT
import Belle2
22 from fei
import monitoring
24 from B2Tools
import b2latex
25 from B2Tools
import format
32 if __name__ ==
'__main__':
34 output_file = sys.argv[1]
36 raise AttributeError(
"You have to supply the output tex file.")
38 particles, configuration = monitoring.load_config()
39 monitoringParticle = []
40 for particle
in particles:
41 monitoringParticle.append(monitoring.MonitoringParticle(particle))
44 o = b2latex.LatexFile()
46 o += b2latex.TitlePage(title=
'Full Event Interpretation Report',
47 authors=[
'Thomas Keck',
'Christian Pulvermacher',
'William Sutcliffe'],
49 This report contains key performance indicators and control plots of the Full Event Interpretation.
50 The pre-, and post-cuts as well as trained multivariate selection methods are described.
51 Furthermore the resulting purities and efficiencies are stated.
53 add_table_of_contents=
True).finish()
55 o += b2latex.Section(
"Summary").finish()
56 o += b2latex.String(
r"""
57 For each decay channel of each particle a multivariate selection method is trained after applying
58 a fast pre-cut on the candidates. Afterwards, a post-cut is applied on the signal probability calculated by the method.
59 This reduces combinatorics in the following stages of the Full
63 table = b2latex.LongTable(columnspecs=
r'c|rr|rrrrrr',
64 caption=
'Per-particle efficiency before and after the applied pre- and post-cut.',
65 head=
r'Particle & \multicolumn{2}{c}{Covered BR} '
66 r' & \multicolumn{3}{c}{pre-cut} & \multicolumn{3}{c}{post-cut} \\'
67 r' & exc & inc & user & ranking & vertex '
68 r' & absolute & ranking & unique',
69 format_string=
r'{name} & {exc_br:.3f} & {inc_br:.3f} & {user_pre_cut:.3f} & {ranking_pre_cut:.3f}'
70 r' & {vertex_pre_cut:.3f} & {absolute_post_cut:.3f}'
71 r' & {ranking_post_cut:.3f} & {after_tag:.3f}')
73 for p
in monitoringParticle:
74 table.add(name=format.decayDescriptor(p.particle.identifier),
75 exc_br=sum(p.exc_br_per_channel.values()),
76 inc_br=sum(p.inc_br_per_channel.values()),
77 user_pre_cut=sum(p.before_ranking.values()).efficiency,
78 ranking_pre_cut=sum(p.after_ranking.values()).efficiency,
79 vertex_pre_cut=sum(p.after_vertex.values()).efficiency,
80 absolute_post_cut=p.before_ranking_postcut.efficiency,
81 ranking_post_cut=p.after_ranking_postcut.efficiency,
82 after_tag=p.after_tag.efficiency)
85 table = b2latex.LongTable(columnspecs=
r'c|rrrrrr',
86 caption=
'Per-particle purity before and after the applied pre- and post-cut.',
88 r' & \multicolumn{3}{c}{pre-cut} & \multicolumn{3}{c}{post-cut} \\'
89 r' & user & ranking & vertex '
90 r' & absolute & ranking & unique',
91 format_string=
r'{name} & {user_pre_cut:.3f} & {ranking_pre_cut:.3f}'
92 r' & {vertex_pre_cut:.3f} & {absolute_post_cut:.3f}'
93 r' & {ranking_post_cut:.3f} & {after_tag:.3f}')
95 for p
in monitoringParticle:
96 table.add(name=format.decayDescriptor(p.particle.identifier),
97 user_pre_cut=sum(p.before_ranking.values()).purity,
98 ranking_pre_cut=sum(p.after_ranking.values()).purity,
99 vertex_pre_cut=sum(p.after_vertex.values()).purity,
100 absolute_post_cut=p.before_ranking_postcut.purity,
101 ranking_post_cut=p.after_ranking_postcut.purity,
102 after_tag=p.after_tag.purity)
106 moduleTypes = [
'ParticleCombiner',
'MVAExpert',
'MCMatch',
'ParticleVertexFitter',
'BestCandidateSelection',
'Other']
108 o += b2latex.Section(
"CPU time").finish()
109 colour_list = b2latex.DefineColourList()
110 o += colour_list.finish()
112 for p
in monitoringParticle:
113 o += b2latex.SubSection(format.decayDescriptor(p.particle.identifier)).finish()
115 table = b2latex.LongTable(columnspecs=
r'lrcrr',
116 caption=
'Total CPU time spent in event() calls for each channel. Bars show ' +
117 ', '.join(
'\\textcolor{%s}{%s}' % (c, m)
118 for c, m
in zip(colour_list.colours, moduleTypes)) +
119 ', in this order. Does not include I/O, initialisation, training, post-cuts etc.',
120 head=
r'Decay & CPU time & by module & per (true) candidate & Relative time ',
121 format_string=
r'{name} & {time} & {bargraph} & {timePerCandidate} & {timePercent:.2f}\% ')
123 tt_channel = sum(p.module_statistic.channel_time.values())
124 tt_particle = p.module_statistic.particle_time + sum(p.module_statistic.channel_time.values())
125 fraction = tt_channel / tt_particle * 100
if tt_particle > 0
else 0.0
127 for channel
in p.particle.channels:
128 time = p.time_per_channel[channel.label]
129 trueCandidates = p.after_classifier[channel.label].nSig
130 allCandidates = p.after_classifier[channel.label].nTotal
132 if trueCandidates == 0
or allCandidates == 0:
135 timePerCandidate = format.duration(time / trueCandidates) +
' (' + format.duration(time / allCandidates) +
')'
136 timePercent = time / tt_particle * 100
if tt_particle > 0
else 0
138 percents = [p.module_statistic.channel_time_per_module[channel.label].get(key, 0.0) / float(time) * 100.0
139 if time > 0
else 0.0
for key
in moduleTypes[:-1]]
140 percents.append(100.0 - sum(percents))
142 table.add(name=format.decayDescriptor(channel.label),
143 bargraph=
r'\plotbar{ %g/, %g/, %g/, %g/, %g/, %g/, }' % tuple(percents),
144 time=format.duration(time),
145 timePerCandidate=timePerCandidate,
146 timePercent=time / tt_particle * 100
if p.total_time > 0
else 0)
148 o += table.finish(tail=
'Total & & {tt_channel} / {tt_particle} & & {fraction:.2f}'.format(
149 tt_channel=format.duration(tt_channel), tt_particle=format.duration(tt_particle), fraction=fraction))
151 for p
in monitoringParticle:
152 print(p.particle.identifier)
154 o += b2latex.Section(format.decayDescriptor(p.particle.identifier)).finish()
155 string = b2latex.String(
r"In the reconstruction of {name} {nChannels} out of {max_nChannels} possible channels were used. "
156 r"The covered inclusive / exclusive branching fractions is {inc_br:.5f} / {exc_br:.5f}."
157 r"The final unique efficiency and purity was {eff:.5f} / {pur:.5f}")
159 o += string.finish(name=format.decayDescriptor(p.particle.identifier),
160 nChannels=p.reconstructed_number_of_channels,
161 max_nChannels=p.total_number_of_channels,
162 exc_br=sum(p.exc_br_per_channel.values()),
163 inc_br=sum(p.inc_br_per_channel.values()),
164 eff=p.after_tag.efficiency,
165 pur=p.after_tag.purity)
167 roc_plot_filename = monitoring.removeJPsiSlash(p.particle.identifier +
'_ROC')
168 monitoring.MonitorROCPlot(p, roc_plot_filename)
169 o += b2latex.Graphics().add(roc_plot_filename +
'.png', width=0.8).finish()
171 diag_plot_filename = monitoring.removeJPsiSlash(p.particle.identifier +
'_Diag')
172 monitoring.MonitorDiagPlot(p, diag_plot_filename)
173 o += b2latex.Graphics().add(diag_plot_filename +
'.png', width=0.8).finish()
175 if p.particle.identifier
in [
'B+:generic',
'B0:generic']:
176 money_plot_filename = monitoring.removeJPsiSlash(p.particle.identifier +
'_Money')
177 monitoring.MonitorMbcPlot(p, money_plot_filename)
178 g = b2latex.Graphics()
179 for filename
in glob.glob(money_plot_filename +
'_*.png'):
180 g.add(filename, width=0.49)
183 if p.particle.identifier
in [
'B+:semileptonic',
'B0:semileptonic']:
184 money_plot_filename = monitoring.removeJPsiSlash(p.particle.identifier +
'_Money')
185 monitoring.MonitorCosBDLPlot(p, money_plot_filename)
186 g = b2latex.Graphics()
187 for filename
in glob.glob(money_plot_filename +
'_*.png'):
188 g.add(filename, width=0.49)
191 table = b2latex.LongTable(columnspecs=
r'c|rr|rrr',
192 caption=
'Per-channel efficiency before and after the applied pre-cut.',
193 head=
r'Particle & \multicolumn{2}{c}{Covered BR} '
194 r' & \multicolumn{3}{c}{pre-cut} \\'
195 r' & exc & inc & user & ranking & vertex ',
196 format_string=
r'{name} & {exc_br:.3f} & {inc_br:.3f} & {user_pre_cut:.5f} & '
197 r'{ranking_pre_cut:.5f} & {vertex_pre_cut:.5f}')
199 for channel
in p.particle.channels:
200 table.add(name=format.decayDescriptor(channel.label),
201 exc_br=p.exc_br_per_channel[channel.label],
202 inc_br=p.inc_br_per_channel[channel.label],
203 user_pre_cut=p.before_ranking[channel.label].efficiency,
204 ranking_pre_cut=p.after_ranking[channel.label].efficiency,
205 vertex_pre_cut=p.after_vertex[channel.label].efficiency,
206 absolute_post_cut=p.before_ranking_postcut.efficiency,
207 ranking_post_cut=p.after_ranking_postcut.efficiency,
208 after_tag=p.after_tag.efficiency)
211 table = b2latex.LongTable(columnspecs=
r'c|c|rrr',
212 caption=
'Per-channel purity before and after the applied pre-cut.',
213 head=
r'Particle & Ignored '
214 r' & \multicolumn{3}{c}{pre-cut} \\'
215 r' && user & ranking & vertex ',
216 format_string=
r'{name} & {ignored} & {user_pre_cut:.5f} & {ranking_pre_cut:.5f}'
217 r' & {vertex_pre_cut:.5f}')
219 for channel
in p.particle.channels:
220 table.add(name=format.decayDescriptor(channel.label),
221 ignored=
r'\textcolor{red}{$\blacksquare$}' if p.ignored_channels[channel.label]
else '',
222 user_pre_cut=p.before_ranking[channel.label].purity,
223 ranking_pre_cut=p.after_ranking[channel.label].purity,
224 vertex_pre_cut=p.after_vertex[channel.label].purity)
227 o.save(output_file, compile=
True)