2
ReducePySciFiPlot fills Tracker histograms for online reconstruction. It produces histograms of Hits per plane, Spacepoints per station and event displays.
3
It draws them, refreshes the canvases and prints to eps at the end of
6
# This file is part of MAUS: http://micewww.pp.rl.ac.uk:8080/projects/maus
8
# MAUS is free software: you can redistribute it and/or modify
9
# it under the terms of the GNU General Public License as published by
10
# the Free Software Foundation, either version 3 of the License, or
11
# (at your option) any later version.
13
# MAUS is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU General Public License for more details.
18
# You should have received a copy of the GNU General Public License
19
# along with MAUS. If not, see <http://www.gnu.org/licenses/>.
21
# Turn off false positives related to ROOT
22
# pylint: disable = E1101
23
# Disable messages about too many branches and too many lines.
24
# pylint: disable = R0912
25
# pylint: disable = R0915
26
# pylint: disable = C0103, C0301
27
# pylint: disable = W0105, W0612, W0201
30
from ReducePyROOTHistogram import ReducePyROOTHistogram
32
class ReducePySciFiPlot(ReducePyROOTHistogram): # pylint: disable=R0902
34
ReducePySciFiPlot plots several Tracker histograms.
35
Currently the following histograms are filled:
36
Digits per tracker and station,
38
Spacepoints per station
40
Histograms are drawn on different canvases.
41
The canvases are refreshed every N spills where N = refresh_rate
42
set via refresh_rate data card value (see below).
44
The default is to run ROOT in batch mode
45
To run in interactive mode, set root_batch_mode = 0 in the data card
48
At the end of the run, the canvases are printed to eps files
50
A sequence of 3 histograms are output as JSON documents of form:
53
{"image": {"keywords": [...list of image keywords...],
54
"description":"...a description of the image...",
57
"data": "...base 64 encoded image..."}}
60
SciFi, Digits, PE Channel, Spacepoints
62
If "histogram_auto_number" (see below) is "true" then the TAG will
63
have a number N appended where N means that the histogram was
64
produced as a consequence of the (N + 1)th spill processed by the
65
worker. The number will be zero-padded to form a six digit string
66
e.g. "00000N". If "histogram_auto_number" is false then no such
69
In cases where a spill is input that contains errors (e.g. is
70
badly formatted or is missing the data needed to update a
71
histogram) then a spill is output which is just the input spill
72
with an "errors" field containing the error e.g.
75
{"errors": {..., "bad_json_document": "unable to do json.loads on input"}}
76
{"errors": {..., "no_space_points": "no space points"}}
79
The caller can configure the worker and specify:
81
-Image type ("histogram_image_type"). Must be one of those
82
supported by ROOT (currently "ps", "eps", "gif", "jpg", "jpeg",
83
"pdf", "svg", "png"). Default "eps".
84
-Auto-number ("histogram_auto_number"). Default: false. Flag
85
that determines if the image tag (see above) has the spill count
86
appended to it or not.
87
-ROOT batch mode ("root_batch_mode"). Default: 0 (false). Flag
88
indicating whether ROOT should be run in batch or interactive
90
-Refresh rate ("refresh_rate"). Default: 5. Number of spills
91
input before the next set of histograms are output.
96
Set initial attribute values.
97
@param self Object reference.
99
ReducePyROOTHistogram.__init__(self)
100
# Do initialisation specific to this class.
101
# Refresh_rate determines how often (in spill counts) the
102
# canvases are updated.
103
self.refresh_rate = 5
104
# Histogram initializations. they are defined explicitly in
107
self.ScifiDigitT1 = None
108
self.SciFiDigitT2 = None
109
self.SciFiPEperChannelT1S1 = None
110
self.SciFiPEperChannelT1S2 = None
111
self.SciFiPEperChannelT1S3 = None
112
self.SciFiPEperChannelT1S4 = None
113
self.SciFiPEperChannelT1S5 = None
114
self.SciFiPEperChannelT2S1 = None
115
self.SciFiPEperChannelT2S2 = None
116
self.SciFiPEperChannelT2S3 = None
117
self.SciFiPEperChannelT2S4 = None
118
self.SciFiPEperChannelT2S5 = None
119
self.SciFiSpacepointsT1 = None
120
self.SciFiSpacepointsT2 = None
122
self.canvas_SciFiDigit = None
123
self.canvas_SciFiPEperChannel = None
124
self.canvas_SciFiSpacepoints = None
126
# Has an end_of_run been processed?
127
self.run_ended = False
129
def _configure_at_birth(self, config_doc):
131
Configure worker from data cards. Overrides super-class method.
132
@param self Object reference.
133
@param config_doc JSON document.
134
@returns True if configuration succeeded.
136
# Read in configuration flags and parameters - these will
137
# overwrite whatever defaults were set in __init__.
138
if 'refresh_rate' in config_doc:
139
self.refresh_rate = int(config_doc["refresh_rate"])
140
# Initialize histograms, setup root canvases, and set root
143
self.run_ended = False
146
def _update_histograms(self, spill):
147
"""Update the Histograms """
148
if not spill.has_key("daq_event_type"):
149
raise ValueError("No event type")
150
if spill["daq_event_type"] == "end_of_run":
151
if (not self.run_ended):
153
self.run_ended = True
154
return self.get_histogram_images()
158
# do not try to get data from start/end spill markers
159
if spill["daq_event_type"] == "start_of_run" \
160
or spill["daq_event_type"] == "start_of_burst" \
161
or spill["daq_event_type"] == "end_of_burst":
164
# Get SciFi digits & fill the relevant histograms.
165
if not self.get_SciFiDigits(spill):
166
raise ValueError("SciFi digits not in spill")
168
# Get SciFi spacepoints & fill the relevant histograms.
169
if not self.get_SciFiSpacepoints(spill):
170
raise ValueError("SciFi spacepoints not in spill")
172
# Refresh canvases at requested frequency.
173
#print self.refresh_rate
174
if self.spill_count % self.refresh_rate == 0:
176
return self.get_histogram_images()
180
def get_SciFiDigits(self, spill):
183
Get the SciFiDigits and update the histograms.
185
@param self Object reference.
186
@param spill Current spill.
187
@return True if no errors or False if no "digits" in
190
if 'recon_events' not in spill:
191
raise ValueError("recon_events not in spill")
192
# print 'nevt = ', len(spill['recon_events']), spill['recon_events']
193
for event in range(len(spill['recon_events'])):
194
if 'sci_fi_event' not in spill['recon_events'][event]:
195
#print 'no scifi event'
198
# Return if we cannot find sci fi digits in the spill.
200
spill['recon_events'][event]['sci_fi_event']:
204
If the tracker number = 0 fill ScifiDigitT1 with station Number
205
and likewise for tracker 2.
207
# Gives information on cabling efficiency
208
SciFiDigits = spill['recon_events'][event]['sci_fi_event']['digits']
209
for i in range(len(SciFiDigits)):
210
#print SciFiDigits[i]['tracker']
211
if (SciFiDigits[i]['tracker'] == 0):
212
self.ScifiDigitT1.Fill(SciFiDigits[i]['station'])
213
if (SciFiDigits[i]['tracker'] == 1):
214
self.SciFiDigitT2.Fill(SciFiDigits[i]['station'])
216
# Gives information on fibre performance
217
for i in range(len(SciFiDigits)):
218
#print SciFiDigits[i]['tracker']
219
if (SciFiDigits[i]['tracker'] == 0):
220
#print SciFiDigits[i]['npe']
221
#print SciFiDigits[i]['channel']
222
if (SciFiDigits[i]['station'] == 1):
223
self.SciFiPEperChannelT1S1.Fill(SciFiDigits[i]['channel'], \
224
SciFiDigits[i]['npe'])
225
if (SciFiDigits[i]['station'] == 2):
226
self.SciFiPEperChannelT1S2.Fill(SciFiDigits[i]['channel'], \
227
SciFiDigits[i]['npe'])
228
if (SciFiDigits[i]['station'] == 3):
229
self.SciFiPEperChannelT1S3.Fill(SciFiDigits[i]['channel'], \
230
SciFiDigits[i]['npe'])
231
if (SciFiDigits[i]['station'] == 4):
232
self.SciFiPEperChannelT1S4.Fill(SciFiDigits[i]['channel'], \
233
SciFiDigits[i]['npe'])
234
if (SciFiDigits[i]['station'] == 5):
235
self.SciFiPEperChannelT1S5.Fill(SciFiDigits[i]['channel'], \
236
SciFiDigits[i]['npe'])
237
if (SciFiDigits[i]['tracker'] == 1):
238
if (SciFiDigits[i]['station'] == 1):
239
self.SciFiPEperChannelT2S1.Fill(SciFiDigits[i]['channel'], \
240
SciFiDigits[i]['npe'])
241
if (SciFiDigits[i]['station'] == 2):
242
self.SciFiPEperChannelT2S2.Fill(SciFiDigits[i]['channel'], \
243
SciFiDigits[i]['npe'])
244
if (SciFiDigits[i]['station'] == 3):
245
self.SciFiPEperChannelT2S3.Fill(SciFiDigits[i]['channel'], \
246
SciFiDigits[i]['npe'])
247
if (SciFiDigits[i]['station'] == 4):
248
self.SciFiPEperChannelT2S4.Fill(SciFiDigits[i]['channel'], \
249
SciFiDigits[i]['npe'])
250
if (SciFiDigits[i]['station'] == 5):
251
self.SciFiPEperChannelT2S5.Fill(SciFiDigits[i]['channel'], \
252
SciFiDigits[i]['npe'])
256
# Gives information on reconstruction efficiency
257
def get_SciFiSpacepoints(self, spill):
260
Get the SciFiDigits and update the histograms.
262
@param self Object reference.
263
@param spill Current spill.
264
@return True if no errors or False if no "digits" in
267
if 'recon_events' not in spill:
268
raise ValueError("recon_events not in spill")
269
# print 'nevt = ', len(spill['recon_events']), spill['recon_events']
270
for event in range(len(spill['recon_events'])):
271
if 'sci_fi_event' not in spill['recon_events'][event]:
272
#print 'no scifi event'
275
# Return if we cannot find sci fi digits in the spill.
276
if 'spacepoints' not in \
277
spill['recon_events'][event]['sci_fi_event']:
280
'''If the tracker number =0 fill SciFiSpacepointsT1 with station Number
281
and likewise for tracker 2.'''
282
SciFiSpacepoints = spill['recon_events'][event]['sci_fi_event']['spacepoints']
283
for i in range(len(SciFiSpacepoints)):
284
print SciFiSpacepoints[i]['tracker']
285
if (SciFiSpacepoints[i]['tracker'] == 0):
286
self.SciFiSpacepointsT1.Fill(SciFiSpacepoints[i]['station'])
287
if (SciFiSpacepoints[i]['tracker'] == 1):
288
self.SciFiSpacepointsT2.Fill(SciFiSpacepoints[i]['station'])
292
def __init_histos(self): #pylint: disable=R0201, R0914
294
Initialise ROOT to display histograms.
295
@param self Object reference.
298
self.cnv = ROOT.gROOT.SetStyle("Plain")
301
self.style = ROOT.gStyle.SetOptStat(0)
303
#sensible color palette
304
self.style = ROOT.gStyle.SetPalette(1)
307
self.ScifiDigitT1 = ROOT.TH1F("h1", "SciFi Digits in Tracker 1", 100, 0, 6)
308
self.ScifiDigitT1.SetTitle("SciFi Digits Tracker 1")
309
self.ScifiDigitT1.GetXaxis().SetTitle("Stations")
310
self.ScifiDigitT1.GetYaxis().SetTitle("Number of digits")
311
self.SciFiDigitT2 = ROOT.TH1F("h1", "SciFi Digits in Tracker 2", 100, 0, 6)
312
self.SciFiDigitT2.SetTitle("SciFi Digits Tracker 2")
313
self.SciFiDigitT2.GetXaxis().SetTitle("Stations")
314
self.SciFiDigitT2.GetYaxis().SetTitle("Number of digits")
316
self.SciFiPEperChannelT1S1 = ROOT.TH1F("h1", "SciFi Digits: pe per channel in Station 1 Tracker 1", 215, 0, 215)
317
self.SciFiPEperChannelT1S1.SetTitle("SciFi Digits: pe per channel in Station 1 in Tracker 1")
318
self.SciFiPEperChannelT1S1.GetXaxis().SetTitle("Channel number")
319
#self.SciFiPEperChannelT1S1.GetYaxis().SetTitleOffset(0.0)
320
self.SciFiPEperChannelT1S1.GetYaxis().SetTitle("Number of pe")
321
self.SciFiPEperChannelT1S2 = ROOT.TH1F("h1", "SciFi Digits: pe per channel in Station 2 Tracker 1", 215, 0, 215)
322
self.SciFiPEperChannelT1S2.SetTitle("SciFi Digits: pe per channel in Station 2 in Tracker 1")
323
self.SciFiPEperChannelT1S2.GetXaxis().SetTitle("Channel number")
324
self.SciFiPEperChannelT1S2.GetYaxis().SetTitle("Number of pe")
325
self.SciFiPEperChannelT1S3 = ROOT.TH1F("h1", "SciFi Digits: pe per channel in Station 3 Tracker 1", 215, 0, 215)
326
self.SciFiPEperChannelT1S3.SetTitle("SciFi Digits: pe per channel in Station 3 in Tracker 1")
327
self.SciFiPEperChannelT1S3.GetXaxis().SetTitle("Channel number")
328
self.SciFiPEperChannelT1S3.GetYaxis().SetTitle("Number of pe")
329
self.SciFiPEperChannelT1S4 = ROOT.TH1F("h1", "SciFi Digits: pe per channel in Station 4 Tracker 1", 215, 0, 215)
330
self.SciFiPEperChannelT1S4.SetTitle("SciFi Digits: pe per channel in Station 4 in Tracker 1")
331
self.SciFiPEperChannelT1S4.GetXaxis().SetTitle("Channel number")
332
self.SciFiPEperChannelT1S4.GetYaxis().SetTitle("Number of pe")
333
self.SciFiPEperChannelT1S5 = ROOT.TH1F("h1", "SciFi Digits: pe per channel in Station 5 Tracker 1", 215, 0, 215)
334
self.SciFiPEperChannelT1S5.SetTitle("SciFi Digits: pe per channel in Station 5 in Tracker 1")
335
self.SciFiPEperChannelT1S5.GetXaxis().SetTitle("Channel number")
336
self.SciFiPEperChannelT1S5.GetYaxis().SetTitle("Number of pe")
338
self.SciFiPEperChannelT2S1 = ROOT.TH1F("h1", "SciFi Digits: pe per channel in Station 1 Tracker 2", 215, 0, 215)
339
self.SciFiPEperChannelT2S1.SetTitle("SciFi Digits: pe per channel in Station 1 in Tracker 2")
340
self.SciFiPEperChannelT2S1.GetXaxis().SetTitle("Channel number")
341
self.SciFiPEperChannelT2S1.GetYaxis().SetTitle("Number of pe")
342
self.SciFiPEperChannelT2S2 = ROOT.TH1F("h1", "SciFi Digits: pe per channel in Station 2 Tracker 2", 215, 0, 215)
343
self.SciFiPEperChannelT2S2.SetTitle("SciFi Digits: pe per channel in Station 2 in Tracker 2")
344
self.SciFiPEperChannelT2S2.GetXaxis().SetTitle("Channel number")
345
self.SciFiPEperChannelT2S2.GetYaxis().SetTitle("Number of pe")
346
self.SciFiPEperChannelT2S3 = ROOT.TH1F("h1", "SciFi Digits: pe per channel in Station 3 Tracker 2", 215, 0, 215)
347
self.SciFiPEperChannelT2S3.SetTitle("SciFi Digits: pe per channel in Station 3 in Tracker 2")
348
self.SciFiPEperChannelT2S3.GetXaxis().SetTitle("Channel number")
349
self.SciFiPEperChannelT2S3.GetYaxis().SetTitle("Number of pe")
350
self.SciFiPEperChannelT2S4 = ROOT.TH1F("h1", "SciFi Digits: pe per channel in Station 4 Tracker 2", 215, 0, 215)
351
self.SciFiPEperChannelT2S4.SetTitle("SciFi Digits: pe per channel in Station 4 in Tracker 2")
352
self.SciFiPEperChannelT2S4.GetXaxis().SetTitle("Channel number")
353
self.SciFiPEperChannelT2S4.GetYaxis().SetTitle("Number of pe")
354
self.SciFiPEperChannelT2S5 = ROOT.TH1F("h1", "SciFi Digits: pe per channel in Station 5 Tracker 2", 215, 0, 215)
355
self.SciFiPEperChannelT2S5.SetTitle("SciFi Digits: pe per channel in Station 5 in Tracker 2")
356
self.SciFiPEperChannelT2S5.GetXaxis().SetTitle("Channel number")
357
self.SciFiPEperChannelT2S5.GetYaxis().SetTitle("Number of pe")
360
self.SciFiSpacepointsT1 = ROOT.TH1F("h1", "SciFi Spacepoints in Tracker 1", 100, 0, 6)
361
self.SciFiSpacepointsT1.SetTitle("SciFi Spacepoints Tracker 1")
362
self.SciFiSpacepointsT1.GetXaxis().SetTitle("Stations")
363
self.SciFiSpacepointsT1.GetYaxis().SetTitle("Number of spacepoints")
364
self.SciFiSpacepointsT2 = ROOT.TH1F("h1", "SciFi Spacepoints in Tracker 2", 100, 0, 6)
365
self.SciFiSpacepointsT2.SetTitle("SciFi Spacepoints Tracker 2")
366
self.SciFiSpacepointsT2.GetXaxis().SetTitle("Stations")
367
self.SciFiSpacepointsT2.GetYaxis().SetTitle("Number of spacepoints")
370
# Draw() of histos has to be done only once
371
# for updating the histograms, just Modified() and Update() on canvases
372
# the update/refresh is done in update_histos()
374
self.canvas_SciFiDigit = ROOT.TCanvas("SciFiDigit", "SciFiDigit")
375
self.canvas_SciFiDigit.SetTitle("x")
376
self.canvas_SciFiDigit.Divide(2, 1)
377
self.canvas_SciFiDigit.cd(1)
378
self.ScifiDigitT1.Draw()
379
self.canvas_SciFiDigit.cd(2)
380
self.SciFiDigitT2.Draw()
382
self.canvas_SciFiPEperChannel = ROOT.TCanvas("SciFiPEperChannel", "SciFiPEperChannel")
383
self.canvas_SciFiPEperChannel.Divide(5, 2)
384
self.canvas_SciFiPEperChannel.cd(1)
385
self.SciFiPEperChannelT1S1.Draw()
386
self.canvas_SciFiPEperChannel.cd(2)
387
self.SciFiPEperChannelT1S2.Draw()
388
self.canvas_SciFiPEperChannel.cd(3)
389
self.SciFiPEperChannelT1S3.Draw()
390
self.canvas_SciFiPEperChannel.cd(4)
391
self.SciFiPEperChannelT1S4.Draw()
392
self.canvas_SciFiPEperChannel.cd(5)
393
self.SciFiPEperChannelT1S5.Draw()
394
self.canvas_SciFiPEperChannel.cd(6)
395
self.SciFiPEperChannelT2S1.Draw()
396
self.canvas_SciFiPEperChannel.cd(7)
397
self.SciFiPEperChannelT2S2.Draw()
398
self.canvas_SciFiPEperChannel.cd(8)
399
self.SciFiPEperChannelT2S3.Draw()
400
self.canvas_SciFiPEperChannel.cd(9)
401
self.SciFiPEperChannelT2S4.Draw()
402
self.canvas_SciFiPEperChannel.cd(10)
403
self.SciFiPEperChannelT2S5.Draw()
405
self.canvas_SciFiSpacepoints = ROOT.TCanvas("SciFiSpacepoints", "SciFiSpacepoints")
406
self.canvas_SciFiSpacepoints.Divide(2, 1)
407
self.canvas_SciFiSpacepoints.cd(1)
408
self.SciFiSpacepointsT1.Draw()
409
self.canvas_SciFiSpacepoints.cd(2)
410
self.SciFiSpacepointsT2.Draw()
414
def update_histos(self):
416
Updates histogram canvases. This is called only when the
417
number of spills is divisible by the refresh rate.
418
@param self Object reference.
421
self.canvas_SciFiDigit.Update()
422
self.canvas_SciFiPEperChannel.Update()
423
self.canvas_SciFiSpacepoints.Update()
425
def get_histogram_images(self):
427
Get histograms as JSON documents.
428
@returns list of 1 JSON document containing the images.
435
keywords = ["SciFi", "Digits"]
436
description = "SciFi"
437
doc = ReducePyROOTHistogram.get_image_doc( \
438
self, keywords, description, tag, self.canvas_SciFiDigit)
439
image_list.append(doc)
443
tag = "SciFi_PEperChannel"
444
keywords = ["SciFi", "PE", "Channel"]
445
description = "SciFi"
446
doc = ReducePyROOTHistogram.get_image_doc( \
447
self, keywords, description, tag, self.canvas_SciFiPEperChannel)
448
image_list.append(doc)
450
# Spacepoints per station
451
tag = "SciFi_Spacepoints"
452
keywords = ["SciFi", "Spacepoints"]
453
description = "SciFi"
454
doc = ReducePyROOTHistogram.get_image_doc( \
455
self, keywords, description, tag, self.canvas_SciFiSpacepoints)
456
image_list.append(doc)
460
def _cleanup_at_death(self):
462
Reinitialise histograms at death and print out new (empty) images
465
self.get_histogram_images()