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 ## cached copy of the CDCWireHitVector
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
174class RLColorMap(CDCHitColorMap):
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
185 mcHitLookUp = Belle2.TrackFindingCDC.CDCMCHitLookUp.getInstance()
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
204class WrongRLColorMap():
205
206 """
207 CDCRecoHit3D to color map for the correctness of the rl information
208 """
209
210 def __init__(self):
211 """Constructor"""
212 mcHitLookUp = Belle2.TrackFindingCDC.CDCMCHitLookUp.getInstance()
213 mcHitLookUp.fill()
214
215 def __call__(self, iCDCRecoHit, cdcRecoHit3D):
216 """
217 This function maps the cdcRecoHit3D to the color which indicates the correctness of the rl passage
218 """
219
220 cdcHit = cdcRecoHit3D.getWireHit().getHit()
221
222 mcHitLookUp = Belle2.TrackFindingCDC.CDCMCHitLookUp.getInstance()
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
239class PosFlagColorMap(CDCHitColorMap):
240
241 """
242 CDCHit to color map by their associated 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
269class BackgroundTagColorMap(CDCHitColorMap):
270
271 """
272 CDCHit to color map by their associated CDCSimHit::getBackgroundTag property.
273 """
274
275 ## access the SimHitBase enum of background tags
276 BackgroundMetaData = Belle2.BackgroundMetaData
277
278 ## dictionary of (tag, label) pairs
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 ## dictionary of (tag, color) pairs
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
352class MCSegmentIdColorMap(CDCHitColorMap):
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
363 mcHitLookUp = Belle2.TrackFindingCDC.CDCMCHitLookUp.getInstance()
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
381class TOFColorMap(CDCHitColorMap):
382
383 """
384 CDCHit to color map by their associated 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
398class ReassignedSecondaryMap(CDCHitColorMap):
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
420class MCParticleColorMap(CDCHitColorMap):
421
422 """
423 CDCHit to color map coloring by the associated MCParticle::getArrayIndex()
424 """
425
426 def __init__(self):
427 """
428 Construction method setting up a Monte Carlo id to color dictionary which is continuously filled
429 as new during the event.
430 """
431
432 ## Dictionary mapping the MCParticle ids to colors for consistent and continuous use of the available colors
433 self.color_by_mcparticleId = {-1: self.bkgHitColor}
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
463class MCPDGCodeColorMap(CDCHitColorMap):
464
465 """
466 CDCHit to color map by the associated MCParticle::getPDG()
467 """
468
469 ## Dictionary to define the color for the most relevant
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 ## Color for the case a particle a pdg code not mentioned in the color_by_pdgcode map
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
529class MCPrimaryColorMap(CDCHitColorMap):
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 Construction method setting up a dictionary to count the hits for each secondary type.
538 """
539
540 ## Dictionary keeping track of the number of hits with a specific secondary process type.
541 self.n_hits_by_secondary_type = {}
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 secondary 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
589class CDCSegmentColorMap:
590
591 """
592 Base class for Segments to color map functional objects.
593 """
594
595 ## Default color to be used
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
606class SegmentMCTrackIdColorMap(CDCSegmentColorMap):
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 = \
618 Belle2.TrackFindingCDC.CDCMCSegment2DLookUp.getInstance()
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
629class SegmentFBInfoColorMap(CDCSegmentColorMap):
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 = \
641 Belle2.TrackFindingCDC.CDCMCSegment2DLookUp.getInstance()
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
658class SegmentFirstInTrackIdColorMap(CDCSegmentColorMap):
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 = \
670 Belle2.TrackFindingCDC.CDCMCSegment2DLookUp.getInstance()
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
681class SegmentLastInTrackIdColorMap(CDCSegmentColorMap):
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 = \
693 Belle2.TrackFindingCDC.CDCMCSegment2DLookUp.getInstance()
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
704class SegmentFirstNPassedSuperLayersColorMap(CDCSegmentColorMap):
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 = \
716 Belle2.TrackFindingCDC.CDCMCSegment2DLookUp.getInstance()
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
728class SegmentLastNPassedSuperLayersColorMap(CDCSegmentColorMap):
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 = \
740 Belle2.TrackFindingCDC.CDCMCSegment2DLookUp.getInstance()
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)
Class representing a hit wire in the central drift chamber.
Definition CDCWireHit.h:55