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
26from B2Tools
import b2latex
27from B2Tools
import format
33def create_latex(output_file, monitoringParticle):
35 o = b2latex.LatexFile()
37 o += b2latex.TitlePage(title=
'Full Event Interpretation Report',
38 authors=[
'Thomas Keck',
'Christian Pulvermacher',
'William Sutcliffe'],
40 This report contains key performance indicators and control plots of the Full Event Interpretation.
41 The pre-, and post-cuts as well as trained multivariate selection methods are described.
42 Furthermore the resulting purities and efficiencies are stated.
44 add_table_of_contents=
True).finish()
46 o += b2latex.Section(
"Summary").finish()
47 o += b2latex.String(
r"""
48 For each decay channel of each particle a multivariate selection method is trained after applying
49 a fast pre-cut on the candidates. Afterwards, a post-cut is applied on the signal probability calculated by the method.
50 This reduces combinatorics in the following stages of the Full
54 table = b2latex.LongTable(columnspecs=
r'c|rr|rrrrrr',
55 caption=
'Per-particle efficiency before and after the applied pre- and post-cut.',
56 head=
r'Particle & \multicolumn{2}{c}{Covered BR} '
57 r' & \multicolumn{3}{c}{pre-cut} & \multicolumn{3}{c}{post-cut} \\'
58 r' & exc & inc & user & ranking & vertex '
59 r' & absolute & ranking & unique',
60 format_string=
r'{name} & {exc_br} & {inc_br} & {user_pre_cut:.3f} & {ranking_pre_cut:.3f}'
61 r' & {vertex_pre_cut:.3f} & {absolute_post_cut:.3f}'
62 r' & {ranking_post_cut:.3f} & {after_tag:.3f}')
63 for p
in monitoringParticle:
64 table.add(name=format.decayDescriptor(p.particle.identifier),
65 exc_br=f
"{sum(p.exc_br_per_channel.values()):.3f}",
66 inc_br=f
"{sum(p.inc_br_per_channel.values()):.3f}",
67 user_pre_cut=sum(p.before_ranking.values()).efficiency,
68 ranking_pre_cut=sum(p.after_ranking.values()).efficiency,
69 vertex_pre_cut=sum(p.after_vertex.values()).efficiency,
70 absolute_post_cut=p.before_ranking_postcut.efficiency,
71 ranking_post_cut=p.after_ranking_postcut.efficiency,
72 after_tag=p.after_tag.efficiency)
76 user_pre_cut=sum(p.before_ranking.values()).efficiency,
77 ranking_pre_cut=sum(p.after_ranking.values()).nSig / sum(p.before_ranking.values()).nSig,
78 vertex_pre_cut=sum(p.after_vertex.values()).nSig / sum(p.after_ranking.values()).nSig,
79 absolute_post_cut=p.before_ranking_postcut.nSig / sum(p.after_vertex.values()).nSig,
80 ranking_post_cut=p.after_ranking_postcut.nSig / p.before_ranking_postcut.nSig,
81 after_tag=p.after_tag.nSig / p.after_ranking_postcut.nSig)
84 table = b2latex.LongTable(columnspecs=
r'c|rrrrrr',
85 caption=
'Per-particle nSignal before and after the applied pre- and post-cut.',
87 r' & \multicolumn{3}{c}{pre-cut} & \multicolumn{3}{c}{post-cut} \\'
88 r' & user & ranking & vertex '
89 r' & absolute & ranking & unique',
90 format_string=
r'{name} & {user_pre_cut:.4e} & {ranking_pre_cut:.4e}'
91 r' & {vertex_pre_cut:.4e} & {absolute_post_cut:.4e}'
92 r' & {ranking_post_cut:.4e} & {after_tag:.4e}')
93 for p
in monitoringParticle:
94 table.add(name=format.decayDescriptor(p.particle.identifier),
95 user_pre_cut=sum(p.before_ranking.values()).nSig,
96 ranking_pre_cut=sum(p.after_ranking.values()).nSig,
97 vertex_pre_cut=sum(p.after_vertex.values()).nSig,
98 absolute_post_cut=p.before_ranking_postcut.nSig,
99 ranking_post_cut=p.after_ranking_postcut.nSig,
100 after_tag=p.after_tag.nSig)
103 table = b2latex.LongTable(columnspecs=
r'c|rrrrrr',
104 caption=
'Per-particle purity before and after the applied pre- and post-cut.',
106 r' & \multicolumn{3}{c}{pre-cut} & \multicolumn{3}{c}{post-cut} \\'
107 r' & user & ranking & vertex '
108 r' & absolute & ranking & unique',
109 format_string=
r'{name} & {user_pre_cut:.3f} & {ranking_pre_cut:.3f}'
110 r' & {vertex_pre_cut:.3f} & {absolute_post_cut:.3f}'
111 r' & {ranking_post_cut:.3f} & {after_tag:.3f}')
113 for p
in monitoringParticle:
114 table.add(name=format.decayDescriptor(p.particle.identifier),
115 user_pre_cut=sum(p.before_ranking.values()).purity,
116 ranking_pre_cut=sum(p.after_ranking.values()).purity,
117 vertex_pre_cut=sum(p.after_vertex.values()).purity,
118 absolute_post_cut=p.before_ranking_postcut.purity,
119 ranking_post_cut=p.after_ranking_postcut.purity,
120 after_tag=p.after_tag.purity)
123 table = b2latex.LongTable(columnspecs=
r'c|rrrrrr',
124 caption=
'Per-particle nBackground before and after the applied pre- and post-cut.',
126 r' & \multicolumn{3}{c}{pre-cut} & \multicolumn{3}{c}{post-cut} \\'
127 r' & user & ranking & vertex '
128 r' & absolute & ranking & unique',
129 format_string=
r'{name} & {user_pre_cut:.4e} & {ranking_pre_cut:.4e}'
130 r' & {vertex_pre_cut:.4e} & {absolute_post_cut:.4e}'
131 r' & {ranking_post_cut:.4e} & {after_tag:.4e}')
132 for p
in monitoringParticle:
133 table.add(name=format.decayDescriptor(p.particle.identifier),
134 user_pre_cut=sum(p.before_ranking.values()).nBg,
135 ranking_pre_cut=sum(p.after_ranking.values()).nBg,
136 vertex_pre_cut=sum(p.after_vertex.values()).nBg,
137 absolute_post_cut=p.before_ranking_postcut.nBg,
138 ranking_post_cut=p.after_ranking_postcut.nBg,
139 after_tag=p.after_tag.nBg)
143 moduleTypes = [
'ParticleCombiner',
'MVAExpert',
'MCMatch',
'ParticleVertexFitter',
'BestCandidateSelection',
'Other']
145 o += b2latex.Section(
"CPU time").finish()
146 colour_list = b2latex.DefineColourList()
147 o += colour_list.finish()
149 for p
in monitoringParticle:
150 o += b2latex.SubSection(format.decayDescriptor(p.particle.identifier)).finish()
152 table = b2latex.LongTable(columnspecs=
r'lrcrr',
153 caption=
'Total CPU time spent in event() calls for each channel. Bars show ' +
154 ', '.join(f
'\\textcolor{{{c}}}{{{m}}}'
155 for c, m
in zip(colour_list.colours, moduleTypes)) +
156 ', in this order. Does not include I/O, initialisation, training, post-cuts etc.',
157 head=
r'Decay & CPU time & by module & per (true) candidate & Relative time ',
158 format_string=
r'{name} & {time} & {bargraph} & {timePerCandidate} & {timePercent:.2f}\% ')
160 tt_channel = sum(p.module_statistic.channel_time.values())
161 tt_particle = p.module_statistic.particle_time + sum(p.module_statistic.channel_time.values())
162 fraction = tt_channel / tt_particle * 100
if tt_particle > 0
else 0.0
164 for channel
in p.particle.channels:
165 time = p.time_per_channel[channel.label]
166 trueCandidates = p.after_classifier[channel.label].nSig
167 allCandidates = p.after_classifier[channel.label].nTotal
169 if trueCandidates == 0
or allCandidates == 0:
172 timePerCandidate = format.duration(time / trueCandidates) +
' (' + format.duration(time / allCandidates) +
')'
175 percents = [p.module_statistic.channel_time_per_module[channel.label].get(key, 0.0) / float(time) * 100.0
176 if time > 0
else 0.0
for key
in moduleTypes[:-1]]
177 percents.append(100.0 - sum(percents))
179 table.add(name=format.decayDescriptor(channel.label),
180 bargraph=
r'\plotbar{ %g/, %g/, %g/, %g/, %g/, %g/, }' % tuple(percents),
181 time=format.duration(time),
182 timePerCandidate=timePerCandidate,
183 timePercent=time / tt_particle * 100
if p.total_time > 0
else 0)
185 o += table.finish(tail=f
'Total & & {format.duration(tt_channel)} / {format.duration(tt_particle)} & & {fraction:.2f}')
187 for p
in monitoringParticle:
188 print(p.particle.identifier)
190 o += b2latex.Section(format.decayDescriptor(p.particle.identifier)).finish()
191 string = b2latex.String(
r"In the reconstruction of {name} {nChannels} out of {max_nChannels} possible channels were used. "
192 r"The covered inclusive / exclusive branching fractions is {inc_br:.5f} / {exc_br:.5f}."
193 r"The final unique efficiency and purity was {eff:.5f} / {pur:.5f}")
195 o += string.finish(name=format.decayDescriptor(p.particle.identifier),
196 nChannels=p.reconstructed_number_of_channels,
197 max_nChannels=p.total_number_of_channels,
198 exc_br=sum(p.exc_br_per_channel.values()),
199 inc_br=sum(p.inc_br_per_channel.values()),
200 eff=p.after_tag.efficiency,
201 pur=p.after_tag.purity)
203 roc_plot_filename = monitoring.removeJPsiSlash(p.particle.identifier +
'_ROC')
204 monitoring.MonitorROCPlot(p, roc_plot_filename)
205 o += b2latex.Graphics().add(roc_plot_filename +
'.png', width=0.8).finish()
207 diag_plot_filename = monitoring.removeJPsiSlash(p.particle.identifier +
'_Diag')
208 monitoring.MonitorDiagPlot(p, diag_plot_filename)
209 o += b2latex.Graphics().add(diag_plot_filename +
'.png', width=0.8).finish()
211 sigprob_plot_filename = monitoring.removeJPsiSlash(p.particle.identifier +
'_SigProb')
212 monitoring.MonitorSigProbPlot(p, sigprob_plot_filename)
213 o += b2latex.Graphics().add(sigprob_plot_filename +
'.png', width=0.8).finish()
215 for spectator
in p.particle.mvaConfig.spectators.keys():
216 money_plot_filename = monitoring.removeJPsiSlash(p.particle.identifier +
'_' + spectator +
'_Money')
217 monitoring.MonitorSpectatorPlot(p, spectator, money_plot_filename, p.particle.mvaConfig.spectators[spectator])
218 g = b2latex.Graphics()
219 for filename
in glob.glob(money_plot_filename +
'_*.png'):
220 g.add(filename, width=0.49)
223 table = b2latex.LongTable(columnspecs=
r'c|rr|rrr',
224 caption=
'Per-channel efficiency before and after the applied pre-cut.',
225 head=
r'Particle & \multicolumn{2}{c}{Covered BR} '
226 r' & \multicolumn{3}{c}{pre-cut} \\'
227 r' & exc & inc & user & ranking & vertex ',
228 format_string=
r'{name} & {exc_br} & {inc_br} & {user_pre_cut:.5f} & '
229 r'{ranking_pre_cut:.5f} & {vertex_pre_cut:.5f}')
231 for channel
in p.particle.channels:
232 table.add(name=format.decayDescriptor(channel.label),
233 exc_br=f
"{p.exc_br_per_channel[channel.label]:.3f}",
234 inc_br=f
"{p.inc_br_per_channel[channel.label]:.3f}",
235 user_pre_cut=p.before_ranking[channel.label].efficiency,
236 ranking_pre_cut=p.after_ranking[channel.label].efficiency,
237 vertex_pre_cut=p.after_vertex[channel.label].efficiency,
238 absolute_post_cut=p.before_ranking_postcut.efficiency,
239 ranking_post_cut=p.after_ranking_postcut.efficiency,
240 after_tag=p.after_tag.efficiency)
244 user_pre_cut=p.before_ranking[channel.label].efficiency,
245 ranking_pre_cut=p.after_ranking[channel.label].nSig / p.before_ranking[channel.label].nSig,
246 vertex_pre_cut=p.after_vertex[channel.label].nSig / p.after_ranking[channel.label].nSig,
247 absolute_post_cut=p.before_ranking_postcut.nSig / p.after_vertex[channel.label].nSig,
248 ranking_post_cut=p.after_ranking_postcut.nSig / p.before_ranking_postcut.nSig,
249 after_tag=p.after_tag.nSig / p.after_ranking_postcut.nSig)
252 table = b2latex.LongTable(columnspecs=
r'c|c|rrr',
253 caption=
'Per-channel purity before and after the applied pre-cut.',
254 head=
r'Particle & Ignored '
255 r' & \multicolumn{3}{c}{pre-cut} \\'
256 r' && user & ranking & vertex ',
257 format_string=
r'{name} & {ignored} & {user_pre_cut:.5f} & {ranking_pre_cut:.5f}'
258 r' & {vertex_pre_cut:.5f}')
260 for channel
in p.particle.channels:
261 table.add(name=format.decayDescriptor(channel.label),
262 ignored=
r'\textcolor{red}{$\blacksquare$}' if p.ignored_channels[channel.label]
else '',
263 user_pre_cut=p.before_ranking[channel.label].purity,
264 ranking_pre_cut=p.after_ranking[channel.label].purity,
265 vertex_pre_cut=p.after_vertex[channel.label].purity)
268 table = b2latex.LongTable(columnspecs=
r'c|rrr',
269 caption=
'Per-channel nSignal before and after the applied pre-cut.',
271 r' & \multicolumn{3}{c}{pre-cut} \\'
272 r' & user & ranking & vertex ',
273 format_string=
r'{name} & {user_pre_cut:.4e} & '
274 r'{ranking_pre_cut:.4e} & {vertex_pre_cut:.4e}')
275 for channel
in p.particle.channels:
276 table.add(name=format.decayDescriptor(channel.label),
277 user_pre_cut=p.before_ranking[channel.label].nSig,
278 ranking_pre_cut=p.after_ranking[channel.label].nSig,
279 vertex_pre_cut=p.after_vertex[channel.label].nSig)
282 table = b2latex.LongTable(columnspecs=
r'c|rrr',
283 caption=
'Per-channel nBackground before and after the applied pre-cut.',
285 r' & \multicolumn{3}{c}{pre-cut} \\'
286 r' & user & ranking & vertex ',
287 format_string=
r'{name} & {user_pre_cut:.4e} & '
288 r'{ranking_pre_cut:.4e} & {vertex_pre_cut:.4e}')
289 for channel
in p.particle.channels:
290 table.add(name=format.decayDescriptor(channel.label),
291 user_pre_cut=p.before_ranking[channel.label].nBg,
292 ranking_pre_cut=p.after_ranking[channel.label].nBg,
293 vertex_pre_cut=p.after_vertex[channel.label].nBg)
296 o.save(output_file, compile=
False)
299if __name__ ==
'__main__':
301 output_file = sys.argv[1]
303 raise AttributeError(
"You have to supply the output tex file.")
305 particles, configuration = monitoring.load_config()
306 monitoringParticle = []
307 for particle
in particles:
308 monitoringParticle.append(monitoring.MonitoringParticle(particle))
309 create_latex(output_file, monitoringParticle)