Belle II Software  release-08-01-10
quadTreePlotter.py
1 
8 
9 from trackfindingcdc.cdcdisplay.svgdrawing import attributemaps
10 import bisect
11 from datetime import datetime
12 import tempfile
13 import numpy as np
14 import matplotlib.pyplot as plt
15 import basf2
16 import ROOT
17 from ROOT import Belle2
18 
19 from ROOT import gSystem
20 gSystem.Load('libtracking')
21 gSystem.Load('libtracking_trackFindingCDC')
22 
23 
24 class QuadTreePlotter(basf2.Module):
25  """
26  This Module is able to draw the content coming from a QuadTreeImplementation with debugOutput = True.
27  """
28 
29  def __init__(self, queue):
30  """
31  Do not forget to set the ranges! Otherwise you will end up with an empty plot..
32  """
33  basf2.Module.__init__(self)
34 
35  self.file_name_of_quad_tree_contentfile_name_of_quad_tree_content = "output.root"
36 
37  self.draw_quad_tree_contentdraw_quad_tree_content = True
38 
39  self.range_x_minrange_x_min = 0
40 
41  self.range_x_maxrange_x_max = 0
42 
43  self.range_y_minrange_y_min = 0
44 
45  self.range_y_maxrange_y_max = 0
46 
47 
48  self.queuequeue = queue
49 
50  self.file_namesfile_names = []
51 
53  """
54  Draw the quad tree content coming from the root file if enabled.
55  """
56 
57  import seaborn as sb
58 
59  if not self.draw_quad_tree_contentdraw_quad_tree_content:
60  return
61 
62  input_file = ROOT.TFile(self.file_name_of_quad_tree_contentfile_name_of_quad_tree_content)
63 
64  hist = input_file.Get("histUsed")
65 
66  xAxis = hist.GetXaxis()
67  yAxis = hist.GetYaxis()
68 
69  x_edges = np.array([xAxis.GetBinLowEdge(iX) for iX in range(1, xAxis.GetNbins() + 2)])
70  y_edges = np.array([yAxis.GetBinLowEdge(iY) for iY in range(1, yAxis.GetNbins() + 2)])
71 
72  arr_l = np.array([[hist.GetBinContent(iX, iY) for iY in range(1, yAxis.GetNbins() + 1)]
73  for iX in range(1, xAxis.GetNbins() + 1)])
74 
75  hist = input_file.Get("histUnused")
76 
77  xAxis = hist.GetXaxis()
78  yAxis = hist.GetYaxis()
79 
80  x_edges = np.array([xAxis.GetBinLowEdge(iX) for iX in range(1, xAxis.GetNbins() + 2)])
81  y_edges = np.array([yAxis.GetBinLowEdge(iY) for iY in range(1, yAxis.GetNbins() + 2)])
82 
83  l2 = np.array([[hist.GetBinContent(iX, iY) for iY in range(1, yAxis.GetNbins() + 1)]
84  for iX in range(1, xAxis.GetNbins() + 1)])
85 
86  cmap = sb.cubehelix_palette(8, start=2, rot=0, dark=0, light=1, reverse=False, as_cmap=True)
87 
88  plt.gca().pcolorfast(x_edges, y_edges, (arr_l + l2).T, cmap=cmap)
89 
90  x_labels = ["{1:0.{0}f}".format(int(not float(x).is_integer()), x) if i % 4 == 0 else "" for i, x in enumerate(x_edges)]
91  plt.xticks(x_edges, x_labels)
92  y_labels = ["{1:0.{0}f}".format(int(not float(y).is_integer()), y) if i % 4 == 0 else "" for i, y in enumerate(y_edges)]
93  plt.yticks(y_edges, y_labels)
94 
95  def save_and_show_file(self):
96  """
97  Save the plot to a svg and show it (maybe a png would be better?)
98  """
99  fileName = tempfile.gettempdir() + "/" + datetime.now().isoformat() + '.svg'
100  plt.savefig(fileName)
101  self.file_namesfile_names.append(fileName)
102 
103  def init_plotting(self):
104  """
105  Initialize the figure with the plot ranges
106  We need to implement axes labels later!
107  """
108  plt.clf()
109  plt.xlim(self.range_x_minrange_x_min, self.range_x_maxrange_x_max)
110  plt.ylim(self.range_y_minrange_y_min, self.range_y_maxrange_y_max)
111 
112  def event(self):
113  """
114  Draw everything
115  """
116  self.init_plottinginit_plotting()
117  self.plot_quad_tree_contentplot_quad_tree_content()
118  self.save_and_show_filesave_and_show_file()
119 
120  def terminate(self):
121  """Termination signal at the end of the event processing"""
122  self.queuequeue.put("quadTree", self.file_namesfile_names)
123 
124 
126 
127  """
128  Implementation of a quad tree plotter for SegmentQuadTrees
129  """
130 
131 
132  draw_segment_intersection = True and False
133 
134  draw_segment = True and False
135 
136  draw_segment_averaged = True and False
137 
138  draw_segment_fitted = True and False
139 
140  draw_mc_information = True and False
141 
142  draw_mc_hits = True and False
143 
144 
145  theta_shifted = False
146 
147  maximum_theta = np.pi
148 
149  def calculateIntersectionInQuadTreePicture(self, first, second):
150  """
151  Calculate the point where the two given hits intersect
152 
153  params
154  ------
155  first: hit
156  second: hit
157  """
158  positionFront = first.getRecoPos2D().conformalTransformed()
159  positionBack = second.getRecoPos2D().conformalTransformed()
160 
161  theta_cut = np.arctan2((positionBack - positionFront).x(), (positionFront - positionBack).y())
162 
163  if self.theta_shiftedtheta_shifted:
164  while theta_cut < - self.maximum_thetamaximum_theta / 2:
165  theta_cut += self.maximum_thetamaximum_theta
166  else:
167  while theta_cut < 0:
168  theta_cut += self.maximum_thetamaximum_theta
169 
170  r_cut = positionFront.x() * np.cos(theta_cut) + positionFront.y() * np.sin(theta_cut)
171 
172  return theta_cut, r_cut
173 
175  """
176  Transform a given normal coordinate position to a legendre position (conformal transformed)
177 
178  params
179  ------
180  position: TrackFindingCDC.Vector2D
181  """
182  position = position.conformalTransformed()
183 
184  theta = np.linspace(self.range_x_minrange_x_minrange_x_min, self.range_x_maxrange_x_maxrange_x_max, 100)
185  r = position.x() * np.cos(theta) + position.y() * np.sin(theta)
186 
187  return theta, r
188 
189  def forAllAxialSegments(self, f):
190  """
191  Loop over all segments and execute a function
192 
193  params
194  ------
195  f: function
196  """
197  items = Belle2.PyStoreObj("CDCSegment2DVector")
198  wrapped_vector = items.obj()
199  vector = wrapped_vector.get()
200 
201  for quad_tree_item in vector:
202  if quad_tree_item.getStereoType() == 0:
203  f(quad_tree_item)
204 
205  def convertToQuadTreePicture(self, phi, mag, charge):
206  """
207  Convert given track parameters into a point in the legendre space
208 
209  params
210  ------
211  phi: phi of the track
212  mag: magnitude of pt
213  charge: charge of the track
214  """
215  theta = phi + np.pi / 2
216  r = 1 / mag * 1.5 * 0.00299792458 * charge
217  if self.theta_shiftedtheta_shifted:
218  if theta > self.maximum_thetamaximum_theta / 2 or theta < -self.maximum_thetamaximum_theta / 2:
219  theta = theta % self.maximum_thetamaximum_theta - self.maximum_thetamaximum_theta / 2
220  else:
221  r *= -1
222  else:
223  if theta > self.maximum_thetamaximum_theta or theta < 0:
224  theta = theta % self.maximum_thetamaximum_theta
225  else:
226  r *= -1
227  return theta, r
228 
229  def event(self):
230  """
231  Draw everything according to the given options
232 
233  Attributes
234  ----------
235  draw_segment_intersection
236  draw_segment
237  draw_segment_averaged
238  draw_segment_fitted
239  draw_mc_information
240  draw_mc_hits
241  """
242  if self.theta_shiftedtheta_shifted:
243 
244  self.range_x_minrange_x_minrange_x_min = -self.maximum_thetamaximum_theta / 2
245 
246  self.range_x_maxrange_x_maxrange_x_max = self.maximum_thetamaximum_theta / 2
247  else:
248  self.range_x_minrange_x_minrange_x_min = 0
249  self.range_x_maxrange_x_maxrange_x_max = self.maximum_thetamaximum_theta
250 
251 
252  self.range_y_minrange_y_minrange_y_min = -0.08
253 
254  self.range_y_maxrange_y_maxrange_y_max = 0.08
255 
256  self.init_plottinginit_plotting()
257  # self.plotQuadTreeContent()
258 
259  if self.draw_segment_intersectiondraw_segment_intersection:
260  map = attributemaps.SegmentMCTrackIdColorMap()
261 
262  def f(segment):
263  theta, r = self.calculateIntersectionInQuadTreePicturecalculateIntersectionInQuadTreePicture(segment.front(), segment.back())
264  plt.plot(theta, r, color=list(map(0, segment)), marker="o")
265 
266  self.forAllAxialSegmentsforAllAxialSegments(f)
267 
268  if self.draw_segmentdraw_segment:
269  map = attributemaps.SegmentMCTrackIdColorMap()
270 
271  def f(segment):
272  theta, r = self.calculatePositionInQuadTreePicturecalculatePositionInQuadTreePicture(segment.front().getRecoPos2D())
273  plt.plot(theta, r, color=list(map(0, segment)), marker="", ls="-")
274 
275  self.forAllAxialSegmentsforAllAxialSegments(f)
276 
277  if self.draw_segment_averageddraw_segment_averaged:
278  map = attributemaps.SegmentMCTrackIdColorMap()
279 
280  def f(segment):
281  middle_index = int(np.round(segment.size() / 2.0))
282  middle_point = list(segment.items())[middle_index]
283  theta_front, r_front = self.calculateIntersectionInQuadTreePicturecalculateIntersectionInQuadTreePicture(segment.front(), middle_point)
284  theta_back, r_back = self.calculateIntersectionInQuadTreePicturecalculateIntersectionInQuadTreePicture(middle_point, segment.back())
285 
286  plt.plot([theta_front, theta_back], [r_front, r_back], color=list(map(0, segment)), marker="o", ls="-")
287 
288  self.forAllAxialSegmentsforAllAxialSegments(f)
289 
290  if self.draw_segment_fitteddraw_segment_fitted:
291  map = attributemaps.SegmentMCTrackIdColorMap()
293 
294  def f(segment):
295  trajectory = fitter.fit(segment)
296  momentum = trajectory.getUnitMom2D(Belle2.TrackFindingCDC.Vector2D(0, 0)).scale(trajectory.getAbsMom2D())
297  theta, r = self.convertToQuadTreePictureconvertToQuadTreePicture(momentum.phi(), momentum.norm(), trajectory.getChargeSign())
298  plt.plot(theta, r, color=list(map(0, segment)), marker="o")
299 
300  self.forAllAxialSegmentsforAllAxialSegments(f)
301 
302  if self.draw_hits:
303  cdcHits = Belle2.PyStoreArray("CDCHits")
304  storedWireHits = Belle2.PyStoreObj('CDCWireHitVector')
305  wireHits = storedWireHits.obj().get()
306 
307  array = Belle2.PyStoreArray("MCTrackCands")
308  cdc_hits = [cdcHits[i] for track in array for i in track.getHitIDs()]
309 
310  for cdcHit in cdcHits:
311  if cdcHit in cdc_hits:
312  continue
313  wireHit = wireHits.at(bisect.bisect_left(wireHits, cdcHit))
314  theta, r = self.calculatePositionInQuadTreePicturecalculatePositionInQuadTreePicture(wireHit.getRefPos2D())
315 
316  plt.plot(theta, r, marker="", color="black", ls="-", alpha=0.8)
317 
318  if self.draw_mc_hitsdraw_mc_hits:
319  storedWireHits = Belle2.PyStoreObj('CDCWireHitVector')
320  wireHits = storedWireHits.obj().get()
321 
322  map = attributemaps.listColors
323  array = Belle2.PyStoreArray("MCTrackCands")
324  cdcHits = Belle2.PyStoreArray("CDCHits")
325 
326  for track in array:
327  mcTrackID = track.getMcTrackId()
328 
329  for cdcHitID in track.getHitIDs(Belle2.Const.CDC):
330  cdcHit = cdcHits[cdcHitID]
331  wireHit = wireHits.at(bisect.bisect_left(wireHits, cdcHit))
332 
333  theta, r = self.calculatePositionInQuadTreePicturecalculatePositionInQuadTreePicture(wireHit.getRefPos2D())
334 
335  plt.plot(theta, r, marker="", color=map[mcTrackID % len(map)], ls="-", alpha=0.2)
336 
337  if self.draw_mc_informationdraw_mc_information:
338  map = attributemaps.listColors
339  array = Belle2.PyStoreArray("MCTrackCands")
340 
341  for track in array:
342  momentum = track.getMomSeed()
343 
344  # HARDCODED!!! Temporary solution
345  theta, r = self.convertToQuadTreePictureconvertToQuadTreePicture(momentum.Phi(), momentum.Mag(), track.getChargeSeed())
346  mcTrackID = track.getMcTrackId()
347 
348  plt.plot(theta, r, marker="o", color="black", ms=10)
349  plt.plot(theta, r, marker="o", color=map[mcTrackID % len(map)], ms=5)
350 
351  self.save_and_show_filesave_and_show_file()
352 
353 
355 
356  """
357  Implementation of a quad tree plotter for StereoHitAssignment
358  """
359 
360 
361  draw_mc_hits = False
362 
363  draw_mc_tracks = False
364 
365  draw_track_hits = False
366 
367  draw_last_track = True
368 
369  delete_bad_hits = False
370 
372  """
373  Convert a genfit::TrackCand into a TrackFindingCDC.CDCTrajectory3D
374 
375  params
376  ------
377  track: genfit::TrackCand
378  """
381 
382  position = Vector3D(track.getPosSeed())
383  momentum = Vector3D(track.getMomSeed())
384  charge = track.getChargeSeed()
385 
386  return Trajectory3D(position, momentum, charge)
387 
388  def create_reco_hit3D(self, cdcHit, trajectory3D, rlInfo):
389  """
390  Use a cdc hit and a trajectory to reconstruct a CDCRecoHit3D
391 
392  params
393  ------
394  cdcHit: CDCHit
395  trajectory3D: TrackFindingCDC.CDCTrajectory3D
396  rlInfo: RightLeftInfo ( = short)
397  """
398  storedWireHits = Belle2.PyStoreObj('CDCWireHitVector')
399  wireHits = storedWireHits.obj().get()
400 
402  wireHit = wireHits.at(bisect.bisect_left(wireHits, cdcHit))
403  rightLeftWireHit = Belle2.TrackFindingCDC.CDCRLWireHit(wireHit, rlInfo)
404  if rightLeftWireHit.getStereoType() != 0:
405  recoHit3D = CDCRecoHit3D.reconstruct(rightLeftWireHit, trajectory3D.getTrajectory2D())
406  return recoHit3D
407  else:
408  return None
409 
410  def get_plottable_line(self, recoHit3D):
411  """
412  Minim the task of the StereoQuadTree by showing the line of quadtree nodes
413  a hit belongs to
414  """
415  z0 = [self.range_y_minrange_y_minrange_y_min, self.range_y_maxrange_y_maxrange_y_max]
416  arr_l = np.array((np.array(recoHit3D.getRecoPos3D().z()) - z0) / recoHit3D.getArcLength2D())
417  return arr_l, z0
418 
419  def plot_hit_line(self, recoHit3D, color):
420  """
421  Draw one recoHit3D
422  """
423  if recoHit3D:
424  if recoHit3D.getStereoType() == 0:
425  return
426 
427  arr_l, z0 = self.get_plottable_lineget_plottable_line(recoHit3D)
428  plt.plot(arr_l, z0, marker="", ls="-", alpha=0.4, color=color)
429 
430  def event(self):
431  """
432  Draw the hit content according to the attributes
433 
434  Attributes
435  ----------
436  draw_mc_hits
437  draw_mc_tracks
438  draw_track_hits
439  draw_last_track
440  delete_bad_hits
441  """
442 
443  self.draw_quad_tree_contentdraw_quad_tree_contentdraw_quad_tree_content = True
444 
445 
446  self.range_x_minrange_x_minrange_x_min = -2 - np.sqrt(3)
447 
448  self.range_x_maxrange_x_maxrange_x_max = 2 + np.sqrt(3)
449 
450 
451  self.range_y_minrange_y_minrange_y_min = -100
452 
453  self.range_y_maxrange_y_maxrange_y_max = -self.range_y_minrange_y_minrange_y_min
454 
455  self.init_plottinginit_plotting()
456  self.plot_quad_tree_contentplot_quad_tree_content()
457 
458  map = attributemaps.listColors
459  cdcHits = Belle2.PyStoreArray("CDCHits")
460 
461  items = Belle2.PyStoreObj("CDCTrackVector")
462  wrapped_vector = items.obj()
463  track_vector = wrapped_vector.get()
464 
465  mcHitLookUp = Belle2.TrackFindingCDC.CDCMCHitLookUp().getInstance()
466  mcHitLookUp.fill()
467 
468  storedWireHits = Belle2.PyStoreObj('CDCWireHitVector')
469  wireHits = storedWireHits.obj().get()
470 
471  if self.draw_mc_hitsdraw_mc_hits:
472  mc_track_cands = Belle2.PyStoreArray("MCTrackCands")
473 
474  for track in mc_track_cands:
475  mcTrackID = track.getMcTrackId()
476  trajectory = self.create_trajectory_from_trackcreate_trajectory_from_track(track)
477 
478  for cdcHitID in track.getHitIDs(Belle2.Const.CDC):
479  cdcHit = cdcHits[cdcHitID]
480 
481  leftRecoHit3D = self.create_reco_hit3Dcreate_reco_hit3D(cdcHit, trajectory, -1)
482  rightRecoHit3D = self.create_reco_hit3Dcreate_reco_hit3D(cdcHit, trajectory, 1)
483 
484  self.plot_hit_lineplot_hit_line(leftRecoHit3D, color=map[mcTrackID % len(map)])
485  self.plot_hit_lineplot_hit_line(rightRecoHit3D, color=map[mcTrackID % len(map)])
486 
487  if self.draw_mc_tracksdraw_mc_tracks:
488  mc_track_cands = Belle2.PyStoreArray("MCTrackCands")
489 
490  for track in mc_track_cands:
491  mcTrackID = track.getMcTrackId()
492  trajectory = self.create_trajectory_from_trackcreate_trajectory_from_track(track)
493  z0 = trajectory.getTrajectorySZ().getZ0()
494 
495  for cdcHitID in track.getHitIDs(Belle2.Const.CDC):
496  cdcHit = cdcHits[cdcHitID]
497  recoHit3D = self.create_reco_hit3Dcreate_reco_hit3D(cdcHit, trajectory, mcHitLookUp.getRLInfo(cdcHit))
498 
499  if recoHit3D:
500  arr_l = (recoHit3D.getRecoPos3D().z() - z0) / recoHit3D.getArcLength2D()
501  plt.plot(arr_l, z0, marker="o", color=map[mcTrackID % len(map)], ls="", alpha=0.2)
502 
503  if self.draw_track_hitsdraw_track_hits:
504  for id, track in enumerate(track_vector):
505  for recoHit3D in list(track.items()):
506  self.plot_hit_lineplot_hit_line(recoHit3D, color=map[id % len(map)])
507 
508  if self.draw_last_trackdraw_last_track and len(track_vector) != 0:
509 
510  last_track = track_vector[-1]
511  trajectory = last_track.getStartTrajectory3D().getTrajectory2D()
512 
513  for wireHit in wireHits:
514  for rlInfo in (-1, 1):
515  recoHit3D = Belle2.TrackFindingCDC.CDCRecoHit3D.reconstruct(wireHit, rlInfo, trajectory)
516 
517  if (self.delete_bad_hitsdelete_bad_hits and
518  (wireHit.getRLInfo() != mcHitLookUp.getRLInfo(wireHit.getWireHit().getHit()) or
519  not recoHit3D.isInCellZBounds())):
520  continue
521 
522  if recoHit3D in list(last_track.items()):
523  color = map[len(track_vector) % len(map)]
524  else:
525  if wireHit.getRLInfo() == 1:
526  color = "black"
527  else:
528  color = "gray"
529  self.plot_hit_lineplot_hit_line(recoHit3D, color)
530 
531  plt.xlabel(r"$\tan \ \lambda$")
532  plt.ylabel(r"$z_0$")
533  self.save_and_show_filesave_and_show_file()
534 
535 
537 
538  """
539  A wrapper around the svg drawer in the tracking package that
540  writes its output files as a list to the queue
541  """
542 
543  def __init__(self, queue, label, *args, **kwargs):
544  """ The same as the base class, except:
545 
546  Arguments
547  ---------
548 
549  queue: The queue to write to
550  label: The key name in the queue
551  """
552 
553  self.queuequeuequeue = queue
554 
555  self.labellabel = label
556  StereoQuadTreePlotter.__init__(self, *args, **kwargs)
557 
558 
559  self.file_listfile_list = []
560 
561  def terminate(self):
562  """ Overwrite the terminate to put the list to the queue"""
563  StereoQuadTreePlotter.terminate(self)
564  self.queuequeuequeue.put(self.labellabel, self.file_listfile_list)
565 
567  """ Overwrite the function to listen for every new filename """
568 
569  from datetime import datetime
570  from matplotlib import pyplot as plt
571 
572  fileName = tempfile.gettempdir() + "/" + datetime.now().isoformat() + '.svg'
573  plt.savefig(fileName)
574  self.file_listfile_list.append(fileName)
A (simplified) python wrapper for StoreArray.
Definition: PyStoreArray.h:72
a (simplified) python wrapper for StoreObjPtr.
Definition: PyStoreObj.h:67
Interface class to the Monte Carlo information for individual hits.
Class representing an oriented hit wire including a hypotheses whether the causing track passes left ...
Definition: CDCRLWireHit.h:41
Class representing a three dimensional reconstructed hit.
Definition: CDCRecoHit3D.h:52
static CDCRecoHit3D reconstruct(const CDCRecoHit2D &recoHit2D, const CDCTrajectory2D &trajectory2D)
Reconstructs the three dimensional hit from the two dimensional and the two dimensional trajectory.
Definition: CDCRecoHit3D.cc:56
static const CDCRiemannFitter & getOriginCircleFitter()
Static getter for an origin circle fitter.
Particle full three dimensional trajectory.
A two dimensional vector which is equipped with functions for correct handeling of orientation relat...
Definition: Vector2D.h:35
A three dimensional vector.
Definition: Vector3D.h:33
range_x_min
cached minimum x value
draw_quad_tree_content
cached flag to draw QuadTree
range_y_max
cached maximum y value
range_x_max
cached maximum x value
file_name_of_quad_tree_content
cached output filename
file_names
cached array of output filenames (one file per image)
range_y_min
cached minimum y value
queue
cached value of the queue input parameter
def __init__(self, queue, label, *args, **kwargs)
label
The label for writing to the queue.
bool draw_segment_averaged
by default, do not draw an averaged segment
bool draw_segment
by default, do not draw a segment
bool draw_segment_fitted
by default, do not draw a fitted segment
range_x_min
lower x bound for polar angle
bool draw_mc_hits
by default, do not draw the MC hits
bool draw_mc_information
by default, do not draw the MC information
def convertToQuadTreePicture(self, phi, mag, charge)
maximum_theta
an alias for the maximum value of the polar angle
def calculatePositionInQuadTreePicture(self, position)
range_x_max
upper x bound for polar angle
bool draw_segment_intersection
by default, do not draw a segment intersection
bool theta_shifted
by default, polar angles and cuts are in the range (0,pi) rather than (-pi/2,+pi/2)
def calculateIntersectionInQuadTreePicture(self, first, second)
def plot_hit_line(self, recoHit3D, color)
bool draw_mc_hits
by default, do not draw the MC hits
bool delete_bad_hits
by default, do not delete the bad track hits
draw_quad_tree_content
by default, draw the QuadTree
bool draw_last_track
by default, draw the last track
def create_reco_hit3D(self, cdcHit, trajectory3D, rlInfo)
bool draw_track_hits
by default, do not draw the track hits
bool draw_mc_tracks
by default, do not draw the MC tracks
HepGeom::Vector3D< double > Vector3D
3D Vector
Definition: Cell.h:34