1 package org.lcsim.recon.cat;
2
3 import java.util.*;
4 import org.lcsim.recon.cat.util.Const;
5 import org.lcsim.event.*;
6 import org.lcsim.util.Driver;
7 import org.lcsim.geometry.IDDecoder;
8 import org.lcsim.util.aida.AIDA;
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 final public class GarfieldTrackFinder extends Driver{
33
34
35
36 static final int APPEND = 0;
37 static final int OVERWRITE = 1;
38 static final int NONE = 2;
39
40 static final int YES = 1;
41 static final int NO = 0;
42
43
44
45 private List<GarfieldHit> listOfHits;
46 private int listOfHitsLowestLayer, listOfHitsHighestLayer;
47 private List<GarfieldHit> selectedHits;
48
49 private GarfieldHitConverter hitConverter;
50
51
52
53 static double k_cm = 10.;
54 private int garfieldnTRKHitMin = 3;
55 private boolean refitDuringPatternReco = true;
56 private double garfieldChi2ContribCut = 50.;
57 private double garfieldChi2Cut = 100.;
58 private double garfieldChi2Cut3Ndf=50.;
59 private double garfieldKappaCut3Ndf=1./(50. * k_cm);
60 private double scaleSearchRegion = 3.;
61 private double maxDistanceFirstHitToBase = 40.*k_cm;
62 private int nNewHitsMax=5;
63 private int nFitIterations=5;
64
65
66
67 private int modeModifyTracklist = APPEND;
68 private boolean modeUseVXD = true;
69 private boolean modeBestTrackOnly = true;
70 private boolean modeFromOutsideIn = true;
71 private boolean modeUseAllMipStubs = true;
72 private int pickEventNo=-1;
73 private int pickMipStubNo=-1;
74 private double pickMipStubAngle=-100000.;
75
76
77
78
79 private int debugLevel = 0;
80
81
82
83
84 private int issuedTrackIDValue;
85 private double minDistanceInHits;
86 private GarfieldHit bestHit;
87 private int bestTrackID;
88 private double bestGrade;
89 static int maxTrkNmbr=10000;
90 static double bfield = 5.;
91
92
93
94
95
96
97
98
99 public GarfieldTrackFinder() {this(0);}
100
101
102
103
104
105
106
107 public GarfieldTrackFinder(int debugLevel) {
108 selectedHits = new ArrayList<GarfieldHit>();
109 this.debugLevel = debugLevel;
110 minDistanceInHits=0.;
111 issuedTrackIDValue=0;
112 }
113
114
115
116
117
118
119
120 public void setDebugLevel(int i){ debugLevel = i;}
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162 public void setMode(String category, int mode) {
163
164 if (category.equalsIgnoreCase("Modify Event TrackList")) {
165 switch (mode) {
166 case APPEND :
167 modeModifyTracklist = APPEND; break;
168 case OVERWRITE :
169 modeModifyTracklist = OVERWRITE; break;
170 case NONE :
171 modeModifyTracklist = NONE; break;
172 default :
173 throw new IllegalArgumentException("Garfield track finder : Unknown mode");
174 }
175
176 } else if (category.equalsIgnoreCase("Use VXD Hits")) {
177 modeUseVXD = (mode == YES);
178
179 } else if (category.equalsIgnoreCase("Best Track Only")) {
180 modeBestTrackOnly = (mode == YES);
181
182 } else if (category.equalsIgnoreCase("From Outside In")) {
183 modeFromOutsideIn = (mode == YES);
184
185 } else if (category.equalsIgnoreCase("Refit During PatternReco")) {
186 refitDuringPatternReco = (mode == YES);
187
188 } else if (category.equalsIgnoreCase("Use All MipStubs")) {
189 modeUseAllMipStubs = (mode == YES);
190
191 } else {
192 throw new IllegalArgumentException("Garfield track finder : Unknown mode category");
193 }
194 }
195
196
197 public void setNNewHitsMax(int i){ nNewHitsMax= i;};
198 public void setNTrkHitMin(int i){ garfieldnTRKHitMin = i;};
199 public void setNFitIterations(int i){ nFitIterations=i;}
200 public void setChi2ContribCut(double d){ garfieldChi2ContribCut = d;}
201 public void setChi2Cut(double d){ garfieldChi2Cut = d;}
202 public void setScaleSearchRegion(double d){ scaleSearchRegion=d;}
203
204 public void setPickEventNo(int i){ pickEventNo=i;}
205
206 public void setPickMipStubNo(int i){ pickMipStubNo=i;}
207
208 public void setPickMipStubAngle(double a){ pickMipStubAngle=a;}
209
210
211
212
213
214
215
216 public void process(EventHeader event) {
217
218
219
220 issuedTrackIDValue=0;
221 ArrayList<GarfieldTrack> listGarfieldTracks = new ArrayList<GarfieldTrack>();
222
223
224
225 int eventNumber = event.getEventNumber();
226 if (debugLevel>=1) System.out.println("GarfieldTrackFinder ev="+eventNumber);
227 if (pickEventNo>=0 && pickEventNo!=eventNumber) {
228 event.put("GarfieldTracks", listGarfieldTracks);
229 return;
230 }
231
232
233
234 List<MipStub> listMipStub;
235 if (modeUseAllMipStubs){
236 listMipStub = event.get(MipStub.class,"GarfieldMipStubs");
237 } else {
238 listMipStub = event.get(MipStub.class,"UnassociatedGarfieldMipStubs");
239 }
240
241 listOfHits = event.get(GarfieldHit.class, "GarfieldHits");
242 if (!listOfHits.isEmpty()) {
243 listOfHitsLowestLayer = listOfHits.get(listOfHits.size()-1).getLayer();
244 listOfHitsHighestLayer = listOfHits.get(0).getLayer();
245 if (debugLevel>=2){
246 System.out.println("GarfieldTrackFinder hit lowest/highest layer "
247 + listOfHitsLowestLayer + " " + listOfHitsHighestLayer);
248 System.out.println("GarfieldTrackFinder barrelLayerVXD "+Const.det().VXD_BARREL.nLayers() +
249 " tracker="+ Const.det().TRACKER_BARREL.nLayers() +
250 " tracker endcap="+Const.det().TRACKER_ENDCAP.nLayers());
251
252 for (GarfieldHit hh : listOfHits) { hh.debug();}
253
254 }
255
256 }
257
258
259
260 int iMipStub = 0;
261
262 for (MipStub mStub : listMipStub) {
263
264 iMipStub++;
265 bestGrade = -1.E12;
266 bestTrackID= -1;
267
268 if ((pickMipStubNo>=0 && iMipStub!=pickMipStubNo) ||
269 (pickMipStubAngle>-100. && Math.abs(pickMipStubAngle - mStub.getPhi())>10./180.*Math.PI)){
270 continue;
271 }
272
273 List<GarfieldTrack> listTemporaryTracks = new ArrayList<GarfieldTrack>();
274 GarfieldTrack newTrk = new GarfieldTrack(mStub, debugLevel);
275 newTrk.setID(issueTrackID());
276 listTemporaryTracks.add(newTrk);
277
278
279
280
281 int ii = 0;
282 boolean done = false;
283 while(!done) {
284 GarfieldTrack g = (GarfieldTrack) listTemporaryTracks.get(ii);
285 if (debugLevel>=2){
286 System.out.println("GarfieldTrackFinder, next track = "+g.getID());
287 g.debug();
288 }
289
290
291
292 getNextHits(g,1.);
293 if (selectedHits.size()==0 && g.getEquivnHits()>0){
294 getNextHits(g,scaleSearchRegion);
295 }
296 if (selectedHits.size()==0 && g.getEquivnHits()>1){
297 g.fastChi2Fit(this.nFitIterations);
298 getNextHits(g,this.scaleSearchRegion);
299 }
300
301
302
303
304 int nNewHits = selectedHits.size();
305 if (nNewHits==0) {
306
307 if (debugLevel>=2) System.out.println("GarfieldTrackFinder done with picking up hits track="+g.getID()+", nhit="+g.getnHits()+" helix base="+g.hel.base(0)+" "+g.hel.base(1)+"minD="+this.minDistanceInHits);
308 } else if (nNewHits > nNewHitsMax){
309 if (debugLevel >=2) System.out.println("GarfieldTrackFinder process: too many new hits nHNew="+nNewHits+" adding best Hit only");
310 GarfieldTrack gNew = new GarfieldTrack(g);
311 gNew.setID(issueTrackID());
312 if (addHit(gNew,bestHit)){listTemporaryTracks.add(gNew);}
313 } else {
314 for (int j = 0 ; j<nNewHits ; j++){
315 GarfieldHit h = (GarfieldHit) selectedHits.get(j);
316 GarfieldTrack gNew = new GarfieldTrack(g);
317 gNew.setID(issueTrackID());
318 if (addHit(gNew,h)) listTemporaryTracks.add(gNew);
319 if (listTemporaryTracks.size() > maxTrkNmbr){
320 panicPurge(listTemporaryTracks,maxTrkNmbr);
321 }
322 }
323 }
324
325 if (debugLevel>=3) System.out.println("GarfieldTrackFinder done with temporary track "+g.getID());
326 ii++;
327 done = ii == listTemporaryTracks.size();
328 }
329
330 if (debugLevel>=2) System.out.println("GarfieldTrackFinder finished creating track seed using MipStub. nTracks="+listTemporaryTracks.size());
331 int mipStubStartInTrackList = listGarfieldTracks.size();
332
333
334
335
336 ListIterator k = listTemporaryTracks.listIterator();
337 while (k.hasNext()) {
338 GarfieldTrack gg = (GarfieldTrack) k.next();
339 if (gg.isRejected()) continue;
340 if (gg.getEquivnHits()<garfieldnTRKHitMin) continue;
341
342 if (gg.getnHits()<garfieldnTRKHitMin) continue;
343 if (gg.getNdf()<=3){
344 double kabs = Math.abs(gg.hel.kappa());
345 if (gg.getChi2()/gg.getNdf()>this.garfieldChi2Cut3Ndf) continue;
346 if (kabs>this.garfieldKappaCut3Ndf) continue;
347 }
348 if (gg.getNumberOfStepovers()>1) continue;
349 gg.fastChi2Fit(this.nFitIterations*4);
350 if (gg.getChi2()/gg.getNdf() < garfieldChi2Cut){
351 gg.setTrackParameters();
352 gg.setRadii();
353 gg.setGrade(garfieldChi2ContribCut);
354 gg.setDone();
355 if (gg.getGrade()>bestGrade){
356 bestTrackID =gg.getID();
357 bestGrade =gg.getGrade();
358 }
359 listGarfieldTracks.add(gg);
360 if (debugLevel >=2) System.out.println("*accepting track "+gg.getID()+", nH="+gg.getnHits()+" chi2="+gg.getChi2()+" ndf="+gg.getNdf()+" cutvalue="+this.garfieldChi2Cut);
361 } else {
362 if (debugLevel >=2) System.out.println("rejecting track "+gg.getID()+", nH="+gg.getnHits()+" chi2="+gg.getChi2()+" ndf="+gg.getNdf()+" cutvalue="+this.garfieldChi2Cut);
363 }
364 if (debugLevel >=3) gg.debug();
365 if (debugLevel >=3) System.out.println("******************");
366 }
367
368 if (debugLevel>=3) System.out.println("clearing listTemporaryTracks");
369
370
371
372
373 if (modeBestTrackOnly){
374 for (int k1=mipStubStartInTrackList; k1<listGarfieldTracks.size(); k1++) {
375 GarfieldTrack gg1 = (GarfieldTrack) listGarfieldTracks.get(k1);
376 if (gg1.getID() != bestTrackID) gg1.purgeTrack();
377 }
378 }
379
380 listTemporaryTracks.clear();
381 }
382
383
384
385 if (debugLevel > 0) System.out.println("GarfieldTrackFinder purging tracks now");
386 for (int k1=0;k1<listGarfieldTracks.size();k1++){
387 GarfieldTrack gg1 = (GarfieldTrack) listGarfieldTracks.get(k1);
388 if (gg1.isPurged()) continue;
389 int nh1 = gg1.getnHits();
390 for (int k2=k1+1;k2<listGarfieldTracks.size();k2++){
391 GarfieldTrack gg2 = (GarfieldTrack) listGarfieldTracks.get(k2);
392 if (gg2.isPurged()) continue;
393 int nh2 = gg2.getnHits();
394 double overLap=overlapRatio(gg1,gg2);
395 if (overLap>0.35){
396
397 if (gg1.getGrade() < gg2.getGrade()) gg1.purgeTrack();
398 else gg2.purgeTrack();
399 if (debugLevel > 1) System.out.println("purged one of pair "+gg1.getID()+" "+gg2.getID());
400 }
401 }
402 }
403
404
405
406 int nPurged = 0;
407 ArrayList<GarfieldTrack> listGarfieldTracksGood = new ArrayList();
408 int NTrks=0;
409 for (int k=0;k<listGarfieldTracks.size();k++){
410 GarfieldTrack gg = (GarfieldTrack) listGarfieldTracks.get(k);
411 if (! gg.isPurged()){
412 gg.fullChi2Fit(0.05, this.nFitIterations);
413 gg.setTrackParameters();
414 gg.setRadii();
415 gg.setGrade(garfieldChi2ContribCut);
416 gg.setDone();
417 listGarfieldTracksGood.add(gg);
418
419
420
421
422
423
424
425
426
427
428
429 NTrks++;
430 } else {
431 nPurged++;
432 }
433 }
434
435 if (debugLevel>=1){
436 System.out.println("List of good GarfieldTracks");
437 for (GarfieldTrack gd : listGarfieldTracksGood){
438 gd.debug();
439 }
440 }
441 if (debugLevel>=1) System.out.println("GarfieldTrackFinder purged "+nPurged+" tracks");
442 if (debugLevel>=3) System.out.println("clearing listGarfieldTracks");
443
444 listGarfieldTracks.clear();
445
446
447
448 listGarfieldTracksGood.trimToSize();
449 event.put("GarfieldTracks",listGarfieldTracksGood);
450 System.out.println("GarfieldTrackfinder found Ntracks="+listGarfieldTracksGood.size());
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469 }
470
471
472
473
474
475
476
477 private void getNextHits(GarfieldTrack g, double scale) {
478
479 selectedHits.clear();
480
481 int lastLayer = g.lastLayer;
482 if (modeFromOutsideIn && (lastLayer == listOfHitsLowestLayer)) return;
483
484 int newLayer= -1;
485 int diffLayer = 0;
486 minDistanceInHits = 1000000.;
487 double d;
488 boolean hitsAreOnTrack = false;
489 double phi1=0.;
490 if (g.getnHits()>0){
491 hitsAreOnTrack=true;
492 phi1= ((GarfieldHit) g.hits.get(g.getnHits()-1)).getPhi();
493 }
494 double dMax = g.distanceCutValue()*scale;
495
496
497
498 for (GarfieldHit h : listOfHits) {
499
500 int hLayer = h.getLayer();
501 boolean good = false;
502
503 if (modeFromOutsideIn){
504 diffLayer = lastLayer - hLayer;
505 if (newLayer == -1 && hLayer < lastLayer) good=true;
506 if (newLayer != -1 && hLayer == newLayer) good=true;
507 }
508 if (!modeFromOutsideIn){
509 diffLayer = hLayer - lastLayer;
510 if (newLayer == -1 && hLayer > lastLayer) good=true;
511 if (newLayer != -1 && hLayer == newLayer) good=true;
512 }
513
514 if ((newLayer != -1) && !(good)) break;
515 if (diffLayer > 6) break;
516 if (diffLayer > 1 && !hitsAreOnTrack ) break;
517
518 if (! good) continue;
519
520 if (hitsAreOnTrack) {
521 double phi2 = h.getPhi();
522 double deltaPhi = Math.abs(phi1-phi2);
523 deltaPhi = Math.min(deltaPhi,Math.abs(deltaPhi-2.*Math.PI));
524 if (deltaPhi>Math.PI/2.) good=false;
525 }
526 if (! good) continue;
527
528 d=h.distanceToHit(g.hel,g.hasZMeasurement());
529 if (d<this.minDistanceInHits){
530 this.minDistanceInHits=d;
531 this.bestHit = h;
532 }
533 if (d<dMax){
534 this.selectedHits.add(h);
535 newLayer = hLayer;
536 }
537 }
538 if (debugLevel>=2){
539 if (selectedHits.size()>0) {
540 System.out.println("GarfieldTrackFinder getNextHits T="
541 +g.getID()+" found Nhits="+ selectedHits.size()+" in Layer "+newLayer+
542 " minD="+minDistanceInHits);
543 } else {
544 System.out.println("GarfieldTrackFinder getNextHits T="+g.getID()+
545 ", did not find hits. The lastLayer="+lastLayer+" minD="+minDistanceInHits);
546 }
547 }
548 }
549
550
551
552
553
554
555 private boolean addHit(GarfieldTrack g, GarfieldHit h) {
556
557 double distanceToBase = g.hel.distanceBaseToPoint(h);
558 if ((g.getnHits() == 0 && distanceToBase > maxDistanceFirstHitToBase) ||
559 (g.getnHits() > 0 && distanceToBase > 80.*k_cm)) {
560 if (debugLevel>=2) System.out.println("routine addHit reject new hit T="+
561 g.getID()+" h="+h.getID()+" dist="+distanceToBase);
562 return false;
563 }
564
565 g.addHit(h);
566 if (debugLevel>=2) System.out.println("Track "+g.getID()+" adding hit=" +
567 h.getID()+ ", Layer="+h.getLayer()+" new nHit="+g.getnHits());
568 if ( g.getNumberOfStepovers()>1) return false;
569 g.calculateHelixFromHits();
570
571 if (this.refitDuringPatternReco && g.getEquivnHits() >= 3) {
572 g.fastChi2Fit(nFitIterations);
573 if (g.chi2Contrib(g.nHits-1)>200.0*this.garfieldChi2ContribCut ){
574 g.dropHit(g.nHits-1);
575 g.calculateHelixFromHits();
576 if (debugLevel>=2) {
577 System.out.println("rejecting Hit T="+g.getID()+" H="+h.getID()+" chi2ndf="+g.getChi2()/g.getNdf()+" stpOver="+g.getNumberOfStepovers());
578 if (debugLevel>=4) g.debug();
579 }
580 return false;
581 } else {
582 g.setStatus("WITH_HITS_FITTED");
583 return true;
584 }
585 } else{
586 g.setStatus("WITH_HITS");
587 return true;
588 }
589 }
590
591
592
593
594 private int issueTrackID() {return issuedTrackIDValue++;}
595
596 private boolean isEven(int i){
597 if (2*((int) (i/2))==i) return true;
598 return false;
599 }
600
601 private double overlapRatio(GarfieldTrack g1, GarfieldTrack g2) {
602 int nOverlap = 0;
603 for (int j=0; j<g1.getnHits(); j++){
604 for (int k=0; k<g2.getnHits(); k++){
605 if (g1.getHitID(j)==g2.getHitID(k)) nOverlap++;
606 }
607 }
608 int nMin = Math.min(g1.getnHits(),g2.getnHits());
609 if (nMin<1) return -1.;
610 double r = ((double) nOverlap)/((double) nMin);
611 return r;
612 }
613
614 private void panicPurge(List lst, int ntrMax) {
615 int ntr = lst.size();
616 System.out.println("GarfieldTrackFinder PanicPurge size="+ntr+" max allowed "+ntrMax);
617 System.out.println("GarfieldTrackFinder PanicPurge brutal removal of last couple of tracks");
618 for (int j = ntr-1; j<ntrMax ; j--){
619 lst.remove(j);
620 }
621 }
622
623
624
625
626 public void testEvent(EventHeader event){
627 int[] hitList = new int[]{0,1,2,3,4,5,6};
628 int nHitInList =7;
629 int mstubID = 0;
630 List listMipStub = (List) event.get("GarfieldMipStubs");
631 MipStub mStub = (MipStub) listMipStub.get(mstubID);
632 GarfieldTrack newTrk = new GarfieldTrack(mStub, 0);
633 newTrk.setID(this.issueTrackID());
634 for (int i=0; i<nHitInList;i++){
635 addHit(newTrk,(GarfieldHit) (this.listOfHits).get(hitList[i]));
636 newTrk.debug();
637 }
638 newTrk.debug();
639 newTrk.calculateChi2();
640 newTrk.fullChi2Fit(0.1,this.nFitIterations);
641 newTrk.debug();
642 newTrk.purgeHits(this.garfieldChi2ContribCut,this.garfieldnTRKHitMin,this.nFitIterations);
643 newTrk.debug();
644 newTrk.setTrackParameters();
645 newTrk.setRadii();
646 newTrk.setDone();
647 newTrk.debug();
648 }
649
650
651
652
653 public void testGenericTrackFit(EventHeader event) {
654 GarfieldTrack newTrk = new GarfieldTrack();
655 newTrk.setDebugLevel(3);
656 newTrk.setID(issueTrackID());
657 double k_mm = 0.1;
658 double err = 2.0 * k_mm;
659 int layer = 0;
660 int id = 0;
661 newTrk.addHit( new GarfieldHit(new double[]{0.0, 0.0, 0.0}, err, layer, id++));
662 newTrk.addHit( new GarfieldHit(new double[]{0.2, 0.2, 1.0}, err, layer, id++));
663 newTrk.addHit( new GarfieldHit(new double[]{0.2, 0.4, 2.0}, err, layer, id++));
664 newTrk.addHit( new GarfieldHit(new double[]{0.4, 0.4, 3.0}, err, layer, id++));
665 newTrk.addHit( new GarfieldHit(new double[]{0.6, 0.6, 4.0}, err, layer, id++));
666 newTrk.addHit( new GarfieldHit(new double[]{0.6, 0.8, 4.0}, err, layer, id++));
667 newTrk.addHit( new GarfieldHit(new double[]{0.8, 0.8, 5.0}, err, layer, id++));
668 newTrk.addHit( new GarfieldHit(new double[]{1.0, 1.0, 6.0}, err, layer, id++));
669 newTrk.addHit( new GarfieldHit(new double[]{1.0, 1.2, 7.0}, err, layer, id++));
670 newTrk.debug();
671 double p0[]=newTrk.getHitPoint(0);
672 double p1[]=newTrk.getHitPoint(newTrk.getnHits()-1);
673 newTrk.setHelix(p0,p1);
674 newTrk.fullChi2Fit(0.1,20);
675 newTrk.debug();
676 newTrk.setTrackParameters();
677 newTrk.setRadii();
678 newTrk.setDone();
679 newTrk.debug();
680
681
682 double step = 0.1;
683 for (int i=-2 ; i<20;i++){
684 newTrk.hel.setPointOnHelix(step * (double) i);
685 }
686
687 for (int k=0 ; k<newTrk.getnHits();k++){
688 double[] ph = newTrk.getHitPoint(k);
689 }
690 }
691
692
693
694
695 public void testEv5(EventHeader event) {
696 List listMipStub = (List) event.get("GarfieldMipStubs");
697 MipStub mStub = (MipStub) listMipStub.get(0);
698 GarfieldTrack newTrk = new GarfieldTrack(mStub, 0);
699 newTrk.setID(this.issueTrackID());
700 GarfieldHit ha = (GarfieldHit) (this.listOfHits).get(0);
701 GarfieldHit hb = (GarfieldHit) (this.listOfHits).get(4);
702 GarfieldHit hc = (GarfieldHit) (this.listOfHits).get(9);
703 GarfieldHit hd = (GarfieldHit) (this.listOfHits).get(11);
704 GarfieldHit he = (GarfieldHit) (this.listOfHits).get(14);
705 addHit(newTrk,ha);
706 addHit(newTrk,hb);
707 addHit(newTrk,hc);
708 addHit(newTrk,hd);
709 addHit(newTrk,he);
710 newTrk.debug();
711 newTrk.calculateChi2();
712 newTrk.setHelixBaseToPCA();
713 newTrk.calculateChi2();
714 newTrk.debug();
715 newTrk.fastChi2Fit(5);
716 newTrk.debug();
717 newTrk.fastChi2Fit(5);
718 newTrk.debug();
719 newTrk.purgeHits(this.garfieldChi2ContribCut,this.garfieldnTRKHitMin,this.nFitIterations/2);
720 }
721
722 }