File indexing completed on 2024-09-26 05:07:22
0001 from builtins import range
0002 import re
0003 import sys
0004 import math
0005 import difflib
0006 import itertools
0007 import collections
0008
0009 from operator import itemgetter, methodcaller
0010
0011 from Validation.RecoTrack.plotting.ntupleDataFormat import *
0012
0013
0014 def _commonHits(trk1, trk2):
0015 """Returns the number of common hits in trk1 and trk2. Matching is
0016 done via the hit type and index, so effectively the matching is
0017 done by clusters. Invalid hits are ignored.
0018
0019 """
0020 hits1 = set()
0021 for hit in trk1.hits():
0022 if not hit.isValidHit(): continue
0023 hits1.add( (type(hit), hit.index()) )
0024
0025 ncommon = 0
0026 for hit in trk2.hits():
0027 if not hit.isValidHit(): continue
0028 if (type(hit), hit.index()) in hits1:
0029 ncommon += 1
0030
0031 return ncommon
0032
0033 def _matchTracksByHits(reftrk, trklist):
0034 if len(trklist) == 0:
0035 return (None, 0)
0036
0037 hits1 = set()
0038 for hit in reftrk.hits():
0039 if not hit.isValidHit(): continue
0040 hits1.add( (type(hit), hit.index()) )
0041
0042 best = (None, 0)
0043 for trk in trklist:
0044 ncommon = 0
0045 for hit in trk.hits():
0046 if not hit.isValidHit(): continue
0047 if (type(hit), hit.index()) in hits1:
0048 ncommon += 1
0049 if ncommon > best[1]:
0050 best = (trk, ncommon)
0051
0052 return best
0053
0054 class _TracksByHitsMatcher(object):
0055 def __init__(self, trklist):
0056 super(_TracksByHitsMatcher, self).__init__()
0057 self._hitsToTracks = collections.defaultdict(list)
0058 for trk in trklist:
0059 for hit in trk.hits():
0060 if hit.isValidHit():
0061 self._hitsToTracks[ (type(hit), hit.index()) ].append(trk)
0062
0063 def match(self, trk):
0064 tracks = collections.defaultdict(int)
0065
0066 for hit in trk.hits():
0067 if not hit.isValidHit(): continue
0068
0069 idx = (type(hit), hit.index())
0070 try:
0071 otherTracks = self._hitsToTracks[idx]
0072 except KeyError:
0073 continue
0074
0075 for ot in otherTracks:
0076 tracks[ot] += 1
0077
0078 best = (None, 0)
0079 for t, ncommon in tracks.items():
0080 if ncommon > best[1]:
0081 best = (t, ncommon)
0082 return best
0083
0084
0085
0086 class _DiffResult(object):
0087 def __init__(self, diff=[], hasDifference=False):
0088 self._diff = []
0089 self._hasDifference = hasDifference
0090 self.extend(diff)
0091
0092 def setDifference(self, diff=True):
0093 self._hasDifference = diff
0094
0095 def hasDifference(self):
0096 return self._hasDifference
0097
0098 def extend(self, diff):
0099 if isinstance(diff, _DiffResult):
0100 self._diff.append(diff)
0101 if diff.hasDifference():
0102 self.setDifference()
0103 else:
0104 self._diff.extend(diff)
0105
0106 def _highlightLine(self, line, plus, minus):
0107 char = " "
0108 if line[0] == "+":
0109 if plus: char = "+"
0110 elif line[0] == "-":
0111 if minus: char = "-"
0112 elif line[0] == "?":
0113 char = "?"
0114 return line[0]+char+line[1:]
0115
0116 def highlight(self, plus=False, minus=False):
0117 if not (plus or minus):
0118 return
0119
0120 for i, line in enumerate(self._diff):
0121 if isinstance(line, _DiffResult):
0122 line.highlight(plus, minus)
0123 else:
0124 self._diff[i] = self._highlightLine(line, plus, minus)
0125
0126 def highlightLines(self, plusregexs=[], minusregexs=[]):
0127 if len(plusregexs) == 0 and len(minusregexs) == 0:
0128 return
0129
0130 for i, line in enumerate(self._diff):
0131 if isinstance(line, _DiffResult):
0132 raise Exception("highlightLines() is currently allowed only for text-only _DiffResult objects")
0133 plus = False
0134 minus = False
0135 for p in plusregexs:
0136 if p.search(line):
0137 plus = True
0138 break
0139 for m in minusregexs:
0140 if m.search(line):
0141 plus = True
0142 break
0143 self._diff[i] = self._highlightLine(line, plus, minus)
0144
0145 def lines(self):
0146 for line in self._diff:
0147 if isinstance(line, _DiffResult):
0148 for l in line.lines():
0149 yield l
0150 else:
0151 yield line
0152
0153 def __str__(self):
0154 return "\n".join([s for s in (str(item) for item in self._diff) if s != ""])
0155
0156 def __len__(self):
0157 return len(self._diff)
0158
0159 def _difflist(list1, list2):
0160 diff = difflib.unified_diff(list1, list2, lineterm="", n=len(list1))
0161 for item in diff:
0162 if item[:2] == "@@":
0163 break
0164 return list(diff)
0165
0166 def _makediff(list1, list2, equalPrefix=" "):
0167 diff = _difflist(list1, list2)
0168 if len(diff) == 0:
0169 return _DiffResult([equalPrefix+s for s in list1], hasDifference=False)
0170 else:
0171 return _DiffResult(diff, hasDifference=True)
0172
0173 def _mapdiff(func, obj1, obj2):
0174 lst1 = func(obj1) if obj1 is not None else []
0175 lst2 = func(obj2) if obj2 is not None else []
0176 return _makediff(lst1, lst2)
0177
0178 def _areSameTracks(trk1, trk2):
0179 ncommon = _commonHits(trk1, trk2)
0180
0181
0182 if not (ncommon == trk1.nValid() and ncommon == trk2.nValid()):
0183 return False
0184
0185
0186 if not (trk1.algoMask() == trk2.algoMask() and trk1.algo() == trk2.algo() and trk1.originalAlgo() == trk2.originalAlgo()):
0187 return False
0188
0189
0190
0191
0192 if trk1.nMatchedTrackingParticles() != trk2.nMatchedTrackingParticles():
0193 return False
0194
0195 for tpInfo1, tpInfo2 in itertools.izip(trk1.matchedTrackingParticleInfos(), trk2.matchedTrackingParticleInfos()):
0196 if tpInfo1.trackingParticle().index() != tpInfo2.trackingParticle().index():
0197 return False
0198
0199 return True
0200
0201 def diffTrackListsFromSameTrackingParticle(trackPrinter, lst1, lst2, lst1extra=[], lst2extra=[], diffByHitsOnly=False):
0202 """lst1 and lst2 are the main lists to make the diff from.
0203
0204 lst1extra and lst2extra are optional to provide suplementary
0205 tracks. Use case: lst1 and lst2 are subset of full tracks,
0206 lst1extra and lst2extra contain tracks matched to the same
0207 TrackingParticle but are outside of the selection of lst1/lst2.
0208 """
0209
0210 diff = _DiffResult()
0211
0212 _trks1extra = list(lst1extra)
0213 _trks2extra = list(lst2extra)
0214
0215 trks1 = list(lst1)+_trks1extra
0216 trks2 = list(lst2)+_trks2extra
0217
0218 trks1extra = set([t.index() for t in _trks1extra])
0219 trks2extra = set([t.index() for t in _trks2extra])
0220
0221 trks1Empty = (len(trks1) == 0)
0222 trks2Empty = (len(trks2) == 0)
0223
0224 if trks1Empty and trks2Empty:
0225 return diff
0226
0227
0228
0229 commonTP = None
0230 def _findCommonTP(_lst, _commonTP, _name):
0231 for trk in _lst:
0232 if trk.nMatchedTrackingParticles() != 1:
0233 raise Exception("Track %d from %s is matched to %d TPs. This is not supported by this function yet." % (trk.index(), _name, trk.nMatchedTrackingParticles()))
0234 if _commonTP is None:
0235 _commonTP = next(trk.matchedTrackingParticleInfos()).trackingParticle()
0236 else:
0237 tp = next(trk.matchedTrackingParticleInfos()).trackingParticle()
0238 if tp.index() != _commonTP.index():
0239 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()))
0240 return _commonTP
0241 commonTP = _findCommonTP(trks1, commonTP, "lst1")
0242 commonTP = _findCommonTP(trks2, commonTP, "lst2")
0243
0244
0245 someTrk1 = trks1[0] if not trks1Empty else None
0246 someTrk2 = trks2[0] if not trks2Empty else None
0247
0248 for trk1 in trks1:
0249 (matchedTrk2, ncommon) = _matchTracksByHits(trk1, trks2)
0250
0251
0252 if matchedTrk2 is None:
0253 if trk1.index() in trks1extra:
0254 raise Exception("Track %d was found in trks1extra but matchedTrk2 is None, this should not happen" % trk1.index())
0255 diff.extend(_makediff(trackPrinter.printTrack(trk1), []))
0256 else:
0257 someTrk2 = matchedTrk2
0258 trks2.remove(matchedTrk2)
0259 tmp = trackPrinter.diff(trk1, matchedTrk2, diffTrackingParticles=False)
0260 if diffByHitsOnly and _areSameTracks(trk1, matchedTrk2):
0261 tmp.setDifference(False)
0262 tmp.highlight(plus=(matchedTrk2.index() in trks2extra), minus=(trk1.index() in trks1extra))
0263 diff.extend(tmp)
0264
0265 for trk2 in trks2:
0266 if trk2.index() in trks2extra:
0267 raise Exception("Track %d was found in trks2extra, but without matching track in trks1, this should not happen" % trk2.index())
0268 diff.extend(_makediff([], trackPrinter.printTrack(trk2)))
0269
0270
0271
0272 tmp = _mapdiff(trackPrinter.printMatchedTrackingParticles, someTrk1, someTrk2)
0273 tmp.setDifference(False)
0274 def _makere(lst):
0275 r = []
0276 for i in lst: r.extend([re.compile("Tracks:.*%d:"%i), re.compile("matched to tracks.*%d"%i)])
0277 return r
0278 plusre = _makere(trks2extra)
0279 minusre = _makere(trks1extra)
0280 tmp.highlightLines(plusre, minusre)
0281 diff.extend(tmp)
0282
0283 return diff
0284
0285 class _TrackAssociation(object):
0286 def __init__(self):
0287 super(_TrackAssociation, self).__init__()
0288 self._trks1 = []
0289 self._trks2 = []
0290 self._trks1OutsideList = []
0291 self._trks2OutsideList = []
0292
0293 self._trks1Ind = set()
0294 self._trks2Ind = set()
0295 self._trks1OutsideListInd = set()
0296 self._trks2OutsideListInd = set()
0297
0298 def _extend(self, trks, name):
0299 lst = getattr(self, name)
0300 ind = getattr(self, name+"Ind")
0301 for t in trks:
0302 if not t.index() in ind:
0303 lst.append(t)
0304 ind.add(t.index())
0305
0306 def extend(self, trks1=[], trks2=[], trks1OutsideList=[], trks2OutsideList=[]):
0307 self.extendTrks1(trks1)
0308 self.extendTrks2(trks2)
0309 self.extendTrks1OutsideList(trks1OutsideList)
0310 self.extendTrks2OutsideList(trks2OutsideList)
0311
0312 def extendTrks1(self, trks):
0313 self._extend(trks, "_trks1")
0314
0315 def extendTrks2(self, trks):
0316 self._extend(trks, "_trks2")
0317
0318 def extendTrks1OutsideList(self, trks):
0319 self._extend(trks, "_trks1OutsideList")
0320
0321 def extendTrks2OutsideList(self, trks):
0322 self._extend(trks, "_trks2OutsideList")
0323
0324 def trks1(self): return self._trks1
0325 def trks2(self): return self._trks2
0326 def trks1OutsideList(self): return self._trks1OutsideList
0327 def trks2OutsideList(self): return self._trks2OutsideList
0328
0329 def hasCommonTrackingParticle(self):
0330 trkGen = itertools.chain(self._trks1, self._trks2)
0331 try:
0332 first = next(trkGen)
0333 except StopIteration:
0334 return False
0335 if first.nMatchedTrackingParticles() != 1:
0336 return False
0337
0338 tpIndex = next(first.matchedTrackingParticleInfos()).trackingParticle().index()
0339
0340 for t in trkGen:
0341 if t.nMatchedTrackingParticles() != 1:
0342 return False
0343 if next(t.matchedTrackingParticleInfos()).trackingParticle().index() != tpIndex:
0344 return False
0345 return True
0346
0347
0348 def merge(self, other):
0349 self.extendTrks1(other._trks1)
0350 self.extendTrks2(other._trks2)
0351 self.extendTrks1OutsideList(other._trks1OutsideList)
0352 self.extendTrks2OutsideList(other._trks2OutsideList)
0353
0354 def minEta(self):
0355 _min = lambda lst: min([t.eta() for t in lst])
0356
0357 if len(self._trks1) > 0:
0358 return _min(self._trks1)
0359 if len(self._trks1OutsideList) > 0:
0360 return _min(self._trks1OutsideList)
0361 if len(self._trks2) > 0:
0362 return _min(self._trks2)
0363 if len(self._trks2_outsideList) > 0:
0364 return _min(self._trks2OutsideList)
0365 raise Exception("This _TrackAssociation is empty, minEta() makes no sense")
0366
0367 def __str__(self):
0368 s = lambda l: str([t.index() for t in l])
0369 return s(self._trks1)+" "+s(self._trks2)+" "+s(self._trks1OutsideList)+" "+s(self._trks2OutsideList)
0370
0371 def _associateTracksByTrackingParticlesAndHits(lst1, lst2):
0372 trks1 = list(lst1)
0373 trks2 = list(lst2)
0374
0375 trks1Matcher = _TracksByHitsMatcher(trks1)
0376 trks2Matcher = _TracksByHitsMatcher(trks2)
0377
0378
0379 trks1Dict = {t.index(): t for t in trks1}
0380 trks2Dict = {t.index(): t for t in trks2}
0381
0382
0383 tps1 = None
0384 tps2 = None
0385 if len(trks1) > 0:
0386 tps1 = TrackingParticles(trks1[0]._tree)
0387 if len(trks2) > 0:
0388 tps2 = TrackingParticles(trks2[0]._tree)
0389
0390 trkAssoc1 = {}
0391 trkAssoc2 = {}
0392
0393 def _getOrCreateAssoc(trk, d, **kwargs):
0394 if trk.index() in d:
0395 a = d[trk.index()]
0396 else:
0397 a = _TrackAssociation()
0398 d[trk.index()] = a
0399 a.extend(**kwargs)
0400 return a
0401
0402 while len(trks1) > 0:
0403 trk1 = trks1.pop(0)
0404 assoc1 = _getOrCreateAssoc(trk1, trkAssoc1, trks1=[trk1])
0405
0406
0407 if trk1.nMatchedTrackingParticles() > 0 and tps2:
0408 matched = False
0409
0410 for tpInfo1 in trk1.matchedTrackingParticleInfos():
0411 tp1 = tpInfo1.trackingParticle()
0412
0413
0414 for trkInfo1 in tp1.matchedTrackInfos():
0415 t1 = trkInfo1.track()
0416 t1Index = t1.index()
0417 if t1Index != trk1.index():
0418 if t1Index in trks1Dict:
0419 assoc1.extend(trks1=[t1])
0420 _getOrCreateAssoc(t1, trkAssoc1, trks1=[t1, trk1])
0421
0422 trks1.remove(trks1Dict[t1Index])
0423 else:
0424
0425 assoc1.extend(trks1OutsideList=[t1])
0426
0427
0428 tp2 = tps2[tp1.index()]
0429 for trkInfo2 in tp2.matchedTrackInfos():
0430 matched = True
0431 t2 = trkInfo2.track()
0432 t2Index = t2.index()
0433 if t2Index in trks2Dict:
0434 assoc1.extend(trks2=[t2])
0435 _getOrCreateAssoc(t2, trkAssoc2, trks1=[trk1], trks2=[t2])
0436
0437 try:
0438 trks2.remove(trks2Dict[t2Index])
0439 except ValueError:
0440 pass
0441 else:
0442
0443 assoc1.extend(trks2OutsideList=[t2])
0444
0445 if matched:
0446 continue
0447
0448
0449
0450 (matchedTrk2, ncommon) = trks2Matcher.match(trk1)
0451 if matchedTrk2 is not None and ncommon >= 3:
0452 assoc1.extend(trks2=[matchedTrk2])
0453 assoc2 = _getOrCreateAssoc(matchedTrk2, trkAssoc2, trks1=[trk1], trks2=[matchedTrk2])
0454
0455 try:
0456 trks2.remove(matchedTrk2)
0457 except ValueError:
0458 pass
0459
0460 (matchedTrk1, ncommon1) = trks1Matcher.match(matchedTrk2)
0461
0462 if (matchedTrk1.nMatchedTrackingParticles() == 0 or not tps2) and matchedTrk1.index() != trk1.index():
0463 assoc2.extend(trks1=[matchedTrk1])
0464 _getOrCreateAssoc(matchedTrk1, trkAssoc1, trks1=[matchedTrk1], trks2=[matchedTrk2])
0465
0466
0467
0468
0469
0470 for trk2 in trks2:
0471 assoc2 = _getOrCreateAssoc(trk2, trkAssoc2, trks2=[trk2])
0472
0473 if trk2.nMatchedTrackingParticles() > 0:
0474 for tpInfo2 in trk2.matchedTrackingParticleInfos():
0475 tp2 = tpInfo2.trackingParticle()
0476 for trkInfo2 in tp2.matchedTrackInfos():
0477 t2 = trkInfo2.track()
0478 t2Index = t2.index()
0479 if t2Index in trks2Dict:
0480 assoc2.extend(trks2=[t2])
0481
0482 else:
0483 assoc2.extend(trks2OutsideList=[t2])
0484
0485
0486
0487
0488 for ind, assoc in trkAssoc1.items():
0489 for t1 in assoc.trks1():
0490 a = trkAssoc1[t1.index()]
0491 assoc.merge(a)
0492 a.merge(assoc)
0493 for t2 in assoc.trks2():
0494 a = trkAssoc2[t2.index()]
0495 assoc.merge(a)
0496 a.merge(assoc)
0497 for ind, assoc in trkAssoc2.items():
0498 for t2 in assoc.trks2():
0499 a = trkAssoc2[t2.index()]
0500 assoc.merge(a)
0501 a.merge(assoc)
0502 for t1 in assoc.trks1():
0503 a = trkAssoc1[t1.index()]
0504 assoc.merge(a)
0505 a.merge(assoc)
0506
0507 for ind, assoc in itertools.chain(trkAssoc1.items(), trkAssoc2.items()):
0508
0509
0510
0511 for t1 in assoc.trks1():
0512 a = trkAssoc1[t1.index()]
0513 assoc.merge(a)
0514 a.merge(assoc)
0515
0516
0517
0518
0519 for t2 in assoc.trks2():
0520 a = trkAssoc2[t2.index()]
0521 assoc.merge(a)
0522 a.merge(assoc)
0523
0524
0525
0526
0527
0528 allAssocs = []
0529 while len(trkAssoc1) > 0:
0530 (t1Index, assoc) = trkAssoc1.popitem()
0531
0532
0533
0534 for t1 in assoc.trks1():
0535 if t1.index() == t1Index: continue
0536 trkAssoc1.pop(t1.index())
0537 for t2 in assoc.trks2():
0538 trkAssoc2.pop(t2.index())
0539 allAssocs.append(assoc)
0540 while len(trkAssoc2) > 0:
0541 (t2Index, assoc) = trkAssoc2.popitem()
0542 if len(assoc.trks1()) > 0:
0543 raise Exception("len(assoc.trks1()) %d != 0 !!! %s for t2 %d" % (len(assoc.trks1()), str([t.index() for t in assoc.trks1()]), t2Index))
0544 for t2 in assoc.trks2():
0545 if t2.index() == t2Index: continue
0546 trkAssoc2.pop(t2.index())
0547 allAssocs.append(assoc)
0548
0549 return allAssocs
0550
0551 def diffTrackListsGeneric(trackPrinter, lst1, lst2, ignoreAdditionalLst2=False):
0552 associations = _associateTracksByTrackingParticlesAndHits(lst1, lst2)
0553
0554
0555 associations.sort(key=methodcaller("minEta"))
0556
0557 diff = _DiffResult()
0558 for assoc in associations:
0559 if assoc.hasCommonTrackingParticle():
0560 if len(assoc.trks1()) == 0 and ignoreAdditionalLst2:
0561 continue
0562
0563 tmp = diffTrackListsFromSameTrackingParticle(trackPrinter, assoc.trks1(), assoc.trks2(), lst1extra=assoc.trks1OutsideList(), lst2extra=assoc.trks2OutsideList(), diffByHitsOnly=True)
0564 if tmp.hasDifference():
0565 diff.extend(tmp)
0566 diff.extend([" "])
0567 elif len(assoc.trks1()) == 1 and len(assoc.trks2()) == 1:
0568 trk1 = assoc.trks1()[0]
0569 trk2 = assoc.trks2()[0]
0570
0571 if not _areSameTracks(trk1, trk2):
0572 diff.extend(trackPrinter.diff(trk1, trk2))
0573 diff.extend([" "])
0574 elif len(assoc.trks2()) == 0:
0575 for t in assoc.trks1():
0576 diff.extend(trackPrinter.diff(t, None))
0577 diff.extend([" "])
0578 elif len(assoc.trks1()) == 0:
0579 if ignoreAdditionalLst2:
0580 continue
0581 for t in assoc.trks1():
0582 diff.extend(trackPrinter.diff(None, t))
0583 diff.extend([" "])
0584 else:
0585
0586 trks1 = list(assoc.trks1())
0587 trks2 = list(assoc.trks2())
0588 trks1.sort(key=lambda t: next(t.hits()).r())
0589 trks2.sort(key=lambda t: next(t.hits()).r())
0590
0591
0592 ncommon = []
0593 for i1, t1 in enumerate(trks1):
0594 for i2, t2 in enumerate(trks2):
0595 ncommon.append( (i1, i2, _commonHits(t1, t2)) )
0596
0597
0598 ncommon.sort(key=itemgetter(2), reverse=True)
0599
0600
0601 pairs = [None]*len(trks1)
0602 usedT2 = [False]*len(trks2)
0603 for i1, i2, ncom in ncommon:
0604 if pairs[i1] is None:
0605 pairs[i1] = i2
0606 usedT2[i2] = True
0607
0608 for i1, i2 in enumerate(pairs):
0609 t1 = trks1[i1]
0610 t2 = trks2[i2]
0611 diff.extend(trackPrinter.diff(t1, t2))
0612 for i2, used in enumerate(usedT2):
0613 if not used:
0614 diff.extend(trackPrinter.diff(None, trks2[i2]))
0615 diff.extend([" "])
0616
0617 return diff
0618
0619 def _formatHitDiffForTwiki(diffHits, prefix):
0620 line_re = re.compile("(?P<sign>[ \\-+])\\s+(?P<det>[a-zA-Z]+)(?P<lay>\\d+)\\D*?(\\((?P<missing>missing|inactive)\\))?\\s+\\d+")
0621
0622 summary = []
0623 prevdet = ""
0624 prevsign = " "
0625 diffLines = diffHits.lines()
0626
0627
0628 for line in diffLines:
0629 if "hits" in line:
0630 break
0631
0632 header = True
0633 for line in diffLines:
0634
0635
0636 if header:
0637 if "hits" in line:
0638 continue
0639 else:
0640 header = False
0641
0642 m = line_re.search(line)
0643 if not m:
0644 break
0645 raise Exception("regex not found from line %s" % line.rstrip())
0646 sign = m.group("sign")
0647 det = m.group("det")
0648 lay = m.group("lay")
0649
0650 if det != prevdet:
0651 if prevsign != " ":
0652 summary.append("%ENDCOLOR%")
0653 prevsign = " "
0654 summary.extend([" ", det])
0655 prevdet = det
0656
0657 if sign != prevsign:
0658 if prevsign != " ":
0659 summary.append("%ENDCOLOR%")
0660 if sign == "-":
0661 summary.append("%RED%")
0662 elif sign == "+":
0663 summary.append("%GREEN%")
0664 prevsign = sign
0665
0666
0667
0668
0669
0670
0671
0672
0673
0674
0675
0676
0677
0678
0679
0680
0681 summary.append(lay)
0682 if m.group("missing"):
0683 if m.group("missing") == "missing":
0684 summary.append("(m)")
0685 elif m.group("missing") == "inactive":
0686 summary.append("(i)")
0687
0688 if prevsign != " ":
0689 summary.append("%ENDCOLOR%")
0690
0691 i = 2
0692 while i < len(summary)-5:
0693 if summary[i] == "(i)" or summary[i] == "(m)":
0694 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%":
0695 summary[i-2:i+6] = [summary[i-1], summary[i]]
0696 i += 1
0697
0698 line = " "+"".join(summary)
0699 return ["?"+prefix+line]
0700
0701
0702 def _hitPatternSummary(hits):
0703 summary = ""
0704
0705 prevdet = 0
0706 for hit in hits:
0707 det = hit.subdet()
0708 lay = hit.layer()
0709
0710 if det != prevdet:
0711 summary += " "+SubDet.toString(det)
0712 prevdet = det
0713
0714 summary += str(lay)
0715 if isinstance(hit, InvalidHit):
0716 summary += "(%s)"%InvalidHit.Type.toString(hit.type())[0]
0717
0718 return summary
0719
0720 class _IndentPrinter(object):
0721 def __init__(self, indent=0):
0722 self._prefix = " "*indent
0723 self._backup = []
0724
0725 def _indent(self, num):
0726 if num > 0:
0727 self._prefix += " "*num
0728 elif num < 0:
0729 self._prefix = self._prefix[:num]
0730
0731 def indent(self, num):
0732 self._backup.append(self._prefix)
0733 self._indent(num)
0734
0735 def setIndentFrom(self, printer, adjust=0):
0736 self._backup.append(self._prefix)
0737 self._prefix = printer._prefix
0738 self._indent(adjust)
0739
0740 def restoreIndent(self):
0741 self._prefix = self._backup.pop()
0742
0743 class _RecHitPrinter(_IndentPrinter):
0744 def __init__(self, indent=0):
0745 super(_RecHitPrinter, self).__init__(indent)
0746
0747 def _printHits(self, hits):
0748 lst = []
0749 for hit in hits:
0750 matched = ""
0751 glued = ""
0752 coord = ""
0753 if hit.isValidHit():
0754 if hasattr(hit, "matchedSimHitInfos"):
0755 matched = " from %s " % HitSimType.toString(hit.simType())
0756 matches = []
0757 hasChargeFraction = False
0758 for shInfo in hit.matchedSimHitInfos():
0759 m = "%d:%d" % (shInfo.simHit().trackingParticle().index(), shInfo.simHit().index())
0760 if hasattr(shInfo, "chargeFraction"):
0761 m += "(%.1f)"%(shInfo.chargeFraction()*100)
0762 hasChargeFraction = True
0763 matches.append(m)
0764 if len(matches) == 0:
0765 matched += "not matched to any TP/SimHit"
0766 else:
0767 matched += "matched to TP:SimHit"
0768 if hasChargeFraction:
0769 matched += "(%)"
0770 matched += " "+",".join(matches)
0771
0772 coord = "x,y,z %f,%f,%f" % (hit.x(), hit.y(), hit.z())
0773 if isinstance(hit, GluedHit):
0774 glued = "monoHit %d stereoHit %d " % (hit.monoHit().index(), hit.stereoHit().index())
0775
0776 lst.append(self._prefix+"{layer} {hit} detid {detid} {detidStr} {glued}{coord}{matched}".format(layer=hit.layerStr(), hit=hit.index(),
0777 detid=hit.detId(), detidStr=hit.detIdStr(),
0778 glued=glued, coord=coord, matched=matched))
0779 return lst
0780
0781 class _TrackingParticleMatchPrinter(object):
0782 def __init__(self, trackingParticles, trackingParticlePrinter, bestMatchingTrackingParticle):
0783 self._trackingParticles = trackingParticles
0784 self._trackingParticlePrinter = trackingParticlePrinter
0785 self._bestMatchingTrackingParticle = bestMatchingTrackingParticle
0786
0787 def bestMatchingTrackingParticle(self):
0788 return self._bestMatchingTrackingParticle
0789
0790 def _printTrackingParticles(self, prefix, tps, header):
0791 lst = []
0792 if self._trackingParticlePrinter is None:
0793 lst.append(prefix+header+" "+",".join([str(tp.index()) for tp in tps]))
0794 else:
0795 lst.append(prefix+header)
0796 for tp in tps:
0797 lst.extend(self._trackingParticlePrinter.printTrackingParticle(tp))
0798 lst.extend(self._trackingParticlePrinter.printHits(tp))
0799 lst.extend(self._trackingParticlePrinter.printMatchedTracks(tp, useTrackPrinter=False))
0800 return lst
0801
0802 def printMatchedTrackingParticles(self, prefix, track):
0803 lst = []
0804 if not self._trackingParticles:
0805 return lst
0806
0807 pfx = prefix+" "
0808 if self._trackingParticlePrinter is not None:
0809 self._trackingParticlePrinter.indent(len(pfx)+1)
0810
0811 if track.nMatchedTrackingParticles() == 0:
0812 if self._bestMatchingTrackingParticle:
0813 bestTP = track.bestMatchingTrackingParticle()
0814 if bestTP is not None:
0815 lst.extend(self._printTrackingParticles(pfx, [bestTP], "not matched to any TP, but a following TP with >= 3 matched hits is found (shared hit fraction %.2f)" % track.bestMatchingTrackingParticleShareFrac()))
0816 else:
0817 lst.append(prefix+"not matched to any TP")
0818 else:
0819 lst.append(prefix+"not matched to any TP")
0820 else:
0821 lst.extend(self._printTrackingParticles(pfx, [tpInfo.trackingParticle() for tpInfo in track.matchedTrackingParticleInfos()], "matched to TPs"))
0822
0823 if self._trackingParticlePrinter is not None:
0824 self._trackingParticlePrinter.restoreIndent()
0825
0826 return lst
0827
0828 class SeedPrinter(_RecHitPrinter):
0829 def __init__(self, indent=0, hits=True, trackingParticles=False, trackingParticlePrinter=None, bestMatchingTrackingParticle=True):
0830 super(SeedPrinter, self).__init__(indent)
0831 self._hits = hits
0832 self._trackingParticleMatchPrinter = _TrackingParticleMatchPrinter(trackingParticles, trackingParticlePrinter, bestMatchingTrackingParticle)
0833
0834 def printHeader(self, seed):
0835 lst = []
0836 track = seed.track()
0837 if track.isValid():
0838 madeTrack = "made track %d" % track.index()
0839 else:
0840 madeTrack = "did not make a track, stopReason %s" % SeedStopReason.toString(seed.stopReason())
0841 if seed.stopReason() == SeedStopReason.NOT_STOPPED:
0842 madeTrack += " (usually this means that the track was reconstructed, but rejected by the track selection)"
0843
0844 lst.append(self._prefix+"Seed %d algo %s %s" % (seed.indexWithinAlgo(), Algo.toString(seed.algo()), madeTrack))
0845 lst.append(self._prefix+" starting state: pT %f local pos x,y %f,%f mom x,y,z %f,%f,%f" % (seed.statePt(), seed.stateTrajX(), seed.stateTrajY(), seed.stateTrajPx(), seed.stateTrajPy(), seed.stateTrajPz()))
0846 return lst
0847
0848 def printHits(self, seed):
0849 lst = []
0850 if self._hits:
0851 lst.append(self._prefix+" hits"+_hitPatternSummary(seed.hits()))
0852 self.indent(2)
0853 lst.extend(self._printHits(seed.hits()))
0854 self.restoreIndent()
0855 return lst
0856
0857 def printMatchedTrackingParticles(self, seed):
0858 return self._trackingParticleMatchPrinter.printMatchedTrackingParticles(self._prefix, seed)
0859
0860 def printSeed(self, seed):
0861 lst = []
0862 lst.extend(self.printHeader(seed))
0863 lst.extend(self.printHits(seed))
0864 lst.extend(self.printMatchedTrackingParticles(seed))
0865 return lst
0866
0867 def __call__(self, seed, out=sys.stdout):
0868 if isinstance(out, list):
0869 lst = out
0870 else:
0871 lst = []
0872
0873 lst.extend(self.printSeed(seed))
0874
0875 if not isinstance(out, list):
0876 for line in lst:
0877 out.write(line),
0878 out.write("\n")
0879
0880 def diff(self, seed1, seed2, diffForTwiki=False, diffTrackingParticles=False):
0881 if seed1 is None:
0882 return _makediff([], self.printSeed(seed2))
0883 if seed2 is None:
0884 return _makediff(self.printSeed(seed1), [])
0885
0886 ret = _DiffResult()
0887 ret.extend(_mapdiff(self.printHeader, seed1, seed2))
0888 diffHits = _mapdiff(self.printHits, seed1, seed2)
0889 ret.extend(diffHits)
0890 if diffForTwiki:
0891 ret.extend(_formatHitDiffForTwiki(diffHits, self._prefix))
0892 if diffTrackingParticles:
0893 ret.extend(_mapdiff(self.printMatchedTrackingParticles, seed1, seed2))
0894 return ret
0895
0896 class TrackPrinter(_RecHitPrinter):
0897 def __init__(self, indent=0, hits=True, seedPrinter=SeedPrinter(), trackingParticles=True, trackingParticlePrinter=None, bestMatchingTrackingParticle=True, diffForTwiki=False):
0898 super(TrackPrinter, self).__init__(indent)
0899 self._hits = hits
0900 self._seedPrinter = seedPrinter
0901 self._trackingParticleMatchPrinter = _TrackingParticleMatchPrinter(trackingParticles, trackingParticlePrinter, bestMatchingTrackingParticle)
0902 self._diffForTwiki = diffForTwiki
0903
0904 def printHeader(self, track):
0905 lst = []
0906 lst.append(self._prefix+"Track %d pT %f eta %f phi %f dxy %f err %f dz %f err %f" % (track.index(), track.pt(), track.eta(), track.phi(), track.dxy(), track.dxyErr(), track.dz(), track.dzErr()))
0907
0908 hp = "loose"
0909 if track.isHP():
0910 hp = "HP"
0911
0912 algo = track.algo()
0913 oriAlgo = track.originalAlgo()
0914 algos = []
0915 algoMask = track.algoMask()
0916 for i in range(Algo.algoSize):
0917 if algoMask & 1:
0918 algos.append(Algo.toString(i))
0919 algoMask = algoMask >> 1
0920 algoMaskStr = ""
0921 if len(algos) >= 2:
0922 algoMaskStr = " algoMask "+",".join(algos)
0923
0924
0925 lst.append(self._prefix+" pixel hits %d strip hits %d chi2/ndof %f" % (track.nPixel(), track.nStrip(), track.nChi2()))
0926 lst.append(self._prefix+" is %s algo %s originalAlgo %s%s stopReason %s" % (hp, Algo.toString(track.algo()), Algo.toString(track.originalAlgo()), algoMaskStr, StopReason.toString(track.stopReason())))
0927 lst.append(self._prefix+" px %f py %f pz %f p %f" % (track.px(), track.py(), track.pz(), math.sqrt(track.px()**2+track.py()**2+track.pz()**2)))
0928 if self._trackingParticleMatchPrinter.bestMatchingTrackingParticle():
0929 bestTP = track.bestMatchingTrackingParticle()
0930 if bestTP:
0931 lst.append(self._prefix+" best-matching TP %d" % bestTP.index())
0932 lst.append(self._prefix+" shared hits %d reco denom %.3f sim denom %.3f sim cluster denom %.3f" % (track.bestMatchingTrackingParticleShareFrac()*track.nValid(), track.bestMatchingTrackingParticleShareFrac(), track.bestMatchingTrackingParticleShareFracSimDenom(), track.bestMatchingTrackingParticleShareFracSimClusterDenom()))
0933 lst.append(self._prefix+" matching chi2/ndof %f" % track.bestMatchingTrackingParticleNormalizedChi2())
0934 lst.append(self._prefix+" pulls pt %f theta %f phi %f dxy %f dz %f" % (track.ptPull(), track.thetaPull(), track.phiPull(), track.dxyPull(), track.dzPull()))
0935 return lst
0936
0937 def printHits(self, track):
0938 lst = []
0939 if self._hits:
0940 lst.append(self._prefix+" hits"+_hitPatternSummary(track.hits()))
0941 self.indent(2)
0942 lst.extend(self._printHits(track.hits()))
0943 self.restoreIndent()
0944 return lst
0945
0946 def printSeed(self, track):
0947 lst = []
0948 if self._seedPrinter:
0949 self._seedPrinter.setIndentFrom(self, adjust=1)
0950 lst.extend(self._seedPrinter.printSeed(track.seed()))
0951 self._seedPrinter.restoreIndent()
0952 return lst
0953
0954 def diffSeeds(self, track1, track2):
0955 ret = _DiffResult()
0956 if self._seedPrinter:
0957 self._seedPrinter.setIndentFrom(self, adjust=1)
0958 ret.extend(self._seedPrinter.diff(track1.seed(), track2.seed(), self._diffForTwiki))
0959 self._seedPrinter.restoreIndent()
0960 return ret
0961
0962 def printTrack(self, track):
0963 lst = self.printHeader(track)
0964 lst.extend(self.printHits(track))
0965 lst.extend(self.printSeed(track))
0966 return lst
0967
0968 def printMatchedTrackingParticles(self, track):
0969 return self._trackingParticleMatchPrinter.printMatchedTrackingParticles(self._prefix, track)
0970
0971 def printTrackAndMatchedTrackingParticles(self, track):
0972 lst = []
0973 lst.extend(self.printTrack(track))
0974 lst.extend(self.printMatchedTrackingParticles(track))
0975 return lst
0976
0977 def __call__(self, track, out=sys.stdout):
0978 if isinstance(out, list):
0979 lst = out
0980 else:
0981 lst = []
0982
0983 lst.extend(self.printTrackAndMatchedTrackingParticles(track))
0984
0985 if not isinstance(out, list):
0986 for line in lst:
0987 out.write(line)
0988 out.write("\n")
0989
0990 def diff(self, track1, track2, diffTrackingParticles=True):
0991 if track1 is None:
0992 lst = self.printTrack(track2) + self.printMatchedTrackingParticles(track2)
0993 return _makediff([], lst)
0994 if track2 is None:
0995 lst = self.printTrack(track1) + self.printMatchedTrackingParticles(track1)
0996 return _makediff(lst, [])
0997
0998 ret = _DiffResult()
0999 ret.extend(_mapdiff(self.printHeader, track1, track2))
1000 if self._diffForTwiki:
1001 trk1TPs = [tpInfo.trackingParticle() for tpInfo in track1.matchedTrackingParticleInfos()]
1002 trk2TPs = [tpInfo.trackingParticle() for tpInfo in track2.matchedTrackingParticleInfos()]
1003
1004 pt_pull1 = "None"
1005 pt_pull2 = "None"
1006 dxy_pull1 = "None"
1007 dxy_pull2 = "None"
1008 dz_pull1 = "None"
1009 dz_pull2 = "None"
1010
1011 ptPull1 = track1.ptPull()
1012 ptPull2 = track2.ptPull()
1013 if ptPull1 is not None and ptPull2 is not None:
1014 fmt = "{pull:.3g}"
1015 pt_pull1 = fmt.format(pull=ptPull1)
1016 pt_pull2 = fmt.format(pull=ptPull2)
1017 dxy_pull1 = fmt.format(pull=track1.dxyPull())
1018 dxy_pull2 = fmt.format(pull=track2.dxyPull())
1019 dz_pull1 = fmt.format(pull=track1.dzPull())
1020 dz_pull2 = fmt.format(pull=track2.dzPull())
1021
1022 lst = [
1023 self._prefix+" parameters",
1024 self._prefix+" pt %RED%{pt1:.3g}%ENDCOLOR% %GREEN%{pt2:.3g}%ENDCOLOR%".format(pt1=track1.pt(), pt2=track2.pt()),
1025 ]
1026 if pt_pull1 != "None":
1027 lst.append(self._prefix+" pull %RED%{pull1}%ENDCOLOR% %GREEN%{pull2}%ENDCOLOR%".format(pull1=pt_pull1, pull2=pt_pull2))
1028 lst.extend([
1029 self._prefix+" eta %RED%{eta1:.3g}%ENDCOLOR% %GREEN%{eta2:.3g}%ENDCOLOR%".format(eta1=track1.eta(), eta2=track2.eta()),
1030 self._prefix+" phi %RED%{phi1:.3g}%ENDCOLOR% %GREEN%{phi2:.3g}%ENDCOLOR%".format(phi1=track1.phi(), phi2=track2.phi()),
1031 self._prefix+" dxy %RED%{dxy1:.3g}%ENDCOLOR% %GREEN%{dxy2:.3g}%ENDCOLOR% ({dxy1rel:.2f}*err1, {dxy2rel:.2f}*err2)".format(dxy1=track1.dxy(), dxy2=track2.dxy(), dxy1rel=(track2.dxy()-track1.dxy())/track1.dxyErr(), dxy2rel=(track2.dxy()-track1.dxy())/track2.dxyErr()),
1032 ])
1033 if dxy_pull1 != "None":
1034 lst.append(self._prefix+" pull %RED%{pull1}%ENDCOLOR% %GREEN%{pull2}%ENDCOLOR%".format(pull1=dxy_pull1, pull2=dxy_pull2))
1035 lst.extend([
1036 self._prefix+" dz %RED%{dz1:.3g}%ENDCOLOR% %GREEN%{dz2:.3g}%ENDCOLOR% ({dz1rel:.2f}*err1, {dz2rel:.2f}*err2)".format(dz1=track1.dz(), dz2=track2.dz(), dz1rel=(track2.dz()-track1.dz())/track1.dzErr(), dz2rel=(track2.dz()-track1.dz())/track2.dzErr()),
1037 ])
1038 if dz_pull1 != "None":
1039 lst.append(self._prefix+" pull %RED%{pull1}%ENDCOLOR% %GREEN%{pull2}%ENDCOLOR%".format(pull1=dz_pull1, pull2=dz_pull2))
1040 lst.extend([
1041 self._prefix+" chi2/ndof %RED%{chi1:.3g}%ENDCOLOR% %GREEN%{chi2:.3g}%ENDCOLOR%".format(chi1=track1.nChi2(), chi2=track2.nChi2()),
1042 ])
1043 ret.extend(_makediff(lst, lst, equalPrefix="?"))
1044
1045 diffHits = _mapdiff(self.printHits, track1, track2)
1046 ret.extend(diffHits)
1047 if self._hits and self._diffForTwiki:
1048 ret.extend(_formatHitDiffForTwiki(diffHits, self._prefix))
1049
1050 ret.extend(self.diffSeeds(track1, track2))
1051 if diffTrackingParticles:
1052 ret.extend(_mapdiff(self.printMatchedTrackingParticles, track1, track2))
1053 return ret
1054
1055 class TrackingParticlePrinter(_IndentPrinter):
1056 def __init__(self, indent=0, parentage=True, hits=True, tracks=True, trackPrinter=None, bestMatchingTrack=True, seedPrinter=SeedPrinter()):
1057 super(TrackingParticlePrinter, self).__init__(indent)
1058 self._parentage = parentage
1059 self._hits = hits
1060 self._tracks = tracks
1061 self._trackPrinter = trackPrinter
1062 self._bestMatchingTrack = bestMatchingTrack
1063 self._seedPrinter = seedPrinter
1064
1065 def _printTP(self, tp):
1066 genIds = ""
1067 if len(tp.genPdgIds()) > 0:
1068 genIds = " genPdgIds "+",".join([str(pdgId) for pdgId in tp.genPdgIds()])
1069 fromB = ""
1070 if tp.isFromBHadron():
1071 fromB = " from B hadron"
1072 return [
1073 self._prefix+"TP %d pdgId %d%s%s ev:bx %d:%d pT %f eta %f phi %f" % (tp.index(), tp.pdgId(), genIds, fromB, tp.event(), tp.bunchCrossing(), tp.pt(), tp.eta(), tp.phi()),
1074 self._prefix+" pixel hits %d strip hits %d numberOfTrackerHits() %d associated reco clusters %d dxy %f dz %f" % (tp.nPixel(), tp.nStrip(), tp.nTrackerHits(), tp.nRecoClusters(), tp.pca_dxy(), tp.pca_dz())
1075 ]
1076
1077
1078 def _parentageChain(self, tp):
1079 lst = []
1080 prodVtx = tp.parentVertex()
1081 if prodVtx.nSourceTrackingParticles() == 1:
1082 lst.extend(self._printTP(next(prodVtx.sourceTrackingParticles())))
1083 elif prodVtx.nSourceTrackingParticles() >= 2:
1084 self.indent(1)
1085 for tp in prodVtx.sourceTrackingParticles():
1086 self._printTP(tp, out)
1087 self.indent(1)
1088 lst.extend(self._parentageChain(tp))
1089 self.indent(-1)
1090 self.indent(-1)
1091 return lst
1092
1093 def printTrackingParticle(self, tp):
1094 lst = []
1095 lst.extend(self._printTP(tp))
1096 if self._parentage:
1097 if tp.parentVertex().nSourceTrackingParticles() > 0:
1098 lst.append(self._prefix+" parentage chain")
1099 self.indent(2)
1100 lst.extend(self._parentageChain(tp))
1101 self.indent(-2)
1102 return lst
1103
1104 def printHits(self, tp):
1105 lst = []
1106 if self._hits:
1107 lst.append(self._prefix+" sim hits"+_hitPatternSummary(tp.simHits()))
1108 for simhit in tp.simHits():
1109 tmp = []
1110 for h in simhit.hits():
1111 tmp.append(",".join([str(trk.index()) for trk in h.tracks()]) + ":%d"%h.index())
1112 if len(tmp) == 0:
1113 matched = "not matched to any Track/RecHit"
1114 else:
1115 matched = "matched to Tracks:RecHits "+";".join(tmp)
1116
1117 lst.append(self._prefix+" %s %d pdgId %d process %d detId %d %s x,y,z %f,%f,%f %s" % (simhit.layerStr(), simhit.index(), simhit.particle(), simhit.process(), simhit.detId(), simhit.detIdStr(), simhit.x(), simhit.y(), simhit.z(), matched))
1118 return lst
1119
1120 def _printMatchedTracksHeader(self):
1121 return [self._prefix+" matched to tracks"]
1122
1123 def _printMatchedTracks(self, tracks, header=None, useTrackPrinter=True):
1124 lst = []
1125 if header is not None:
1126 lst.append(self._prefix+" "+header)
1127 else:
1128 lst.extend(self._printMatchedTracksHeader())
1129 if self._trackPrinter is None or not useTrackPrinter:
1130 lst[-1] += " "+",".join([str(track.index()) for track in tracks])
1131 else:
1132 self._trackPrinter.indent(2)
1133 for track in tracks:
1134 lst.extend(self._trackPrinter.printTrack(track))
1135 self._trackPrinter.restoreIndent()
1136 return lst
1137
1138 def printMatchedTracks(self, tp, useTrackPrinter=True):
1139 lst = []
1140 if tp.nMatchedTracks() == 0:
1141 header = "not matched to any track"
1142 lst.append(self._prefix+" "+header)
1143 if self._bestMatchingTrack:
1144 bestTrack = tp.bestMatchingTrack()
1145 if bestTrack is not None:
1146 lst.pop()
1147 lst.extend(self._printMatchedTracks([bestTrack], header+", but a following track with >= 3 matched hits is found", useTrackPrinter=useTrackPrinter))
1148 else:
1149 lst.extend(self._printMatchedTracks([trkInfo.track() for trkInfo in tp.matchedTrackInfos()], useTrackPrinter=useTrackPrinter))
1150 return lst
1151
1152 def diffMatchedTracks(self, tp1, tp2):
1153 ntrk1 = tp1.nMatchedTracks()
1154 ntrk2 = tp2.nMatchedTracks()
1155
1156 if ntrk1 == 0 or ntrk2 == 0 or self._trackPrinter is None:
1157 return _makediff(self.printMatchedTracks(tp1), self.printMatchedTracks(tp2))
1158
1159 self._trackPrinter.indent(2)
1160
1161 diff = _makediff(self._printMatchedTracksHeader(), self._printMatchedTracksHeader())
1162 trks1 = [trkInfo1.track() for trkInfo1 in tp1.matchedTrackInfos()]
1163 trks2 = [trkInfo2.track() for trkInfo2 in tp2.matchedTrackInfos()]
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176 diff.extend(diffTrackListsFromSameTrackingParticle(self._trackPrinter, trks1, trks2))
1177
1178 self._trackPrinter.restoreIndent()
1179 return diff
1180
1181 def _printMatchedSeeds0(self):
1182 return [self._prefix+ " not matched to any seed"]
1183
1184 def _printMatchedSeedsHeader(self):
1185 return [self._prefix+" matched to seeds"]
1186
1187 def printMatchedSeeds(self, tp):
1188 lst = []
1189 if self._seedPrinter:
1190 if tp.nMatchedSeeds() == 0:
1191 lst.extend(self._printMatchedSeeds0())
1192 else:
1193 lst.extend(self._printMatchedSeedsHeader())
1194 self._seedPrinter.setIndentFrom(self, adjust=2)
1195 for seedInfo in tp.matchedSeedInfos():
1196 lst.extend(self._seedPrinter.printSeed(seedInfo.seed()))
1197 self._seedPrinter.restoreIndent()
1198 return lst
1199
1200 def diffMatchedSeeds(self, tp1, tp2):
1201 if not self._seedPrinter:
1202 return []
1203
1204 nseed1 = tp1.nMatchedSeeds()
1205 nseed2 = tp2.nMatchedSeeds()
1206 if nseed1 == 0 or nseed2 == 0:
1207 return _makediff(self.printMatchedSeeds(tp1), self.printMatchedSeeds(tp2))
1208
1209 self._seedPrinter.setIndentFrom(self, adjust=2)
1210
1211 diff = _makediff(self._printMatchedSeedsHeader(), self._printMatchedSeedsHeader())
1212 seeds2 = [seedInfo2.seed() for seedInfo2 in tp2.matchedSeedInfos()]
1213 for seedInfo1 in tp1.matchedSeedInfos():
1214 seed1 = seedInfo1.seed()
1215 matchedSeed2 = _matchTracksByHits(seed1, seeds2)[0]
1216
1217 if matchedSeed2 is None:
1218 diff.extend(_makediff(self._seedPrinter.printSeed(seed1), []))
1219 else:
1220 seeds2.remove(matchedSeed2)
1221 diff.extend(_makediff(self._seedPrinter.printSeed(seed1), self._seedPrinter.printSeed(matchedSeed2)))
1222
1223 for seed2 in seeds2:
1224 diff.extend(_makediff([], self._seedPrinter.printSeed(seed2)))
1225
1226 self._seedPrinter.restoreIndent()
1227
1228 return diff
1229
1230 def __call__(self, tp, out=sys.stdout):
1231 if isinstance(out, list):
1232 lst = out
1233 else:
1234 lst = []
1235
1236 lst.extend(self.printTrackingParticle(tp))
1237 lst.extend(self.printHits(tp))
1238 lst.extend(self.printMatchedTracks(tp))
1239 lst.extend(self.printMatchedSeeds(tp))
1240
1241 for line in lst:
1242 out.write(line)
1243 out.write("\n")
1244
1245 def diff(self, tp1, tp2):
1246 ret = _DiffResult()
1247 ret.extend(_mapdiff(self.printTrackingParticle, tp1, tp2))
1248 ret.extend(_mapdiff(self.printHits, tp1, tp2))
1249 ret.extend(self.diffMatchedTracks(tp1, tp2))
1250 ret.extend(self.diffMatchedSeeds(tp1, tp2))
1251 return ret
1252