Belle II Software development
attributemaps.py
1#!/usr/bin/env python3
2
3
10
11from ROOT import gSystem
12
13from ROOT import Belle2 # make Belle2 namespace available
14
15import bisect
16import colorsys
17
18gSystem.Load('libframework') # for PyStoreArray
19gSystem.Load('libcdc') # for CDCSimHit
20gSystem.Load('libtracking') # for CDCWire and so on
21gSystem.Load('libgenfit2') # for GFTrackCands
22gSystem.Load('libdataobjects')
23# Standard color map for id types
24listColors = [ # 'magenta',
25 # 'gold',
26 # 'yellow',
27 # 'aquamarine',
28 'red',
29 'blue',
30 'green',
31 'orange',
32 'cyan',
33 'olive',
34 'lime',
35 'maroon',
36 'tomato',
37 'turquoise',
38 'mediumspringgreen',
39 'darkgreen',
40 'indigo',
41]
42
43
44def timeOfFlightToColor(timeOfFlight):
45 """
46 Translates the given floating point time of flight to a color.
47 """
48
49 # values are all fractions of their respective scale
50
51 # Full color circle in 3 nanoseconds
52 hue = 360 / 3.0 * timeOfFlight % 360.0 / 360.0
53 saturation = 0.75
54 lightness = 0.5
55
56 (red, green, blue) = colorsys.hls_to_rgb(hue, lightness, saturation)
57
58 color = f'rgb({red:.2%}, {green:.2%}, {blue:.2%})'
59 return color
60
61
62def inTrackIdToColor(inTrackId):
63 """
64 Translates the given integer in track id to a color.
65 """
66
67 hue = 50 * inTrackId % 360 / 360.0
68 saturation = 0.75
69 lightness = 0.5
70
71 (red, green, blue) = colorsys.hls_to_rgb(hue, lightness, saturation)
72
73 color = f'rgb({red:.2%}, {green:.2%}, {blue:.2%})'
74 return color
75
76
78
79 """
80 Base class for CDCHit to the stroke width map functional objects.
81 """
82
83 def __call__(self, iCDCHit, cdcHit):
84 """
85 Function call to map the CDCHit id and object to a stroke width.
86 """
87
88 return 0.2
89
90
92
93 """
94 CDCHit to stroke width map highlighting the CDCHits with 0 drift length.
95 """
96
97 def __call__(self, iCDCHit, cdcHit):
98 """
99 Function call to map the CDCHit id and object to a stroke width.
100 """
101
102 wirehit = Belle2.TrackFindingCDC.CDCWireHit(cdcHit)
103 if wirehit.getRefDriftLength() == 0.0:
104 return 1
105 else:
106 return 0.2
107
108
110
111 """
112 Base class for CDCHit to color map functional objects.
113 """
114
115
116 bkgHitColor = 'orange'
117
118 def __call__(self, iCDCHit, cdcHit):
119 """
120 Function call to map the CDCHit id and object to a color.
121 """
122
123 return self.bkgHitColor
124
125
127
128 """
129 CDCHit to color map highlighting the CDCHits with 0 drift length.
130 """
131
132 def __call__(self, iCDCHit, cdcHit):
133 """
134 Function call to map the CDCHit id and object to a color.
135 """
136
137 wirehit = Belle2.TrackFindingCDC.CDCWireHit(cdcHit)
138 if wirehit.getRefDriftLength() == 0.0:
139 return 'red'
140 else:
141 return self.bkgHitColor
142
143
145
146 """
147 CDCHit to color map highlighting the CDCHits that posses the do not use flag.
148 """
149
150 def __init__(self):
151 """Constructor"""
152 super().__init__()
153
154 self.storedWireHits = Belle2.PyStoreObj('CDCWireHitVector')
155 if not self.storedWireHits:
156 print('Could not find CDCWireHitVector in the data store to lookup TakenFlag')
157
158 def __call__(self, iCDCHit, cdcHit):
159 """
160 Function call to map the CDCHit id and object to a color.
161 """
162 if not self.storedWireHits:
163 return self.bkgHitColor
164
165 wireHits = self.storedWireHits.obj().get()
166 # Search the sorted range of wire hits for the one corresponding to the given CDCHit
167 wireHit = wireHits.at(bisect.bisect_left(wireHits, cdcHit))
168 if wireHit.getAutomatonCell().hasTakenFlag():
169 return 'red'
170 else:
171 return self.bkgHitColor
172
173
175
176 """
177 CDCHit to color map by their local right left passage information from Monte Carlo truth
178 """
179
180 def __call__(self, iCDCHit, cdcHit):
181 """
182 Function call to map the CDCHit id and object to a color.
183 """
184
186 rlInfo = mcHitLookUp.getRLInfo(cdcHit)
187 if rlInfo == 1:
188 # Right
189 return 'green'
190 elif rlInfo == -1 or rlInfo == 65535: # <- The root interface mistakes the signed enum value for an unsigned value
191 # Left
192 return 'red'
193 else:
194 self.bkgHitColor
195
196 def __str__(self):
197 """
198 Informal string summarizing the translation from right left passage variable to colors.
199 """
200
201 return 'Local right left passage variable: green <-> right, red <-> left, orange <-> not determinable.'
202
203
205
206 """
207 CDCRecoHit3D to color map for the correctness of the rl information
208 """
209
210 def __init__(self):
211 """Constructor"""
213 mcHitLookUp.fill()
214
215 def __call__(self, iCDCRecoHit, cdcRecoHit3D):
216 """
217 This function maps the cdcRecoHit3D to the color which inidcated the correctness of the rl passage
218 """
219
220 cdcHit = cdcRecoHit3D.getWireHit().getHit()
221
223 rlInfo = mcHitLookUp.getRLInfo(cdcHit)
224
225 if rlInfo == -32768 or rlInfo == 32768: # <- The root interface mistakes the signed enum value for an unsigned value
226 return 'violet'
227 elif rlInfo == cdcRecoHit3D.getRLInfo():
228 return 'green'
229 else:
230 return 'red'
231
232 def __str__(self):
233 """
234 Informal string summarizing the translation from right left passage variable to colors.
235 """
236 return 'Correct RL info: gree, wrong RL info: red'
237
238
240
241 """
242 CDCHit to color map by their assoziated CDCSimHit::getPosFlag property.
243 """
244
245 def __call__(self, iCDCHit, cdcHit):
246 """
247 Function call to map the CDCHit id and object to a color.
248 """
249
250 simHit = cdcHit.getRelated('CDCSimHits')
251 posFlag = simHit.getPosFlag()
252 if posFlag == 0:
253 # Right
254 return 'green'
255 elif posFlag == 1:
256 # Left
257 return 'red'
258 else:
259 self.bkgHitColor
260
261 def __str__(self):
262 """
263 Informal string summarizing the translation from CDCSimHit::getPosFlag variable to colors.
264 """
265
266 return 'PosFlag variable of the related CDCSimHit: green <-> 0 (Right), red <-> 1 (Left), orange <-> determinable.'
267
268
270
271 """
272 CDCHit to color map by their assoziated CDCSimHit::getBackgroundTag property.
273 """
274
275
276 BackgroundMetaData = Belle2.BackgroundMetaData
277
278
279 bkgname_by_bkgtag = {
280 BackgroundMetaData.bg_none: 'bg_none',
281 BackgroundMetaData.bg_Coulomb_LER: 'bg_Coulomb_LER',
282 BackgroundMetaData.bg_Coulomb_HER: 'bg_Coulomb_HER',
283 BackgroundMetaData.bg_RBB_LER: 'bg_RBB_LER',
284 BackgroundMetaData.bg_RBB_HER: 'bg_RBB_HER',
285 BackgroundMetaData.bg_Touschek_LER: 'bg_Touschek_LER',
286 BackgroundMetaData.bg_Touschek_HER: 'bg_Touschek_HER',
287 BackgroundMetaData.bg_twoPhoton: 'bg_twoPhoton',
288 BackgroundMetaData.bg_RBB_gamma: 'bg_RBB_gamma',
289 BackgroundMetaData.bg_RBB_LER_far: 'bg_RBB_LER_far',
290 BackgroundMetaData.bg_RBB_HER_far: 'bg_RBB_HER_far',
291 BackgroundMetaData.bg_Touschek_LER_far: 'bg_Touschek_LER_far',
292 BackgroundMetaData.bg_Touschek_HER_far: 'bg_Touschek_HER_far',
293 BackgroundMetaData.bg_SynchRad_LER: 'bg_SynchRad_LER',
294 BackgroundMetaData.bg_SynchRad_HER: 'bg_SynchRad_HER',
295 BackgroundMetaData.bg_other: 'bg_other',
296 }
297
298
299 color_by_bkgtag = {
300 BackgroundMetaData.bg_none: 'orange',
301 BackgroundMetaData.bg_Coulomb_LER: 'red',
302 BackgroundMetaData.bg_Coulomb_HER: 'darkred',
303 BackgroundMetaData.bg_RBB_LER: 'blue',
304 BackgroundMetaData.bg_RBB_HER: 'darkblue',
305 BackgroundMetaData.bg_Touschek_LER: 'green',
306 BackgroundMetaData.bg_Touschek_HER: 'darkgreen',
307 BackgroundMetaData.bg_twoPhoton: 'violet',
308 BackgroundMetaData.bg_RBB_gamma: 'skyblue',
309 BackgroundMetaData.bg_RBB_LER_far: 'turquoise',
310 BackgroundMetaData.bg_RBB_HER_far: 'darkturquoise',
311 BackgroundMetaData.bg_Touschek_LER_far: 'olivergreen',
312 BackgroundMetaData.bg_Touschek_HER_far: 'darkolivegreen',
313 BackgroundMetaData.bg_SynchRad_LER: 'goldenrod',
314 BackgroundMetaData.bg_SynchRad_HER: 'darkgoldenrod',
315 BackgroundMetaData.bg_other: 'orange',
316 }
317
318 def __call__(self, iCDCHit, cdcHit):
319 """
320 Function call to map the CDCHit id and object to a color.
321 """
322
323 cdcSimHit = cdcHit.getRelated('CDCSimHits')
324 backgroundTag = cdcSimHit.getBackgroundTag()
325
326 color = self.color_by_bkgtag.get(backgroundTag, None)
327
328 if color is None:
329 print(f'Background tag {backgroundTag} not associated with a color.')
330 return 'orange'
331 else:
332 return color
333
334 def __str__(self):
335 """
336 Informal string summarizing the translation from CDCSimHit::getBackgroundTag variable to colors.
337 """
338
339 color_by_bkgname = {}
340
341 for backgroundTag in self.bkgname_by_bkgtag:
342 name = self.bkgname_by_bkgtag[backgroundTag]
343 color = self.color_by_bkgtag[backgroundTag]
344 color_by_bkgname[name] = color
345
346 bkgname_and_color = sorted(color_by_bkgname.items())
347
348 message = f'Background tag color coding is \n{chr(10).join(name + " -> " + color for (name, color) in bkgname_and_color):s}'
349 return message
350
351
353
354 """
355 CDCHit to color map by their Monte Carlo segment id
356 """
357
358 def __call__(self, iCDCHit, cdcHit):
359 """
360 Function call to map the CDCHit id and object to a color.
361 """
362
364 inTrackSegmentId = mcHitLookUp.getInTrackSegmentId(cdcHit)
365
366 if inTrackSegmentId < 0:
367 return self.bkgHitColor
368 else:
369 # values are all fractions of their respective scale
370 hue = 50 * inTrackSegmentId % 360 / 360.0
371 saturation = 0.75
372 lightness = 0.5
373
374 (red, green, blue) = colorsys.hls_to_rgb(hue, lightness,
375 saturation)
376
377 color = f'rgb({red:.2%}, {green:.2%}, {blue:.2%})'
378 return color
379
380
382
383 """
384 CDCHit to color map by their assoziated CDCSimHit::getFlightTime.
385 """
386
387 def __call__(self, iCDCHit, cdcHit):
388 """
389 Function call to map the CDCHit id and object to a color.
390 """
391
392 simHit = cdcHit.getRelated('CDCSimHits')
393 timeOfFlight = simHit.getFlightTime()
394
395 return timeOfFlightToColor(timeOfFlight)
396
397
399
400 """
401 CDCHit to color map indicating the reassignment to a different MCParticle.
402 """
403
404 def __call__(self, iCDCHit, cdcHit):
405 """
406 Function call to map the CDCHit id and object to a color.
407 """
408
409 relatedMCParticles = cdcHit.getRelationsWith('MCParticles')
410 if relatedMCParticles.size() == 0:
411 return self.bkgHitColor
412 else:
413 mcRelationWeight = relatedMCParticles.weight(0)
414 if mcRelationWeight > 0:
415 return 'green'
416 else:
417 return 'red'
418
419
421
422 """
423 CDCHit to color map coloring by the assoziated MCParticle::getArrayIndex()
424 """
425
426 def __init__(self):
427 """
428 Construction method setting up a Monte Carlo id to color dictionary which is continously filled
429 as new during the event.
430 """
431
432
434
435 def __call__(self, iCDCHit, cdcHit):
436 """
437 Function call to map the CDCHit id and object to a color.
438 """
439
440 mcParticle = cdcHit.getRelated('MCParticles')
441 if mcParticle:
442 mcParticleId = mcParticle.getArrayIndex()
443 else:
444 mcParticleId = -1
445
446 # cdcSimHit = cdcHit.getRelated("CDCSimHits")
447 # if cdcSimHit:
448 # cdcSimHitTrackId = cdcSimHit.getTrackId()
449 # else:
450 # cdcSimHitTrackId = -1
451
452 if mcParticleId in self.color_by_mcparticleId:
453 color = self.color_by_mcparticleId[mcParticleId]
454 else:
455 iColor = len(self.color_by_mcparticleId)
456 iColor = iColor % len(listColors)
457 color = listColors[iColor]
458 self.color_by_mcparticleId[mcParticleId] = color
459
460 return color
461
462
464
465 """
466 CDCHit to color map by the assoziated MCParticle::getPDG()
467 """
468
469
470 color_by_pdgcode = {
471 -999: CDCHitColorMap.bkgHitColor,
472 11: 'blue',
473 -11: 'blue',
474 13: 'turquoise',
475 -13: 'turquoise',
476 15: 'cyan',
477 -15: 'cyan',
478 211: 'green',
479 -211: 'green',
480 321: 'olive',
481 -321: 'olive',
482 2212: 'red',
483 -2212: 'red',
484 }
485
486
487 missing_pdg_color = 'lime'
488
489 def __call__(self, iCDCHit, cdcHit):
490 """
491 Function call to map the CDCHit id and object to a color.
492 """
493
494 mcParticle = cdcHit.getRelated('MCParticles')
495 if mcParticle:
496 pdgcode = mcParticle.getPDG()
497 else:
498
499 # getSecondaryPhysicsProcess()
500 pdgcode = -999
501
502 if pdgcode in self.color_by_pdgcode:
503 color = self.color_by_pdgcode[pdgcode]
504 else:
505 print('Unknown PDG code', pdgcode)
506 color = self.missing_pdg_color
507
508 return color
509
510 def __str__(self):
511 """
512 Informal string summarizing the translation from pdg codes to colors.
513 """
514
515 legend_head = 'Legend:\n'
516
517 pdg_code_by_color = {}
518
519 for (pdgcode, color) in list(self.color_by_pdgcode.items()):
520 pdg_code_by_color.setdefault(color, [])
521 pdg_code_by_color[color].append(pdgcode)
522
523 legend_content = '\n'.join(str(color) + '->' + str(pdg_code_by_color[color])
524 for color in pdg_code_by_color)
525
526 return legend_head + legend_content
527
528
530
531 """
532 CDCHit to color map by the isPrimary information as well as the secondary process type in case the particle is not primary.
533 """
534
535 def __init__(self):
536 """
537 Constuction method setting up a dictionary to count the hits for each secondary type.
538 """
539
540
542
543 def __call__(self, iCDCHit, cdcHit):
544 """
545 Function call to map the CDCHit id and object to a color.
546 """
547
548 mcParticle = cdcHit.getRelated('MCParticles')
549 if mcParticle:
550 primaryFlag = 1
551 isPrimary = mcParticle.hasStatus(primaryFlag)
552 secondaryProcess = mcParticle.getSecondaryPhysicsProcess()
553 if secondaryProcess > 0:
554 motherMCParticle = mcParticle.getMother()
555 secondary_type = (motherMCParticle.getPDG(),
556 mcParticle.getPDG())
557 else:
558 motherMCParticle = None
559 secondary_type = (-999, mcParticle.getPDG())
560
561 self.n_hits_by_secondary_type.setdefault(secondary_type, 0)
562 self.n_hits_by_secondary_type[secondary_type] = \
563 self.n_hits_by_secondary_type[secondary_type] + 1
564 if isPrimary:
565 return 'blue'
566 elif secondaryProcess > 200:
567 # decay in flight
568 return 'green'
569 else:
570 return 'red'
571 else:
572 return self.bkgHitColor
573
574 def __str__(self):
575 """
576 Informal string summarizing the translation from seconday process codes to colors.
577 """
578
579 return """
580Legend:
581blue->primary
582green->secondary decay in flight
583red->secondary other process
584orange->beam background
585""" \
586 + str(self.n_hits_by_secondary_type)
587
588
590
591 """
592 Base class for Segments to color map functional objects.
593 """
594
595
596 bkgSegmentColor = 'orange'
597
598 def __call__(self, iSegment, segment):
599 """
600 Function call to map a segments object from the local finder to a color.
601 """
602
603 return self.bkgSegmentColor
604
605
607
608 """
609 Segment to color map based on the matched MCTrackId
610 """
611
612 def __call__(self, iSegment, segment):
613 """
614 Function call to map a segments object from the local finder to a color.
615 """
616
617 mcSegmentLookUp = \
619
620 mcTrackId = mcSegmentLookUp.getMCTrackId(segment)
621 if mcTrackId < 0:
622 return self.bkgSegmentColor
623 else:
624 iColor = mcTrackId % len(listColors)
625 color = listColors[iColor]
626 return color
627
628
630
631 """
632 Segment to color map based on the forward or backward alignment relative to the match Monte Carlo track.
633 """
634
635 def __call__(self, iSegment, segment):
636 """
637 Function call to map a segments object from the local finder to a color.
638 """
639
640 mcSegmentLookUp = \
642
643 # Just to look at matched segments
644 mcTrackId = mcSegmentLookUp.getMCTrackId(segment)
645 if mcTrackId < 0:
646 return self.bkgSegmentColor
647
648 fbInfo = mcSegmentLookUp.isForwardOrBackwardToMCTrack(segment)
649 if fbInfo == 1:
650 return 'green'
651 elif fbInfo == -1 or fbInfo == 65535: # <- The root interface mistakes the signed enum value for an unsigned value
652 return 'red'
653 else:
654 print('Segment not orientable to match track')
655 return self.bkgSegmentColor
656
657
659
660 """
661 Segment to color map by the in track id of the first hit.
662 """
663
664 def __call__(self, iSegment, segment):
665 """
666 Function call to map a segments object from the local finder to a color.
667 """
668
669 mcSegmentLookUp = \
671
672 # Just to look at matched segments
673 firstInTrackId = mcSegmentLookUp.getFirstInTrackId(segment)
674
675 if firstInTrackId < 0:
676 return self.bkgSegmentColor
677
678 return inTrackIdToColor(firstInTrackId)
679
680
682
683 """
684 Segment to color map by the in track id of the last hit.
685 """
686
687 def __call__(self, iSegment, segment):
688 """
689 Function call to map a segments object from the local finder to a color.
690 """
691
692 mcSegmentLookUp = \
694
695 # Just to look at matched segments
696 lastInTrackId = mcSegmentLookUp.getLastInTrackId(segment)
697
698 if lastInTrackId < 0:
699 return self.bkgSegmentColor
700
701 return inTrackIdToColor(lastInTrackId)
702
703
705
706 """
707 Segment to color map by the number of passed superlayers of the first hit.
708 """
709
710 def __call__(self, iSegment, segment):
711 """
712 Function call to map a segments object from the local finder to a color.
713 """
714
715 mcSegmentLookUp = \
717
718 # Just to look at matched segments
719 firstNPassedSuperLayers = \
720 mcSegmentLookUp.getFirstNPassedSuperLayers(segment)
721
722 if firstNPassedSuperLayers < 0:
723 return self.bkgSegmentColor
724
725 return inTrackIdToColor(firstNPassedSuperLayers)
726
727
729
730 """
731 Segment to color map by the number of passed superlayers of the last hit.
732 """
733
734 def __call__(self, iSegment, segment):
735 """
736 Function call to map a segments object from the local finder to a color.
737 """
738
739 mcSegmentLookUp = \
741
742 # Just to look at matched segments
743 lastNPassedSuperLayers = \
744 mcSegmentLookUp.getLastNPassedSuperLayers(segment)
745
746 if lastNPassedSuperLayers < 0:
747 return self.bkgSegmentColor
748
749 return inTrackIdToColor(lastNPassedSuperLayers)
Metadata information about the beam background file.
a (simplified) python wrapper for StoreObjPtr.
Definition: PyStoreObj.h:67
static const CDCMCHitLookUp & getInstance()
Getter for the singletone instance.
static const CDCMCSegment2DLookUp & getInstance()
Getter for the singletone instance.
Class representing a hit wire in the central drift chamber.
Definition: CDCWireHit.h:55
dict color_by_pdgcode
Dictionary to define the color for the most relevant.
str missing_pdg_color
Color for the case a particle a pdg code not mentioned in the color_by_pdgcode map.
color_by_mcparticleId
Dictionary mapping the MCParticle ids to colors for consistent and contious use of the available colo...
n_hits_by_secondary_type
Dictionary keeping track of the number of hits with a specific secondary process type.