CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Classes | Functions
ntuplePrintersDiff Namespace Reference

Classes

class  _DiffResult
 
class  _IndentPrinter
 
class  _RecHitPrinter
 
class  _TrackAssociation
 
class  _TrackingParticleMatchPrinter
 
class  _TracksByHitsMatcher
 
class  SeedPrinter
 
class  TrackingParticlePrinter
 
class  TrackPrinter
 

Functions

def _areSameTracks
 
def _associateTracksByTrackingParticlesAndHits
 
def _commonHits
 
def _difflist
 
def _formatHitDiffForTwiki
 
def _hitPatternSummary
 
def _makediff
 
def _mapdiff
 
def _matchTracksByHits
 
def diffTrackListsFromSameTrackingParticle
 
def diffTrackListsGeneric
 

Function Documentation

def ntuplePrintersDiff._areSameTracks (   trk1,
  trk2 
)
private

Definition at line 178 of file ntuplePrintersDiff.py.

References _commonHits().

Referenced by diffTrackListsFromSameTrackingParticle(), and diffTrackListsGeneric().

179 def _areSameTracks(trk1, trk2):
180  ncommon = _commonHits(trk1, trk2)
181 
182  # if tracks have same hits, consider their reco as identical
183  if not (ncommon == trk1.nValid() and ncommon == trk2.nValid()):
184  return False
185 
186  # although if there is any change in their iterations, mark them different
187  if not (trk1.algoMask() == trk2.algoMask() and trk1.algo() == trk2.algo() and trk1.originalAlgo() == trk2.originalAlgo()):
188  return False
189 
190  # if reco is the same, check if they are matched to the
191  # same TPs (in case the track-TP matching is modified
192  # between ntuples)
193  if trk1.nMatchedTrackingParticles() != trk2.nMatchedTrackingParticles():
194  return False
195 
196  for tpInfo1, tpInfo2 in itertools.izip(trk1.matchedTrackingParticleInfos(), trk2.matchedTrackingParticleInfos()):
197  if tpInfo1.trackingParticle().index() != tpInfo2.trackingParticle().index():
198  return False
199 
200  return True
def ntuplePrintersDiff._associateTracksByTrackingParticlesAndHits (   lst1,
  lst2 
)
private

Definition at line 371 of file ntuplePrintersDiff.py.

References str.

Referenced by diffTrackListsGeneric().

373  trks1 = list(lst1)
374  trks2 = list(lst2)
375 
376  trks1Matcher = _TracksByHitsMatcher(trks1)
377  trks2Matcher = _TracksByHitsMatcher(trks2)
378 
379  # Used to have exactly the same Track objects for the same index
380  trks1Dict = {t.index(): t for t in trks1}
381  trks2Dict = {t.index(): t for t in trks2}
382 
383  # Bit of a hack...
384  tps1 = None
385  tps2 = None
386  if len(trks1) > 0:
387  tps1 = TrackingParticles(trks1[0]._tree)
388  if len(trks2) > 0:
389  tps2 = TrackingParticles(trks2[0]._tree)
390 
391  trkAssoc1 = {}
392  trkAssoc2 = {}
393 
394  def _getOrCreateAssoc(trk, d, **kwargs):
395  if trk.index() in d:
396  a = d[trk.index()]
397  else:
398  a = _TrackAssociation()
399  d[trk.index()] = a
400  a.extend(**kwargs)
401  return a
402 
403  while len(trks1) > 0:
404  trk1 = trks1.pop(0)
405  assoc1 = _getOrCreateAssoc(trk1, trkAssoc1, trks1=[trk1])
406 
407  # First associate via TP
408  if trk1.nMatchedTrackingParticles() > 0 and tps2:
409  matched = False
410 
411  for tpInfo1 in trk1.matchedTrackingParticleInfos():
412  tp1 = tpInfo1.trackingParticle()
413 
414  # Find possible duplicates within trks1
415  for trkInfo1 in tp1.matchedTrackInfos():
416  t1 = trkInfo1.track()
417  t1Index = t1.index()
418  if t1Index != trk1.index():
419  if t1Index in trks1Dict:
420  assoc1.extend(trks1=[t1]) # trk1 -> t1
421  _getOrCreateAssoc(t1, trkAssoc1, trks1=[t1, trk1]) # t1 -> trk1
422  #print "trk1 %d <-> t1 %d (TP)" % (trk1.index(), t1.index())
423  trks1.remove(trks1Dict[t1Index])
424  else:
425  #print "trk1 %d -> t1 %d (TP, not in list)" % (trk1.index(), t1.index())
426  assoc1.extend(trks1OutsideList=[t1]) # trk1 -> t1, if t1 is not in trks1
427 
428  # Then look for the same tp in trks2
429  tp2 = tps2[tp1.index()]
430  for trkInfo2 in tp2.matchedTrackInfos():
431  matched = True
432  t2 = trkInfo2.track()
433  t2Index = t2.index()
434  if t2Index in trks2Dict:
435  assoc1.extend(trks2=[t2]) # trk1 -> t2
436  _getOrCreateAssoc(t2, trkAssoc2, trks1=[trk1], trks2=[t2]) # t2 -> trk1
437  #print "trk1 %d <-> t2 %d (TP)" % (trk1.index(), t2.index())
438  try:
439  trks2.remove(trks2Dict[t2Index]) # can fail if t2 has already been matched via hits
440  except ValueError:
441  pass
442  else:
443  #print "trk1 %d -> t2 %d (TP, not in list)" % (trk1.index(), t2.index())
444  assoc1.extend(trks2OutsideList=[t2]) # trk1 -> t2, if t2 is not in trks2
445 
446  if matched:
447  continue
448 
449  # If no matching tracks in trks2 via TrackingParticles, then
450  # proceed finding the best match via hits
451  (matchedTrk2, ncommon) = trks2Matcher.match(trk1)
452  if matchedTrk2 is not None and ncommon >= 3:
453  assoc1.extend(trks2=[matchedTrk2])
454  assoc2 = _getOrCreateAssoc(matchedTrk2, trkAssoc2, trks1=[trk1], trks2=[matchedTrk2])
455  #print "trk1 %d <-> t2 %d (hits)" % (trk1.index(), matchedTrk2.index())
456  try:
457  trks2.remove(matchedTrk2) # can fail if matchedTrk2 has already been matched via TP
458  except ValueError:
459  pass
460 
461  (matchedTrk1, ncommon1) = trks1Matcher.match(matchedTrk2)
462  # if matchedTrk1 has TP, the link from matchedTrk1 -> matchedTrk2 will be created later
463  if (matchedTrk1.nMatchedTrackingParticles() == 0 or not tps2) and matchedTrk1.index() != trk1.index():
464  assoc2.extend(trks1=[matchedTrk1])
465  _getOrCreateAssoc(matchedTrk1, trkAssoc1, trks1=[matchedTrk1], trks2=[matchedTrk2])
466  #print "trk1 %d <-> t2 %d (hits, via t2)" % (matchedTrk1.index(), matchedTrk2.index())
467 
468  # no match
469 
470  # remaining tracks in trks2
471  for trk2 in trks2:
472  assoc2 = _getOrCreateAssoc(trk2, trkAssoc2, trks2=[trk2])
473  # collect duplicates
474  if trk2.nMatchedTrackingParticles() > 0:
475  for tpInfo2 in trk2.matchedTrackingParticleInfos():
476  tp2 = tpInfo2.trackingParticle()
477  for trkInfo2 in tp2.matchedTrackInfos():
478  t2 = trkInfo2.track()
479  t2Index = t2.index()
480  if t2Index in trks2Dict:
481  assoc2.extend(trks2=[t2])
482  #print "trk2 %d -> t2 %d (TP)" % (trk2.index(), t2.index())
483  else:
484  assoc2.extend(trks2OutsideList=[t2])
485  #print "trk2 %d -> t2 %d (TP, not in list)" % (trk2.index(), t2.index())
486 
487  # merge results
488  # any good way to avoid copy-past?
489  for ind, assoc in trkAssoc1.items():
490  for t1 in assoc.trks1():
491  a = trkAssoc1[t1.index()]
492  assoc.merge(a)
493  a.merge(assoc)
494  for t2 in assoc.trks2():
495  a = trkAssoc2[t2.index()]
496  assoc.merge(a)
497  a.merge(assoc)
498  for ind, assoc in trkAssoc2.items():
499  for t2 in assoc.trks2():
500  a = trkAssoc2[t2.index()]
501  assoc.merge(a)
502  a.merge(assoc)
503  for t1 in assoc.trks1():
504  a = trkAssoc1[t1.index()]
505  assoc.merge(a)
506  a.merge(assoc)
507 
508  for ind, assoc in itertools.chain(trkAssoc1.items(), trkAssoc2.items()):
509  #if ind in [437, 1101]:
510  # print "----"
511  # print ind, [t.index() for t in assoc.trks1()], [t.index() for t in assoc.trks2()]
512  for t1 in assoc.trks1():
513  a = trkAssoc1[t1.index()]
514  assoc.merge(a)
515  a.merge(assoc)
516 
517  #if ind in [437, 1101]:
518  # print ind, [t.index() for t in assoc.trks1()], [t.index() for t in assoc.trks2()]
519 
520  for t2 in assoc.trks2():
521  a = trkAssoc2[t2.index()]
522  assoc.merge(a)
523  a.merge(assoc)
524  #if ind in [437, 1101]:
525  # print ind, [t.index() for t in assoc.trks1()], [t.index() for t in assoc.trks2()]
526  # print "####"
527 
528  # collapse to a single collection of associations
529  allAssocs = []
530  while len(trkAssoc1) > 0:
531  (t1Index, assoc) = trkAssoc1.popitem()
532 
533  #if t1Index == 1299:
534  # print t1Index, [t.index() for t in assoc.trks2()]
535  for t1 in assoc.trks1():
536  if t1.index() == t1Index: continue
537  trkAssoc1.pop(t1.index())
538  for t2 in assoc.trks2():
539  trkAssoc2.pop(t2.index())
540  allAssocs.append(assoc)
541  while len(trkAssoc2) > 0:
542  (t2Index, assoc) = trkAssoc2.popitem()
543  if len(assoc.trks1()) > 0:
544  raise Exception("len(assoc.trks1()) %d != 0 !!! %s for t2 %d" % (len(assoc.trks1()), str([t.index() for t in assoc.trks1()]), t2Index))
545  for t2 in assoc.trks2():
546  if t2.index() == t2Index: continue
547  trkAssoc2.pop(t2.index())
548  allAssocs.append(assoc)
549 
550  return allAssocs
def _associateTracksByTrackingParticlesAndHits
#define str(s)
def ntuplePrintersDiff._commonHits (   trk1,
  trk2 
)
private
Returns the number of common hits in trk1 and trk2. Matching is
done via the hit type and index, so effectively the matching is
done by clusters. Invalid hits are ignored.

Definition at line 14 of file ntuplePrintersDiff.py.

Referenced by _areSameTracks(), and diffTrackListsGeneric().

14 
15 def _commonHits(trk1, trk2):
16  """Returns the number of common hits in trk1 and trk2. Matching is
17  done via the hit type and index, so effectively the matching is
18  done by clusters. Invalid hits are ignored.
19 
20  """
21  hits1 = set()
22  for hit in trk1.hits():
23  if not hit.isValidHit(): continue
24  hits1.add( (type(hit), hit.index()) )
25 
26  ncommon = 0
27  for hit in trk2.hits():
28  if not hit.isValidHit(): continue
29  if (type(hit), hit.index()) in hits1:
30  ncommon += 1
31 
32  return ncommon
def ntuplePrintersDiff._difflist (   list1,
  list2 
)
private

Definition at line 159 of file ntuplePrintersDiff.py.

Referenced by _makediff().

160 def _difflist(list1, list2):
161  diff = difflib.unified_diff(list1, list2, lineterm="", n=len(list1))
162  for item in diff:
163  if item[:2] == "@@":
164  break
165  return list(diff)
def ntuplePrintersDiff._formatHitDiffForTwiki (   diffHits,
  prefix 
)
private

Definition at line 619 of file ntuplePrintersDiff.py.

References join().

Referenced by ntuplePrintersDiff.SeedPrinter.diff(), and ntuplePrintersDiff.TrackPrinter.diff().

620 def _formatHitDiffForTwiki(diffHits, prefix):
621  line_re = re.compile("(?P<sign>[ \-+])\s+(?P<det>[a-zA-Z]+)(?P<lay>\d+)\D*?(\((?P<missing>missing|inactive)\))?\s+\d+")
622 
623  summary = []
624  prevdet = ""
625  prevsign = " "
626  diffLines = diffHits.lines()
627 
628  # skip anything before the first line with "hits"
629  for line in diffLines:
630  if "hits" in line:
631  break
632 
633  header = True
634  for line in diffLines:
635  # skip multiple occurrances of "hits" line, but only until
636  # first line without "hits" is encountered
637  if header:
638  if "hits" in line:
639  continue
640  else:
641  header = False
642 
643  m = line_re.search(line)
644  if not m:
645  break
646  raise Exception("regex not found from line %s" % line.rstrip())
647  sign = m.group("sign")
648  det = m.group("det")
649  lay = m.group("lay")
650 
651  if det != prevdet:
652  if prevsign != " ":
653  summary.append("%ENDCOLOR%")
654  prevsign = " "
655  summary.extend([" ", det])
656  prevdet = det
657 
658  if sign != prevsign:
659  if prevsign != " ":
660  summary.append("%ENDCOLOR%")
661  if sign == "-":
662  summary.append("%RED%")
663  elif sign == "+":
664  summary.append("%GREEN%")
665  prevsign = sign
666 
667  #print sign, det, lay
668  #if len(summary) > 0:
669  # print " ", summary[-1]
670 
671  #if det != prevdet:
672  # if prevsign != " ":
673  # #if len(summary) > 0:
674  # # if
675  # summary.append("%ENDCOLOR")
676  # summary.extend([" ", det])
677  # if prevsign == "-":
678  # summary.append("%RED%")
679  # elif prevsign == "+":
680  # summary.append("%GREEN%")
681  # prevdet = det
682  summary.append(lay)
683  if m.group("missing"):
684  if m.group("missing") == "missing":
685  summary.append("(m)")
686  elif m.group("missing") == "inactive":
687  summary.append("(i)")
688 
689  if prevsign != " ":
690  summary.append("%ENDCOLOR%")
691  # prune "changed" missing/inactive hits
692  i = 2
693  while i < len(summary)-5:
694  if summary[i] == "(i)" or summary[i] == "(m)":
695  if summary[i-2] == "%RED%" and summary[i+1] == "%ENDCOLOR%" and summary[i+2] == "%GREEN%" and summary[i+3] == summary[i-1] and summary[i+4] == summary[i] and summary[i+5] == "%ENDCOLOR%":
696  summary[i-2:i+6] = [summary[i-1], summary[i]]
697  i += 1
698 
699  line = " "+"".join(summary)
700  return ["?"+prefix+line]
701 
# Common detailed printout helpers
static std::string join(char **cmd)
Definition: RemoteFile.cc:19
def ntuplePrintersDiff._hitPatternSummary (   hits)
private

Definition at line 702 of file ntuplePrintersDiff.py.

References str.

Referenced by ntuplePrintersDiff.SeedPrinter.printHits(), ntuplePrintersDiff.TrackPrinter.printHits(), and ntuplePrintersDiff.TrackingParticlePrinter.printHits().

703 def _hitPatternSummary(hits):
704  summary = ""
705 
706  prevdet = 0
707  for hit in hits:
708  det = hit.subdet()
709  lay = hit.layer()
710 
711  if det != prevdet:
712  summary += " "+SubDet.toString(det)
713  prevdet = det
714 
715  summary += str(lay)
716  if isinstance(hit, InvalidHit):
717  summary += "(%s)"%InvalidHit.Type.toString(hit.type())[0]
718 
719  return summary
#define str(s)
def ntuplePrintersDiff._makediff (   list1,
  list2,
  equalPrefix = " " 
)
private

Definition at line 166 of file ntuplePrintersDiff.py.

References _difflist().

Referenced by _mapdiff(), ntuplePrintersDiff.SeedPrinter.diff(), ntuplePrintersDiff.TrackPrinter.diff(), ntuplePrintersDiff.TrackingParticlePrinter.diffMatchedSeeds(), ntuplePrintersDiff.TrackingParticlePrinter.diffMatchedTracks(), and diffTrackListsFromSameTrackingParticle().

167 def _makediff(list1, list2, equalPrefix=" "):
168  diff = _difflist(list1, list2)
169  if len(diff) == 0:
170  return _DiffResult([equalPrefix+s for s in list1], hasDifference=False)
171  else:
172  return _DiffResult(diff, hasDifference=True)
def ntuplePrintersDiff._mapdiff (   func,
  obj1,
  obj2 
)
private

Definition at line 173 of file ntuplePrintersDiff.py.

References _makediff(), and cms::cuda.func.

Referenced by ntuplePrintersDiff.SeedPrinter.diff(), ntuplePrintersDiff.TrackPrinter.diff(), ntuplePrintersDiff.TrackingParticlePrinter.diff(), and diffTrackListsFromSameTrackingParticle().

174 def _mapdiff(func, obj1, obj2):
175  lst1 = func(obj1) if obj1 is not None else []
176  lst2 = func(obj2) if obj2 is not None else []
177  return _makediff(lst1, lst2)
uint32_t T const *__restrict__ uint32_t const *__restrict__ int32_t int Histo::index_type cudaStream_t Func __host__ __device__ V int Func func
def ntuplePrintersDiff._matchTracksByHits (   reftrk,
  trklist 
)
private

Definition at line 33 of file ntuplePrintersDiff.py.

Referenced by ntuplePrintersDiff.TrackingParticlePrinter.diffMatchedSeeds(), and diffTrackListsFromSameTrackingParticle().

33 
34 def _matchTracksByHits(reftrk, trklist):
35  if len(trklist) == 0:
36  return (None, 0)
37 
38  hits1 = set()
39  for hit in reftrk.hits():
40  if not hit.isValidHit(): continue
41  hits1.add( (type(hit), hit.index()) )
42 
43  best = (None, 0)
44  for trk in trklist:
45  ncommon = 0
46  for hit in trk.hits():
47  if not hit.isValidHit(): continue
48  if (type(hit), hit.index()) in hits1:
49  ncommon += 1
50  if ncommon > best[1]:
51  best = (trk, ncommon)
52 
53  return best
def ntuplePrintersDiff.diffTrackListsFromSameTrackingParticle (   trackPrinter,
  lst1,
  lst2,
  lst1extra = [],
  lst2extra = [],
  diffByHitsOnly = False 
)
lst1 and lst2 are the main lists to make the diff from.

lst1extra and lst2extra are optional to provide suplementary
tracks. Use case: lst1 and lst2 are subset of full tracks,
lst1extra and lst2extra contain tracks matched to the same
TrackingParticle but are outside of the selection of lst1/lst2.

Definition at line 201 of file ntuplePrintersDiff.py.

References _areSameTracks(), _makediff(), _mapdiff(), _matchTracksByHits(), and GetRecoTauVFromDQM_MC_cff.next.

Referenced by ntuplePrintersDiff.TrackingParticlePrinter.diffMatchedTracks(), and diffTrackListsGeneric().

202 def diffTrackListsFromSameTrackingParticle(trackPrinter, lst1, lst2, lst1extra=[], lst2extra=[], diffByHitsOnly=False):
203  """lst1 and lst2 are the main lists to make the diff from.
204 
205  lst1extra and lst2extra are optional to provide suplementary
206  tracks. Use case: lst1 and lst2 are subset of full tracks,
207  lst1extra and lst2extra contain tracks matched to the same
208  TrackingParticle but are outside of the selection of lst1/lst2.
209  """
210 
211  diff = _DiffResult()
212 
213  _trks1extra = list(lst1extra)
214  _trks2extra = list(lst2extra)
215 
216  trks1 = list(lst1)+_trks1extra
217  trks2 = list(lst2)+_trks2extra # make copy because it is modified
218 
219  trks1extra = set([t.index() for t in _trks1extra])
220  trks2extra = set([t.index() for t in _trks2extra])
221 
222  trks1Empty = (len(trks1) == 0)
223  trks2Empty = (len(trks2) == 0)
224 
225  if trks1Empty and trks2Empty:
226  return diff
227 
228  # make sure all tracks really come from a single TP
229  # just to simplify the work loop, generalization can be considered later
230  commonTP = None
231  def _findCommonTP(_lst, _commonTP, _name):
232  for trk in _lst:
233  if trk.nMatchedTrackingParticles() != 1:
234  raise Exception("Track %d from %s is matched to %d TPs. This is not supported by this function yet." % (trk.index(), _name, trk.nMatchedTrackingParticles()))
235  if _commonTP is None:
236  _commonTP = next(trk.matchedTrackingParticleInfos()).trackingParticle()
237  else:
238  tp = next(trk.matchedTrackingParticleInfos()).trackingParticle()
239  if tp.index() != _commonTP.index():
240  raise Exception("Track %d from %s is matched to TP %d, which differs from the TP %d of already processed tracks." % (trk.index(), _name, _commonTP.index(), tp.index()))
241  return _commonTP
242  commonTP = _findCommonTP(trks1, commonTP, "lst1")
243  commonTP = _findCommonTP(trks2, commonTP, "lst2")
244 
245  # Need some tracks from trks1 and trks2 to print the TrackingParticle information
246  someTrk1 = trks1[0] if not trks1Empty else None
247  someTrk2 = trks2[0] if not trks2Empty else None
248 
249  for trk1 in trks1:
250  (matchedTrk2, ncommon) = _matchTracksByHits(trk1, trks2)
251 
252  # no more tracks in tp2
253  if matchedTrk2 is None:
254  if trk1.index() in trks1extra:
255  raise Exception("Track %d was found in trks1extra but matchedTrk2 is None, this should not happen" % trk1.index())
256  diff.extend(_makediff(trackPrinter.printTrack(trk1), []))
257  else: # diff trk1 to best-matching track from trks2
258  someTrk2 = matchedTrk2
259  trks2.remove(matchedTrk2)
260  tmp = trackPrinter.diff(trk1, matchedTrk2, diffTrackingParticles=False)
261  if diffByHitsOnly and _areSameTracks(trk1, matchedTrk2):
262  tmp.setDifference(False)
263  tmp.highlight(plus=(matchedTrk2.index() in trks2extra), minus=(trk1.index() in trks1extra))
264  diff.extend(tmp)
265 
266  for trk2 in trks2: # remaining tracks in trks2
267  if trk2.index() in trks2extra:
268  raise Exception("Track %d was found in trks2extra, but without matching track in trks1, this should not happen" % trk2.index())
269  diff.extend(_makediff([], trackPrinter.printTrack(trk2)))
270 
271  # finally add information of the trackingParticle
272  # easiest is to pass a track matched to the TP
273  tmp = _mapdiff(trackPrinter.printMatchedTrackingParticles, someTrk1, someTrk2)
274  tmp.setDifference(False) # we know the TP is the same, even if the "track match" information will differ
275  def _makere(lst):
276  r = []
277  for i in lst: r.extend([re.compile("Tracks:.*%d:"%i), re.compile("matched to tracks.*%d"%i)])
278  return r
279  plusre = _makere(trks2extra)
280  minusre = _makere(trks1extra)
281  tmp.highlightLines(plusre, minusre)
282  diff.extend(tmp)
283 
284  return diff
def ntuplePrintersDiff.diffTrackListsGeneric (   trackPrinter,
  lst1,
  lst2,
  ignoreAdditionalLst2 = False 
)

Definition at line 551 of file ntuplePrintersDiff.py.

References _areSameTracks(), _associateTracksByTrackingParticlesAndHits(), _commonHits(), diffTrackListsFromSameTrackingParticle(), GetRecoTauVFromDQM_MC_cff.next, and alignCSCRings.r.

552 def diffTrackListsGeneric(trackPrinter, lst1, lst2, ignoreAdditionalLst2=False):
553  associations = _associateTracksByTrackingParticlesAndHits(lst1, lst2)
554 
555  # sort in eta
556  associations.sort(key=methodcaller("minEta"))
557 
558  diff = _DiffResult()
559  for assoc in associations:
560  if assoc.hasCommonTrackingParticle():
561  if len(assoc.trks1()) == 0 and ignoreAdditionalLst2:
562  continue
563 
564  tmp = diffTrackListsFromSameTrackingParticle(trackPrinter, assoc.trks1(), assoc.trks2(), lst1extra=assoc.trks1OutsideList(), lst2extra=assoc.trks2OutsideList(), diffByHitsOnly=True)
565  if tmp.hasDifference():
566  diff.extend(tmp)
567  diff.extend([" "])
568  elif len(assoc.trks1()) == 1 and len(assoc.trks2()) == 1:
569  trk1 = assoc.trks1()[0]
570  trk2 = assoc.trks2()[0]
571 
572  if not _areSameTracks(trk1, trk2):
573  diff.extend(trackPrinter.diff(trk1, trk2))
574  diff.extend([" "])
575  elif len(assoc.trks2()) == 0:
576  for t in assoc.trks1():
577  diff.extend(trackPrinter.diff(t, None))
578  diff.extend([" "])
579  elif len(assoc.trks1()) == 0:
580  if ignoreAdditionalLst2:
581  continue
582  for t in assoc.trks1():
583  diff.extend(trackPrinter.diff(None, t))
584  diff.extend([" "])
585  else:
586  # needs to be rather generic, let's start by sorting by the innermost hit
587  trks1 = list(assoc.trks1())
588  trks2 = list(assoc.trks2())
589  trks1.sort(key=lambda t: next(t.hits()).r())
590  trks2.sort(key=lambda t: next(t.hits()).r())
591 
592  # then calculate number of shared hits for each pair
593  ncommon = []
594  for i1, t1 in enumerate(trks1):
595  for i2, t2 in enumerate(trks2):
596  ncommon.append( (i1, i2, _commonHits(t1, t2)) )
597 
598  # sort that by number of common hits, descending order
599  ncommon.sort(key=itemgetter(2), reverse=True)
600 
601  # then make the diffs starting from the pair with largest number of common hits
602  pairs = [None]*len(trks1)
603  usedT2 = [False]*len(trks2)
604  for i1, i2, ncom in ncommon:
605  if pairs[i1] is None:
606  pairs[i1] = i2
607  usedT2[i2] = True
608 
609  for i1, i2 in enumerate(pairs):
610  t1 = trks1[i1]
611  t2 = trks2[i2]
612  diff.extend(trackPrinter.diff(t1, t2))
613  for i2, used in enumerate(usedT2):
614  if not used:
615  diff.extend(trackPrinter.diff(None, trks2[i2]))
616  diff.extend([" "])
617 
618  return diff
def _associateTracksByTrackingParticlesAndHits