1 package org.lcsim.fit.helicaltrack;
2
3
4
5
6
7
8
9
10 import hep.physics.matrix.SymmetricMatrix;
11 import hep.physics.vec.BasicHep3Vector;
12 import hep.physics.vec.Hep3Vector;
13
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19
20 import org.lcsim.fit.circle.CircleFit;
21 import org.lcsim.fit.circle.CircleFitter;
22 import org.lcsim.fit.line.SlopeInterceptLineFit;
23 import org.lcsim.fit.line.SlopeInterceptLineFitter;
24 import org.lcsim.fit.zsegment.ZSegmentFit;
25 import org.lcsim.fit.zsegment.ZSegmentFitter;
26 import org.lcsim.geometry.subdetector.BarrelEndcapFlag;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 public class HelicalTrackFitter {
47
48 private CircleFitter _cfitter = new CircleFitter();
49 private SlopeInterceptLineFitter _lfitter = new SlopeInterceptLineFitter();
50 private ZSegmentFitter _zfitter = new ZSegmentFitter();
51 private CircleFit _cfit;
52 private SlopeInterceptLineFit _lfit;
53 private ZSegmentFit _zfit;
54 private HelicalTrackFit _fit;
55 private double _tolerance = 3.;
56
57
58
59
60 public enum FitStatus {
61
62
63
64
65 Success,
66
67
68
69 CircleFitFailed,
70
71
72
73 InconsistentSeed,
74
75
76
77 LineFitFailed,
78
79
80
81 ZSegmentFitFailed
82 };
83
84
85
86
87 public HelicalTrackFitter() {
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 public FitStatus fit(double[] x, double[] y, double[] z, double[] drphi, double[] dz, int np) {
105 List<HelicalTrackHit> hitcol = new ArrayList<HelicalTrackHit>();
106 for (int i = 0; i < np; i++) {
107 Hep3Vector pos = new BasicHep3Vector(x[i], y[i], z[i]);
108 if (dz[i] > 0.) {
109 HelicalTrackHit hit = new HelicalTrack3DHit(pos, MakeCov(pos, drphi[i], 0., dz[i]),
110 0., 0., null, "Unknown", 0, BarrelEndcapFlag.BARREL);
111 hitcol.add(hit);
112 } else {
113 double zmin = z[i] - Math.abs(dz[i]);
114 double zmax = z[i] + Math.abs(dz[i]);
115 HelicalTrackHit hit = new HelicalTrack2DHit(pos, MakeCov(pos, drphi[i], 0., 0.),
116 0., 0., null, "Unknown", 0, BarrelEndcapFlag.BARREL, zmin, zmax);
117 hitcol.add(hit);
118 }
119 }
120 return fit(hitcol);
121 }
122
123
124
125
126
127
128
129
130
131 public FitStatus fit(List<HelicalTrackHit> hitcol) {
132 Map<HelicalTrackHit, MultipleScatter> msmap = new HashMap<HelicalTrackHit, MultipleScatter>();
133 return fit(hitcol, msmap, null);
134 }
135
136
137
138
139
140
141
142
143
144
145
146 public FitStatus fit(List<HelicalTrackHit> hitcol, Map<HelicalTrackHit, MultipleScatter> msmap, HelicalTrackFit oldhelix) {
147
148
149 int nhit = hitcol.size();
150
151
152
153
154
155 Collections.sort(hitcol);
156
157
158
159 double zfirst = hitcol.get(0).z();
160 double zlast = hitcol.get(nhit - 1).z();
161 if (Math.abs(zfirst) > Math.abs(zlast)) {
162 Collections.reverse(hitcol);
163 }
164
165
166 _cfit = null;
167 _lfit = null;
168 _zfit = null;
169 _fit = null;
170
171
172 List<HelicalTrackHit> circle_hits = new ArrayList<HelicalTrackHit>();
173 List<HelicalTrackHit> pixel_hits = new ArrayList<HelicalTrackHit>();
174 List<HelicalTrackHit> strip_hits = new ArrayList<HelicalTrackHit>();
175
176
177 for (HelicalTrackHit hit : hitcol) {
178
179 if (hit.drphi() > 0) circle_hits.add(hit);
180
181 if (hit instanceof HelicalTrack3DHit) pixel_hits.add(hit);
182
183 if (hit instanceof HelicalTrack2DHit) strip_hits.add(hit);
184
185 if (hit instanceof HelicalTrackCross) pixel_hits.add(hit);
186 }
187
188
189 int nc = circle_hits.size();
190 if (nc < 3) {
191 return FitStatus.CircleFitFailed;
192 }
193
194
195 double[] chisq = new double[2];
196 int[] ndof = new int[2];
197 double[] par = new double[5];
198 SymmetricMatrix cov = new SymmetricMatrix(5);
199
200
201 double[] x = new double[nc];
202 double[] y = new double[nc];
203 double[] wrphi = new double[nc];
204
205
206 for (int i = 0; i < nc; i++) {
207 HelicalTrackHit hit = circle_hits.get(i);
208
209 x[i] = hit.x();
210 y[i] = hit.y();
211
212
213 double drphi_ms = 0.;
214 if (msmap.containsKey(hit)) {
215 drphi_ms = msmap.get(hit).drphi();
216 }
217
218 double drphi_res = hit.drphi();
219 wrphi[i] = 1. / (drphi_res * drphi_res + drphi_ms * drphi_ms);
220 }
221
222
223 boolean success = _cfitter.fit(x, y, wrphi, nc);
224 if (!success) {
225 return FitStatus.CircleFitFailed;
226 }
227
228
229 _cfit = _cfitter.getfit();
230
231
232 Map<HelicalTrackHit, Double> smap = getPathLengths(hitcol);
233
234
235 if (smap.get(circle_hits.get(nc-1)) < 0.) {
236
237
238 _cfit = CircleFix(_cfitter.getfit());
239
240
241 for (HelicalTrackHit hit : hitcol) {
242 double oldpath = smap.get(hit);
243 smap.put(hit, -oldpath);
244 }
245 }
246
247
248 for (HelicalTrackHit hit : smap.keySet()) {
249 if (smap.get(hit) < 0.) return FitStatus.InconsistentSeed;
250 }
251
252
253 chisq[0] = _cfit.chisq();
254 ndof[0] = nc - 3;
255
256
257
258
259 par[HelicalTrackFit.dcaIndex] = -1. * _cfit.dca();
260 par[HelicalTrackFit.phi0Index] = _cfit.phi();
261 par[HelicalTrackFit.curvatureIndex] = _cfit.curvature();
262
263
264
265
266
267
268
269 cov.setElement(HelicalTrackFit.curvatureIndex, HelicalTrackFit.curvatureIndex, _cfit.cov()[0]);
270 cov.setElement(HelicalTrackFit.curvatureIndex, HelicalTrackFit.phi0Index, _cfit.cov()[1]);
271 cov.setElement(HelicalTrackFit.phi0Index, HelicalTrackFit.phi0Index, _cfit.cov()[2]);
272 cov.setElement(HelicalTrackFit.curvatureIndex, HelicalTrackFit.dcaIndex, -1. * _cfit.cov()[3]);
273 cov.setElement(HelicalTrackFit.phi0Index, HelicalTrackFit.dcaIndex, -1. * _cfit.cov()[4]);
274 cov.setElement(HelicalTrackFit.dcaIndex, HelicalTrackFit.dcaIndex, _cfit.cov()[5]);
275
276
277 int npix = pixel_hits.size();
278 if (npix > 1) {
279
280
281 double[] s = new double[npix];
282 double[] z = new double[npix];
283 double[] dz = new double[npix];
284
285
286 for (int i = 0; i < npix; i++) {
287 HelicalTrackHit hit = pixel_hits.get(i);
288 z[i] = hit.z();
289 dz[i] = HitUtils.zres(hit, msmap, oldhelix);
290 s[i] = smap.get(hit);
291 }
292
293
294 success = _lfitter.fit(s, z, dz, npix);
295 if (!success) {
296 return FitStatus.LineFitFailed;
297 }
298
299
300 _lfit = _lfitter.getFit();
301 chisq[1] = _lfit.chisquared();
302 ndof[1] = npix - 2;
303
304
305 par[HelicalTrackFit.z0Index] = _lfit.intercept();
306 par[HelicalTrackFit.slopeIndex] = _lfit.slope();
307
308
309 cov.setElement(HelicalTrackFit.z0Index, HelicalTrackFit.z0Index, Math.pow(_lfit.interceptUncertainty(), 2));
310 cov.setElement(HelicalTrackFit.z0Index, HelicalTrackFit.slopeIndex, _lfit.covariance());
311 cov.setElement(HelicalTrackFit.slopeIndex, HelicalTrackFit.slopeIndex, Math.pow(_lfit.slopeUncertainty(), 2));
312
313 } else {
314
315
316
317
318 if (npix == 1) {
319
320 HelicalTrackHit hit = pixel_hits.get(0);
321
322 if (hit.BarrelEndcapFlag() == BarrelEndcapFlag.BARREL) {
323
324 strip_hits.add(
325 HitUtils.PixelToStrip(hit, smap, msmap, oldhelix, _tolerance));
326 }
327 }
328
329
330 int nstrip = strip_hits.size();
331 if (nstrip < 2) {
332 throw new RuntimeException("Too few hits for a ZSegment fit");
333 }
334
335
336 double[] s = new double[nstrip];
337 double[] zmin = new double[nstrip];
338 double[] zmax = new double[nstrip];
339
340
341 for (int i = 0; i < nstrip; i++) {
342 HelicalTrack2DHit hit = (HelicalTrack2DHit) strip_hits.get(i);
343 s[i] = smap.get(hit);
344
345 double dz = 0.;
346 if (msmap.containsKey(hit)) {
347 dz = msmap.get(hit).dz();
348 }
349 zmin[i] = hit.zmin() - _tolerance * dz;
350 zmax[i] = hit.zmax() + _tolerance * dz;
351 }
352
353
354 success = _zfitter.fit(s, zmin, zmax);
355 if (!success) {
356 return FitStatus.ZSegmentFitFailed;
357 }
358
359
360 _zfit = _zfitter.getFit();
361 chisq[1] = 0.;
362 ndof[1] = 0;
363
364
365 par[HelicalTrackFit.z0Index] = _zfit.getCentroid()[0];
366 par[HelicalTrackFit.slopeIndex] = _zfit.getCentroid()[1];
367
368
369 cov.setElement(HelicalTrackFit.z0Index, HelicalTrackFit.z0Index,
370 _zfit.getCovariance().e(0, 0));
371 cov.setElement(HelicalTrackFit.z0Index, HelicalTrackFit.slopeIndex,
372 _zfit.getCovariance().e(0, 1));
373 cov.setElement(HelicalTrackFit.slopeIndex, HelicalTrackFit.slopeIndex,
374 _zfit.getCovariance().e(1, 1));
375 }
376
377
378 if (strip_hits.size() > 0) {
379 chisq[1] += MissedStripPenalty(strip_hits, par, cov, smap, msmap);
380 }
381
382
383 _fit = new HelicalTrackFit(par, cov, chisq, ndof, smap, msmap);
384
385 return FitStatus.Success;
386 }
387
388
389
390
391
392
393 public HelicalTrackFit getFit() {
394 return _fit;
395 }
396
397
398
399
400
401
402 public CircleFit getCircleFit() {
403 return _cfit;
404 }
405
406
407
408
409
410
411 public SlopeInterceptLineFit getLineFit() {
412 return _lfit;
413 }
414
415
416
417
418
419
420 public ZSegmentFit getZSegmentFit() {
421 return _zfit;
422 }
423
424
425
426
427
428
429
430 public void setTolerance(double tolerance) {
431 _tolerance = tolerance;
432 return;
433 }
434
435
436
437
438
439 public double getTolerance() {
440 return _tolerance;
441 }
442
443 public void setReferencePoint(double x, double y) {
444 _cfitter.setreferenceposition(x, y);
445 return;
446 }
447
448
449
450
451
452
453
454
455
456
457
458 private SymmetricMatrix MakeCov(Hep3Vector pos, double drphi, double dr, double dz) {
459
460
461 double x = pos.x();
462 double y = pos.y();
463 double r2 = x * x + y * y;
464
465
466 SymmetricMatrix cov = new SymmetricMatrix(3);
467 cov.setElement(0, 0, (y * y * drphi * drphi + x * x * dr * dr) / r2);
468 cov.setElement(0, 1, x * y * (dr * dr - drphi * drphi) / r2);
469 cov.setElement(1, 1, (x * x * drphi * drphi + y * y * dr * dr) / r2);
470 cov.setElement(2, 2, dz * dz);
471
472 return cov;
473 }
474
475
476
477
478
479
480
481
482
483
484
485
486 private CircleFit CircleFix(CircleFit oldfit) {
487
488
489 double dca = -oldfit.dca();
490 double phi0 = oldfit.phi() + Math.PI;
491 if (phi0 > 2. * Math.PI) {
492 phi0 -= 2. * Math.PI;
493 }
494 double curv = -oldfit.curvature();
495
496
497 double[] cov = oldfit.cov();
498 cov[1] = -cov[1];
499 cov[4] = -cov[4];
500
501
502 return new CircleFit(oldfit.xref(), oldfit.yref(), curv, phi0, dca, oldfit.chisq(), cov);
503 }
504
505
506
507
508
509
510 private Map<HelicalTrackHit, Double> getPathLengths(List<HelicalTrackHit> hits) {
511
512
513 Map<HelicalTrackHit, Double> smap = new HashMap<HelicalTrackHit, Double>();
514
515
516 double slast = 0.;
517 int ilast = -1;
518 double s;
519 for (int i = 0; i < hits.size(); i++) {
520
521
522 HelicalTrackHit hit = hits.get(i);
523 if (hit instanceof HelicalTrack2DHit) {
524
525
526 s = HelixUtils.PathLength(_cfit, hit);
527
528 } else {
529
530 if (ilast < 0) {
531
532 s = HelixUtils.PathLength(_cfit, hit);
533
534 } else {
535
536 s = slast + HelixUtils.PathLength(_cfit, hits.get(ilast), hit);
537 }
538
539
540 ilast = i;
541 slast = s;
542 }
543
544
545 smap.put(hit, s);
546 }
547 return smap;
548 }
549
550
551
552
553
554
555
556
557
558 private double MissedStripPenalty(List<HelicalTrackHit> hitcol, double[] par, SymmetricMatrix cov,
559 Map<HelicalTrackHit, Double> smap, Map<HelicalTrackHit, MultipleScatter> msmap) {
560
561 double z0 = par[HelicalTrackFit.z0Index];
562 double slope = par[HelicalTrackFit.slopeIndex];
563 double cov_z0z0 = cov.e(HelicalTrackFit.z0Index, HelicalTrackFit.z0Index);
564 double cov_slsl = cov.e(HelicalTrackFit.slopeIndex, HelicalTrackFit.slopeIndex);
565 double cov_z0sl = cov.e(HelicalTrackFit.z0Index, HelicalTrackFit.slopeIndex);
566
567 double chisq = 0.;
568
569 for (HelicalTrackHit hit : hitcol) {
570 if (hit instanceof HelicalTrack2DHit) {
571
572 double s = smap.get(hit);
573
574 double zhelix = z0 + s * slope;
575
576 double dzsq = cov_z0z0 + 2. * s * cov_z0sl + s * s * cov_slsl;
577
578 double dz_ms = 0.;
579 if (msmap.containsKey(hit)) {
580 dz_ms = msmap.get(hit).dz();
581 }
582
583 dzsq += dz_ms * dz_ms;
584
585 double zmin = ((HelicalTrack2DHit) hit).zmin();
586 double zmax = ((HelicalTrack2DHit) hit).zmax();
587
588 if (zhelix < zmin) {
589 chisq += (zhelix - zmin) * (zhelix - zmin) / dzsq;
590 }
591 if (zhelix > zmax) {
592 chisq += (zhelix - zmax) * (zhelix - zmax) / dzsq;
593 }
594 }
595 }
596 return chisq;
597 }
598 }