12 Call this "python3 fei/latexReporting.py summary.tex"
13 in a directory containing the monitoring output of the FEI
14 It will create a latex document containing a summary and plots
15 and tries to compile this summary.tex into a PDF file summary.pdf
17 You can improve / modify this script
18 E.g. If you want to add new plots:
19 Add your plot in the monitoring.py file
20 Add your plot below using b2latex.Graphics
24from fei
import monitoring
25from fei.core import get_stages_from_particles
27from B2Tools
import b2latex
28from B2Tools
import format
34def create_latex(output_file, monitoringParticle):
36 o = b2latex.LatexFile()
38 o += b2latex.TitlePage(title=
'Full Event Interpretation Report',
39 authors=[
'Thomas Keck',
'Christian Pulvermacher',
'William Sutcliffe'],
41 This report contains key performance indicators and control plots of the Full Event Interpretation.
42 The pre-, and post-cuts as well as trained multivariate selection methods are described.
43 Furthermore the resulting purities and efficiencies are stated.
45 add_table_of_contents=
True).finish()
47 o += b2latex.Section(
"Summary").finish()
48 o += b2latex.String(
r"""
49 For each decay channel of each particle a multivariate selection method is trained after applying
50 a fast pre-cut on the candidates. Afterwards, a post-cut is applied on the signal probability calculated by the method.
51 This reduces combinatorics in the following stages of the Full
55 table = b2latex.LongTable(columnspecs=
r'c|rr|rrrrrr',
56 caption=
'Per-particle efficiency before and after the applied pre- and post-cut.',
57 head=
r'Particle & \multicolumn{2}{c}{Covered BR} '
58 r' & \multicolumn{3}{c}{pre-cut} & \multicolumn{3}{c}{post-cut} \\'
59 r' & exc & inc & user & ranking & vertex '
60 r' & absolute & ranking & unique',
61 format_string=
r'{name} & {exc_br} & {inc_br} & {user_pre_cut:.3f} & {ranking_pre_cut:.3f}'
62 r' & {vertex_pre_cut:.3f} & {absolute_post_cut:.3f}'
63 r' & {ranking_post_cut:.3f} & {after_tag:.3f}')
64 for p
in monitoringParticle:
65 table.add(name=format.decayDescriptor(p.particle.identifier),
66 exc_br=f
"{sum(p.exc_br_per_channel.values()):.3f}",
67 inc_br=f
"{sum(p.inc_br_per_channel.values()):.3f}",
68 user_pre_cut=sum(p.before_ranking.values()).efficiency,
69 ranking_pre_cut=sum(p.after_ranking.values()).efficiency,
70 vertex_pre_cut=sum(p.after_vertex.values()).efficiency,
71 absolute_post_cut=p.before_ranking_postcut.efficiency,
72 ranking_post_cut=p.after_ranking_postcut.efficiency,
73 after_tag=p.after_tag.efficiency)
77 user_pre_cut=sum(p.before_ranking.values()).efficiency,
78 ranking_pre_cut=sum(p.after_ranking.values()).nSig / sum(p.before_ranking.values()).nSig,
79 vertex_pre_cut=sum(p.after_vertex.values()).nSig / sum(p.after_ranking.values()).nSig,
80 absolute_post_cut=p.before_ranking_postcut.nSig / sum(p.after_vertex.values()).nSig,
81 ranking_post_cut=p.after_ranking_postcut.nSig / p.before_ranking_postcut.nSig,
82 after_tag=p.after_tag.nSig / p.after_ranking_postcut.nSig)
85 table = b2latex.LongTable(columnspecs=
r'c|rrrrrr',
86 caption=
'Per-particle nSignal 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:.4e} & {ranking_pre_cut:.4e}'
92 r' & {vertex_pre_cut:.4e} & {absolute_post_cut:.4e}'
93 r' & {ranking_post_cut:.4e} & {after_tag:.4e}')
94 for p
in monitoringParticle:
95 table.add(name=format.decayDescriptor(p.particle.identifier),
96 user_pre_cut=sum(p.before_ranking.values()).nSig,
97 ranking_pre_cut=sum(p.after_ranking.values()).nSig,
98 vertex_pre_cut=sum(p.after_vertex.values()).nSig,
99 absolute_post_cut=p.before_ranking_postcut.nSig,
100 ranking_post_cut=p.after_ranking_postcut.nSig,
101 after_tag=p.after_tag.nSig)
104 table = b2latex.LongTable(columnspecs=
r'c|rrrrrr',
105 caption=
'Per-particle purity before and after the applied pre- and post-cut.',
107 r' & \multicolumn{3}{c}{pre-cut} & \multicolumn{3}{c}{post-cut} \\'
108 r' & user & ranking & vertex '
109 r' & absolute & ranking & unique',
110 format_string=
r'{name} & {user_pre_cut:.3f} & {ranking_pre_cut:.3f}'
111 r' & {vertex_pre_cut:.3f} & {absolute_post_cut:.3f}'
112 r' & {ranking_post_cut:.3f} & {after_tag:.3f}')
114 for p
in monitoringParticle:
115 table.add(name=format.decayDescriptor(p.particle.identifier),
116 user_pre_cut=sum(p.before_ranking.values()).purity,
117 ranking_pre_cut=sum(p.after_ranking.values()).purity,
118 vertex_pre_cut=sum(p.after_vertex.values()).purity,
119 absolute_post_cut=p.before_ranking_postcut.purity,
120 ranking_post_cut=p.after_ranking_postcut.purity,
121 after_tag=p.after_tag.purity)
124 table = b2latex.LongTable(columnspecs=
r'c|rrrrrr',
125 caption=
'Per-particle nBackground before and after the applied pre- and post-cut.',
127 r' & \multicolumn{3}{c}{pre-cut} & \multicolumn{3}{c}{post-cut} \\'
128 r' & user & ranking & vertex '
129 r' & absolute & ranking & unique',
130 format_string=
r'{name} & {user_pre_cut:.4e} & {ranking_pre_cut:.4e}'
131 r' & {vertex_pre_cut:.4e} & {absolute_post_cut:.4e}'
132 r' & {ranking_post_cut:.4e} & {after_tag:.4e}')
133 for p
in monitoringParticle:
134 table.add(name=format.decayDescriptor(p.particle.identifier),
135 user_pre_cut=sum(p.before_ranking.values()).nBg,
136 ranking_pre_cut=sum(p.after_ranking.values()).nBg,
137 vertex_pre_cut=sum(p.after_vertex.values()).nBg,
138 absolute_post_cut=p.before_ranking_postcut.nBg,
139 ranking_post_cut=p.after_ranking_postcut.nBg,
140 after_tag=p.after_tag.nBg)
144 moduleTypes = [
'ParticleCombiner',
'MVAExpert',
'MCMatch',
'ParticleVertexFitter',
'BestCandidateSelection',
'Other']
146 o += b2latex.Section(
"CPU time").finish()
147 colour_list = b2latex.DefineColourList()
148 o += colour_list.finish()
150 for p
in monitoringParticle:
151 o += b2latex.SubSection(format.decayDescriptor(p.particle.identifier)).finish()
153 table = b2latex.LongTable(columnspecs=
r'lrcrr',
154 caption=
'Total CPU time spent in event() calls for each channel. Bars show ' +
155 ', '.join(f
'\\textcolor{{{c}}}{{{m}}}'
156 for c, m
in zip(colour_list.colours, moduleTypes)) +
157 ', in this order. Does not include I/O, initialisation, training, post-cuts etc.',
158 head=
r'Decay & CPU time & by module & per (true) candidate & Relative time ',
159 format_string=
r'{name} & {time} & {bargraph} & {timePerCandidate} & {timePercent:.2f}\% ')
161 tt_channel = sum(p.module_statistic.channel_time.values())
162 tt_particle = p.module_statistic.particle_time + sum(p.module_statistic.channel_time.values())
163 fraction = tt_channel / tt_particle * 100
if tt_particle > 0
else 0.0
165 for channel
in p.particle.channels:
166 time = p.time_per_channel[channel.label]
167 trueCandidates = p.after_classifier[channel.label].nSig
168 allCandidates = p.after_classifier[channel.label].nTotal
170 if trueCandidates == 0
or allCandidates == 0:
173 timePerCandidate = format.duration(time / trueCandidates) +
' (' + format.duration(time / allCandidates) +
')'
176 percents = [p.module_statistic.channel_time_per_module[channel.label].get(key, 0.0) / float(time) * 100.0
177 if time > 0
else 0.0
for key
in moduleTypes[:-1]]
178 percents.append(100.0 - sum(percents))
180 table.add(name=format.decayDescriptor(channel.label),
181 bargraph=
r'\plotbar{ %g/, %g/, %g/, %g/, %g/, %g/, }' % tuple(percents),
182 time=format.duration(time),
183 timePerCandidate=timePerCandidate,
184 timePercent=time / tt_particle * 100
if p.total_time > 0
else 0)
186 o += table.finish(tail=f
'Total & & {format.duration(tt_channel)} / {format.duration(tt_particle)} & & {fraction:.2f}')
188 for p
in monitoringParticle:
189 print(p.particle.identifier)
191 o += b2latex.Section(format.decayDescriptor(p.particle.identifier)).finish()
192 string = b2latex.String(
r"In the reconstruction of {name} {nChannels} out of {max_nChannels} possible channels were used. "
193 r"The covered inclusive / exclusive branching fractions is {inc_br:.5f} / {exc_br:.5f}."
194 r"The final unique efficiency and purity was {eff:.5f} / {pur:.5f}")
196 o += string.finish(name=format.decayDescriptor(p.particle.identifier),
197 nChannels=p.reconstructed_number_of_channels,
198 max_nChannels=p.total_number_of_channels,
199 exc_br=sum(p.exc_br_per_channel.values()),
200 inc_br=sum(p.inc_br_per_channel.values()),
201 eff=p.after_tag.efficiency,
202 pur=p.after_tag.purity)
204 roc_plot_filename = monitoring.removeJPsiSlash(p.particle.identifier +
'_ROC')
205 monitoring.MonitorROCPlot(p, roc_plot_filename)
206 o += b2latex.Graphics().add(roc_plot_filename +
'.png', width=0.8).finish()
208 diag_plot_filename = monitoring.removeJPsiSlash(p.particle.identifier +
'_Diag')
209 monitoring.MonitorDiagPlot(p, diag_plot_filename)
210 o += b2latex.Graphics().add(diag_plot_filename +
'.png', width=0.8).finish()
212 sigprob_plot_filename = monitoring.removeJPsiSlash(p.particle.identifier +
'_SigProb')
213 monitoring.MonitorSigProbPlot(p, sigprob_plot_filename)
214 o += b2latex.Graphics().add(sigprob_plot_filename +
'.png', width=0.8).finish()
216 for spectator
in p.particle.mvaConfig.spectators.keys():
217 money_plot_filename = monitoring.removeJPsiSlash(p.particle.identifier +
'_' + spectator +
'_Money')
218 monitoring.MonitorSpectatorPlot(p, spectator, money_plot_filename, p.particle.mvaConfig.spectators[spectator])
219 g = b2latex.Graphics()
220 for filename
in glob.glob(money_plot_filename +
'_*.png'):
221 g.add(filename, width=0.49)
224 table = b2latex.LongTable(columnspecs=
r'c|rr|rrr',
225 caption=
'Per-channel efficiency before and after the applied pre-cut.',
226 head=
r'Particle & \multicolumn{2}{c}{Covered BR} '
227 r' & \multicolumn{3}{c}{pre-cut} \\'
228 r' & exc & inc & user & ranking & vertex ',
229 format_string=
r'{name} & {exc_br} & {inc_br} & {user_pre_cut:.5f} & '
230 r'{ranking_pre_cut:.5f} & {vertex_pre_cut:.5f}')
232 for channel
in p.particle.channels:
233 table.add(name=format.decayDescriptor(channel.label),
234 exc_br=f
"{p.exc_br_per_channel[channel.label]:.3f}",
235 inc_br=f
"{p.inc_br_per_channel[channel.label]:.3f}",
236 user_pre_cut=p.before_ranking[channel.label].efficiency,
237 ranking_pre_cut=p.after_ranking[channel.label].efficiency,
238 vertex_pre_cut=p.after_vertex[channel.label].efficiency,
239 absolute_post_cut=p.before_ranking_postcut.efficiency,
240 ranking_post_cut=p.after_ranking_postcut.efficiency,
241 after_tag=p.after_tag.efficiency)
245 user_pre_cut=p.before_ranking[channel.label].efficiency,
246 ranking_pre_cut=p.after_ranking[channel.label].nSig / p.before_ranking[channel.label].nSig,
247 vertex_pre_cut=p.after_vertex[channel.label].nSig / p.after_ranking[channel.label].nSig,
248 absolute_post_cut=p.before_ranking_postcut.nSig / p.after_vertex[channel.label].nSig,
249 ranking_post_cut=p.after_ranking_postcut.nSig / p.before_ranking_postcut.nSig,
250 after_tag=p.after_tag.nSig / p.after_ranking_postcut.nSig)
253 table = b2latex.LongTable(columnspecs=
r'c|c|rrr',
254 caption=
'Per-channel purity before and after the applied pre-cut.',
255 head=
r'Particle & Ignored '
256 r' & \multicolumn{3}{c}{pre-cut} \\'
257 r' && user & ranking & vertex ',
258 format_string=
r'{name} & {ignored} & {user_pre_cut:.5f} & {ranking_pre_cut:.5f}'
259 r' & {vertex_pre_cut:.5f}')
261 for channel
in p.particle.channels:
262 table.add(name=format.decayDescriptor(channel.label),
263 ignored=
r'\textcolor{red}{$\blacksquare$}' if p.ignored_channels[channel.label]
else '',
264 user_pre_cut=p.before_ranking[channel.label].purity,
265 ranking_pre_cut=p.after_ranking[channel.label].purity,
266 vertex_pre_cut=p.after_vertex[channel.label].purity)
269 table = b2latex.LongTable(columnspecs=
r'c|rrr',
270 caption=
'Per-channel nSignal before and after the applied pre-cut.',
272 r' & \multicolumn{3}{c}{pre-cut} \\'
273 r' & user & ranking & vertex ',
274 format_string=
r'{name} & {user_pre_cut:.4e} & '
275 r'{ranking_pre_cut:.4e} & {vertex_pre_cut:.4e}')
276 for channel
in p.particle.channels:
277 table.add(name=format.decayDescriptor(channel.label),
278 user_pre_cut=p.before_ranking[channel.label].nSig,
279 ranking_pre_cut=p.after_ranking[channel.label].nSig,
280 vertex_pre_cut=p.after_vertex[channel.label].nSig)
283 table = b2latex.LongTable(columnspecs=
r'c|rrr',
284 caption=
'Per-channel nBackground before and after the applied pre-cut.',
286 r' & \multicolumn{3}{c}{pre-cut} \\'
287 r' & user & ranking & vertex ',
288 format_string=
r'{name} & {user_pre_cut:.4e} & '
289 r'{ranking_pre_cut:.4e} & {vertex_pre_cut:.4e}')
290 for channel
in p.particle.channels:
291 table.add(name=format.decayDescriptor(channel.label),
292 user_pre_cut=p.before_ranking[channel.label].nBg,
293 ranking_pre_cut=p.after_ranking[channel.label].nBg,
294 vertex_pre_cut=p.after_vertex[channel.label].nBg)
297 o.save(output_file, compile=
False)
301if __name__ ==
'__main__':
303 output_file = sys.argv[1]
305 raise AttributeError(
"You have to supply the output tex file.")
307 particles, configuration = monitoring.load_config()
308 cache = configuration.cache
309 stages = get_stages_from_particles(particles)
310 monitoringParticle = []
311 for i
in range(cache):
312 for particle
in particles:
313 if particle
in stages[i]:
314 print(
'FEI: latexReporting: ', i, particle.identifier)
315 monitoringParticle.append(monitoring.MonitoringParticle(particle))
316 create_latex(output_file, monitoringParticle)