LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
KalmanFilterAlg.cxx
Go to the documentation of this file.
1 
12 #include "cetlib_except/exception.h"
14 #include "boost/numeric/ublas/vector_proxy.hpp"
15 #include "boost/numeric/ublas/matrix_proxy.hpp"
21 #include "TGaxis.h"
22 #include "TText.h"
23 #include "TLegend.h"
24 #include "TLegendEntry.h"
25 #include "TText.h"
26 
27 // Local functions.
28 
29 namespace {
30 
31  void hit_position(const trkf::KHitBase& hit, double& z, double &x) {
32 
33  // Map hit -> (z,x) for plotting.
34 
35  // Default result.
36 
37  z = 0.;
38  x = 0.;
39 
40  // Cast this hit to KHit<1>. Only know how to handle 1D hits.
41 
42  const trkf::KHit<1>* phit1 = dynamic_cast<const trkf::KHit<1>*>(&hit);
43  if(phit1) {
44  const std::shared_ptr<const trkf::Surface>& psurf = hit.getMeasSurface();
45 
46  // Handle SurfYZPlane.
47 
48  if(const trkf::SurfYZPlane* pyz = dynamic_cast<const trkf::SurfYZPlane*>(&*psurf)) {
49 
50  // Now finished doing casts.
51  // We have a kind of hit and measurement surface that we know how to handle.
52 
53  // Get x coordinate from hit and surface.
54 
55  x = pyz->x0() + phit1->getMeasVector()(0);
56 
57  // Get z position from surface parameters.
58  // The "z" position is actually calculated as the perpendicular distance
59  // from a corner, which is a proxy for wire number.
60 
61  double z0 = pyz->z0();
62  double y0 = pyz->y0();
63  double phi = pyz->phi();
65  double ymax = geom->DetHalfWidth();
66  if(phi > 0.)
67  z = z0 * std::cos(phi) + (ymax - y0) * std::sin(phi);
68  else
69  z = z0 * std::cos(phi) - (ymax + y0) * std::sin(phi);
70 
71  //int pl = hit.getMeasPlane();
72  //std::cout << "pl = " << pl
73  // << ", x=" << x
74  // << ", z0=" << z0
75  // << ", y0=" << y0
76  // << ", phi=" << phi
77  // << ", z=" << z
78  // << std::endl;
79  }
80  else if(const trkf::SurfYZLine* pyz = dynamic_cast<const trkf::SurfYZLine*>(&*psurf)) {
81 
82  // Now finished doing casts.
83  // We have a kind of hit and measurement surface that we know how to handle.
84 
85  // Get x coordinate from surface.
86 
87  x = pyz->x0();
88 
89  // Get z position from surface parameters.
90  // The "z" position is actually calculated as the perpendicular distance
91  // from a corner, which is a proxy for wire number.
92 
93  double z0 = pyz->z0();
94  double y0 = pyz->y0();
95  double phi = pyz->phi();
97  double ymax = geom->DetHalfWidth();
98  if(phi > 0.)
99  z = z0 * std::cos(phi) + (ymax - y0) * std::sin(phi);
100  else
101  z = z0 * std::cos(phi) - (ymax + y0) * std::sin(phi);
102 
103  //int pl = hit.getMeasPlane();
104  //std::cout << "pl = " << pl
105  // << ", x=" << x
106  // << ", z0=" << z0
107  // << ", y0=" << y0
108  // << ", phi=" << phi
109  // << ", z=" << z
110  // << std::endl;
111  }
112  }
113  }
114 
115  void update_momentum(const trkf::KVector<2>::type& defl,
116  const trkf::KSymMatrix<2>::type& errc,
117  const trkf::KSymMatrix<2>::type& errn,
118  double mass, double& invp, double& var_invp)
119  // Momentum updater.
120  //
121  // Arguments: defl - Deflection (2D slope residual between two
122  // sampled points on track).
123  // errc - Error matrix of deflection residual
124  // exclusive of multiple scattering.
125  // errn - Part of deflection noise error matrix
126  // proportional to 1/(beta*momentum).
127  // mass - Mass of particle.
128  // invp - Modified 1/momentum track parameter.
129  // var_invp - Modified 1/momentum variance.
130  //
131  // Returns: True if success.
132  //
133  // The total deflection residual error matrix is
134  //
135  // err = errc + [1/(beta*momentum)] * errn.
136  //
137  // The inverse momentum and error are updated using using log-likelihood
138  //
139  // log(L) = -0.5 * log(det(err)) - 0.5 * defl^T * err^(-1) * defl.
140  // log(L) = -0.5 * tr(log(err)) - 0.5 * defl^T * err^(-1) * defl.
141  //
142  {
143  // Calculate original k = 1./(beta*p), and original variance of k.
144 
145  double invp2 = invp*invp;
146  double invp3 = invp*invp2;
147  double invp4 = invp2*invp2;
148  double mass2 = mass*mass;
149  double k = std::sqrt(invp2 + mass2 * invp4);
150  double dkdinvp = (invp + 2.*mass2*invp3) / k;
151  double vark = var_invp * dkdinvp*dkdinvp;
152 
153  // First, find current inverse error matrix using momentum hypothesis.
154 
155  trkf::KSymMatrix<2>::type inverr = errc + k * errn;
156  trkf::syminvert(inverr);
157 
158  // Find the first and second derivatives of the log likelihood
159  // with respact to k.
160 
161  trkf::KMatrix<2, 2>::type temp1 = prod(inverr, errn);
162  trkf::KMatrix<2, 2>::type temp2 = prod(temp1, temp1);
163 
164  // KJK-FIXME: Ideally, the explicit type specification below
165  // ('trk::KVector<T>::type') should be replaced with the 'auto'
166  // keyword. However, Boost 1.66.0a runs into a static-assert
167  // failure with the 'complexity' of vtemp2 not being 0. I am not
168  // sure what the complexity means.
169  //
170  // If 'trkf::KVector<2>::type vtemp2 = prod(temp1, vtemp1)' is
171  // used below, then the GCC 7.3 compiler thinks there may be an
172  // uninitialized variable in vtemp2. A workaround is to use the
173  // Boost interface that fills a default-constructed vector. Note
174  // that this workaround may hide an actual problem. It is the
175  // responsibility of the maintainer of this code to determine if
176  // an actual problem exists.
177 
178  trkf::KVector<2>::type vtemp1 = prod(inverr, defl);
179  trkf::KVector<2>::type vtemp2;
180  prod(temp1, vtemp1, vtemp2);
181  trkf::KVector<2>::type vtemp3 = prod(temp1, vtemp2);
182  double derivk1 = -0.5 * trkf::trace(temp1) + 0.5 * inner_prod(defl, vtemp2);
183  double derivk2 = 0.5 * trkf::trace(temp2) - inner_prod(defl, vtemp3);
184 
185  // We expect the log-likelihood to be most nearly Gaussian
186  // with respect to variable q = k^(-1/2) = std::sqrt(beta*p).
187  // Therefore, transform the original variables and log-likelihood
188  // derivatives to q-space.
189 
190  double q = 1./std::sqrt(k);
191  double varq = vark / (4.*k*k*k);
192  double derivq1 = (-2.*k/q) * derivk1;
193  double derivq2 = 6.*k*k * derivk1 + 4.*k*k*k * derivk2;
194 
195  if(derivq2 < 0.) {
196 
197  // Estimate the measurement in q-space.
198 
199  double q1 = q - derivq1 / derivq2;
200  double varq1 = -1./derivq2;
201 
202  // Get updated estimated q, combining original estimate and
203  // update from the current measurement.
204 
205  double newvarq = 1. / (1./varq + 1./varq1);
206  double newq = newvarq * (q/varq + q1/varq1);
207  q = newq;
208  varq = newvarq;
209 
210  // Calculate updated c = 1./p and variance.
211 
212  double q2 = q*q;
213  double q4 = q2*q2;
214  double c2 = 2. / (q4 + q2 * std::sqrt(q4 + 4.*mass2));
215  double c = std::sqrt(c2);
216  double dcdq = -2. * (c/q) * (1. + mass2*c2) / (1. + 2.*mass2*c2);
217  double varc = varq * dcdq*dcdq;
218 
219  // Update result.
220 
221  invp = c;
222  var_invp = varc;
223  }
224  }
225 }
226 
228 
230  fTrace(false),
231  fMaxPErr(0.),
232  fGoodPErr(0.),
233  fMaxIncChisq(0.),
234  fMaxSeedIncChisq(0.),
235  fMaxSmoothIncChisq(0.),
236  fMaxEndChisq(0.),
237  fMinLHits(0),
238  fMaxLDist(0.),
239  fMaxPredDist(0.),
240  fMaxSeedPredDist(0.),
241  fMaxPropDist(0.),
242  fMinSortDist(0.),
243  fMaxSortDist(0.),
244  fMaxSamePlane(0),
245  fGapDist(0.),
246  fMaxNoiseHits(0),
247  fMinSampleDist(0.),
248  fFitMomRange(false),
249  fFitMomMS(false),
250  fGTrace(false),
251  fGTraceWW(0),
252  fGTraceWH(0),
253  fPlane(-1),
254  fInfoPad(0),
255  fMessages(0)
256 {
257  mf::LogInfo("KalmanFilterAlg") << "KalmanFilterAlg instantiated.";
258 
259  // Load fcl parameters.
260 
261  reconfigure(pset);
262 }
263 
266 {}
267 
270 {
271  fTrace = pset.get<bool>("Trace");
272  fMaxPErr = pset.get<double>("MaxPErr");
273  fGoodPErr = pset.get<double>("GoodPErr");
274  fMaxIncChisq = pset.get<double>("MaxIncChisq");
275  fMaxSeedIncChisq = pset.get<double>("MaxSeedIncChisq");
276  fMaxSmoothIncChisq = pset.get<double>("MaxSmoothIncChisq");
277  fMaxEndChisq = pset.get<double>("MaxEndChisq");
278  fMinLHits = pset.get<int>("MinLHits");
279  fMaxLDist = pset.get<double>("MaxLDist");
280  fMaxPredDist = pset.get<double>("MaxPredDist");
281  fMaxSeedPredDist = pset.get<double>("MaxSeedPredDist");
282  fMaxPropDist = pset.get<double>("MaxPropDist");
283  fMinSortDist = pset.get<double>("MinSortDist");
284  fMaxSortDist = pset.get<double>("MaxSortDist");
285  fMaxSamePlane = pset.get<int>("MaxSamePlane");
286  fGapDist = pset.get<double>("GapDist");
287  fMaxNoiseHits = pset.get<double>("MaxNoiseHits");
288  fMinSampleDist = pset.get<double>("MinSampleDist");
289  fFitMomRange = pset.get<bool>("FitMomRange");
290  fFitMomMS = pset.get<bool>("FitMomMS");
291  fGTrace = pset.get<bool>("GTrace");
292  if(fGTrace) {
293  fGTraceWW = pset.get<double>("GTraceWW");
294  fGTraceWH = pset.get<double>("GTraceWH");
295  fGTraceXMin = pset.get<double>("GTraceXMin");
296  fGTraceXMax = pset.get<double>("GTraceXMax");
297  fGTraceZMin = pset.get<std::vector<double> >("GTraceZMin");
298  fGTraceZMax = pset.get<std::vector<double> >("GTraceZMax");
299  }
300 }
301 
325  KGTrack& trg,
326  const Propagator* prop,
329  bool linear) const
330 {
331  if (!prop)
332  throw cet::exception("KalmanFilterAlg") << "trkf::KalmanFilterAlg::buildTrack(): no propagator\n";
333 
334  // Direction must be forward or backward (unknown is not allowed).
335 
336  if(dir != Propagator::FORWARD && dir != Propagator::BACKWARD)
337  throw cet::exception("KalmanFilterAlg")
338  << "No direction for Kalman fit.\n";
339 
340  // Set up canvas for graphical trace.
341 
342  if(fGTrace) {
343 
344  // Make a new canvas with a unique name.
345 
346  static int cnum=0;
347  ++cnum;
348  std::ostringstream ostr;
349  ostr << "khit" << cnum;
350  fCanvases.emplace_back(new TCanvas(ostr.str().c_str(), ostr.str().c_str(),
351  fGTraceWW, fGTraceWH));
352  fPads.clear();
353  fMarkerMap.clear();
354  int nview = 3;
355  fCanvases.back()->Divide(2, nview/2 + 1);
356 
357  // Make subpad for each view.
358 
359  for(int iview=0; iview < nview; ++iview) {
360 
361  std::ostringstream ostr;
362  ostr << "Plane " << iview;
363 
364  fCanvases.back()->cd(iview+1);
365  double zmin = 0.06;
366  double zmax = 0.94;
367  double xmin = 0.04;
368  double xmax = 0.95;
369  TPad* p = new TPad(ostr.str().c_str(), ostr.str().c_str(), zmin, xmin, zmax, xmax);
370  p->SetBit(kCanDelete); // Give away ownership.
371  p->Range(fGTraceZMin[iview], fGTraceXMin, fGTraceZMax[iview], fGTraceXMax);
372  p->SetFillStyle(4000); // Transparent.
373  p->Draw();
374  fPads.push_back(p);
375 
376  // Draw label.
377 
378  TText* t = new TText(zmax-0.02, xmax-0.03, ostr.str().c_str());
379  t->SetBit(kCanDelete); // Give away ownership.
380  t->SetTextAlign(33);
381  t->SetTextFont(42);
382  t->SetTextSize(0.04);
383  t->Draw();
384 
385  // Draw axes.
386 
387  TGaxis* pz1 = new TGaxis(zmin, xmin, zmax, xmin,
388  fGTraceZMin[iview], fGTraceZMax[iview], 510, "");
389  pz1->SetBit(kCanDelete); // Give away ownership.
390  pz1->Draw();
391 
392  TGaxis* px1 = new TGaxis(zmin, xmin, zmin, xmax,
393  fGTraceXMin, fGTraceXMax, 510, "");
394  px1->SetBit(kCanDelete); // Give away ownership.
395  px1->Draw();
396 
397  TGaxis* pz2 = new TGaxis(zmin, xmax, zmax, xmax,
398  fGTraceZMin[iview], fGTraceZMax[iview], 510, "-");
399  pz2->SetBit(kCanDelete); // Give away ownership.
400  pz2->Draw();
401 
402  TGaxis* px2 = new TGaxis(zmax, xmin, zmax, xmax,
403  fGTraceXMin, fGTraceXMax, 510, "L+");
404  px2->SetBit(kCanDelete); // Give away ownership.
405  px2->Draw();
406 
407  }
408 
409  // Draw legend.
410 
411  fCanvases.back()->cd(nview+1);
412  fInfoPad = gPad;
413  TLegend* leg = new TLegend(0.6, 0.5, 0.99, 0.99);
414  leg->SetBit(kCanDelete); // Give away ownership.
415 
416  TLegendEntry* entry = 0;
417  TMarker* m = 0;
418 
419  m = new TMarker(0., 0., 20);
420  m->SetBit(kCanDelete);
421  m->SetMarkerSize(1.2);
422  m->SetMarkerColor(kRed);
423  entry = leg->AddEntry(m, "Hits on Track", "P");
424  entry->SetBit(kCanDelete);
425 
426  m = new TMarker(0., 0., 20);
427  m->SetBit(kCanDelete);
428  m->SetMarkerSize(1.2);
429  m->SetMarkerColor(kOrange);
430  entry = leg->AddEntry(m, "Smoothed Hits on Track", "P");
431  entry->SetBit(kCanDelete);
432 
433  m = new TMarker(0., 0., 20);
434  m->SetBit(kCanDelete);
435  m->SetMarkerSize(1.2);
436  m->SetMarkerColor(kBlack);
437  entry = leg->AddEntry(m, "Available Hits", "P");
438  entry->SetBit(kCanDelete);
439 
440  m = new TMarker(0., 0., 20);
441  m->SetBit(kCanDelete);
442  m->SetMarkerSize(1.2);
443  m->SetMarkerColor(kBlue);
444  entry = leg->AddEntry(m, "Rejected Hits", "P");
445  entry->SetBit(kCanDelete);
446 
447  m = new TMarker(0., 0., 20);
448  m->SetBit(kCanDelete);
449  m->SetMarkerSize(1.2);
450  m->SetMarkerColor(kGreen);
451  entry = leg->AddEntry(m, "Removed Hits", "P");
452  entry->SetBit(kCanDelete);
453 
454  m = new TMarker(0., 0., 20);
455  m->SetBit(kCanDelete);
456  m->SetMarkerSize(1.2);
457  m->SetMarkerColor(kMagenta);
458  entry = leg->AddEntry(m, "Seed Hits", "P");
459  entry->SetBit(kCanDelete);
460 
461  m = new TMarker(0., 0., 20);
462  m->SetBit(kCanDelete);
463  m->SetMarkerSize(1.2);
464  m->SetMarkerColor(kCyan);
465  entry = leg->AddEntry(m, "Unreachable Seed Hits", "P");
466  entry->SetBit(kCanDelete);
467 
468  leg->Draw();
469 
470  // Draw message box.
471 
472  fMessages = new TPaveText(0.01, 0.01, 0.55, 0.99, "");
473  fMessages->SetBit(kCanDelete);
474  fMessages->SetTextFont(42);
475  fMessages->SetTextSize(0.04);
476  fMessages->SetTextAlign(12);
477  fMessages->Draw();
478  TText* t = fMessages->AddText("Enter buildTrack");
479  t->SetBit(kCanDelete);
480 
481  fCanvases.back()->Update();
482  }
483 
484  // Sort container using this seed track.
485 
486  hits.sort(trk, true, prop, Propagator::UNKNOWN);
487 
488  // Draw hits and populate hit->marker map.
489 
490  if(fGTrace && fCanvases.size() > 0) {
491 
492  // Loop over sorted KHitGroups.
493  // Paint sorted seed hits magenta.
494 
495  const std::list<KHitGroup>& groups = hits.getSorted();
496  for(auto const& gr : groups) {
497 
498  // Loop over hits in this group.
499 
500  const std::vector<std::shared_ptr<const KHitBase> >& phits = gr.getHits();
501  for(auto const& phit : phits) {
502  const KHitBase& hit = *phit;
503  int pl = hit.getMeasPlane();
504  if(pl >= 0 && pl < int(fPads.size())) {
505  double z = 0.;
506  double x = 0.;
507  hit_position(hit, z, x);
508  TMarker* marker = new TMarker(z, x, 20);
509  fMarkerMap[hit.getID()] = marker;
510  fPads[pl]->cd();
511  marker->SetBit(kCanDelete); // Give away ownership.
512  marker->SetMarkerSize(0.5);
513  marker->SetMarkerColor(kMagenta);
514  marker->Draw();
515  }
516  }
517  }
518 
519  // Loop over unsorted KHitGroups.
520  // Paint unsorted seed hits cyan.
521  // There should be few, if any, unsorted seed hits.
522 
523  const std::list<KHitGroup>& ugroups = hits.getUnsorted();
524  for(auto const& gr : ugroups) {
525 
526  // Loop over hits in this group.
527 
528  const std::vector<std::shared_ptr<const KHitBase> >& phits = gr.getHits();
529  for(auto const& phit : phits) {
530  const KHitBase& hit = *phit;
531  int pl = hit.getMeasPlane();
532  if(pl >= 0 && pl < int(fPads.size())) {
533  double z = 0.;
534  double x = 0.;
535  hit_position(hit, z, x);
536  TMarker* marker = new TMarker(z, x, 20);
537  fMarkerMap[hit.getID()] = marker;
538  fPads[pl]->cd();
539  marker->SetBit(kCanDelete); // Give away ownership.
540  marker->SetMarkerSize(0.5);
541  marker->SetMarkerColor(kCyan);
542  marker->Draw();
543  }
544  }
545  }
546  fCanvases.back()->Update();
547  }
548 
549  // Loop over measurements (KHitGroup) from sorted list.
550 
551  double tchisq = 0.; // Cumulative chisquare.
552  double path = 0.; // Cumulative path distance.
553  int step = 0; // Step count.
554  int nsame = 0; // Number of consecutive measurements in same plane.
555  int last_plane = -1; // Last plane.
556  bool has_pref_plane = false; // Set to true when first preferred plane hit is added to track.
557 
558  // Make a copy of the starting track, in the form of a KFitTrack,
559  // which we will update as we go.
560 
561  TrackError err;
562  trk.getSurface()->getStartingError(err);
563  KETrack tre(trk, err);
564  KFitTrack trf(tre, path, tchisq);
565 
566  // Also use the starting track as the reference track for linearized
567  // propagation, until the track is established with reasonably small
568  // errors.
569 
570  KTrack ref(trk);
571  KTrack* pref = &ref;
572 
573  mf::LogInfo log("KalmanFilterAlg");
574 
575  // Loop over measurement groups (KHitGroups).
576 
577  while(hits.getSorted().size() > 0) {
578  ++step;
579  if(fTrace) {
580  log << "Build Step " << step << "\n";
581  log << "KGTrack has " << trg.numHits() << " hits.\n";
582  log << trf;
583  }
584 
585  // Get an iterator for the next KHitGroup.
586 
588  if(dir == Propagator::FORWARD)
589  it = hits.getSorted().begin();
590  else {
591  it = hits.getSorted().end();
592  --it;
593  }
594  const KHitGroup& gr = *it;
595 
596  if(fTrace) {
597  double path_est = gr.getPath();
598  log << "Next surface: " << *(gr.getSurface()) << "\n";
599  log << " Estimated path length of hit group = " << path_est << "\n";
600  }
601 
602  // Get the next prediction surface. If this KHitGroup is on the
603  // preferred plane, use that as the prediction surface.
604  // Otherwise, use the current track surface as the prediction
605  // surface.
606 
607  std::shared_ptr<const Surface> psurf = trf.getSurface();
608  if (gr.getPlane() < 0)
609  throw cet::exception("KalmanFilterAlg") << "negative plane?\n";
610  if(fPlane < 0 || gr.getPlane() < 0 || fPlane == gr.getPlane())
611  psurf = gr.getSurface();
612 
613  // Propagate track to the prediction surface.
614 
615  boost::optional<double> dist = prop->noise_prop(trf, psurf, Propagator::UNKNOWN, true, pref);
616  if(!!dist && std::abs(*dist) > fMaxPropDist)
617  dist = boost::optional<double>(false, 0.);
618  double ds = 0.;
619 
620  if(!!dist) {
621 
622  // Propagation succeeded.
623  // Update cumulative path distance and track status.
624 
625  ds = *dist;
626  path += ds;
627  trf.setPath(path);
628  if(dir == Propagator::FORWARD)
630  else {
632  }
633  if(fTrace) {
634  log << "After propagation\n";
635  log << " Incremental propagation distance = " << ds << "\n";
636  log << " Path length of prediction surface = " << path << "\n";
637  log << "KGTrack has " << trg.numHits() << " hits.\n";
638  log << trf;
639  }
640 
641  // Loop over measurements in this group.
642 
643  const std::vector<std::shared_ptr<const KHitBase> >& hits = gr.getHits();
644  double best_chisq = 0.;
645  std::shared_ptr<const KHitBase> best_hit;
646  for(std::vector<std::shared_ptr<const KHitBase> >::const_iterator ihit = hits.begin();
647  ihit != hits.end(); ++ihit) {
648  const KHitBase& hit = **ihit;
649 
650  // Turn this hit blue.
651 
652  if(fGTrace && fCanvases.size() > 0) {
653  auto marker_it = fMarkerMap.find(hit.getID());
654  if(marker_it != fMarkerMap.end()) {
655  TMarker* marker = marker_it->second;
656  marker->SetMarkerColor(kBlue);
657  }
658  //fCanvases.back()->Update();
659  }
660 
661  // Update predction using current track hypothesis and get
662  // incremental chisquare.
663 
664  bool ok = hit.predict(trf, prop);
665  if(ok) {
666  double chisq = hit.getChisq();
667  double preddist = hit.getPredDistance();
668  if(fTrace) {
669  log << "Trying Hit.\n"
670  << hit
671  << "\nchisq = " << chisq << "\n"
672  << "prediction distance = " << preddist << "\n";
673  }
674  if((!has_pref_plane || abs(preddist) < fMaxSeedPredDist) &&
675  (best_hit.get() == 0 || chisq < best_chisq) ) {
676  best_chisq = chisq;
677  if(chisq < fMaxSeedIncChisq)
678  best_hit = *ihit;
679  }
680  }
681  }
682  if(fTrace) {
683  log << "Best hit incremental chisquare = " << best_chisq << "\n";
684  if(best_hit.get() != 0) {
685  log << "Hit after prediction\n";
686  log << *best_hit;
687  }
688  else
689  log << "No hit passed chisquare cut.\n";
690  }
691  if(fGTrace && fCanvases.size() > 0)
692  fCanvases.back()->Update();
693 
694  // If we found a best measurement, and if the incremental
695  // chisquare passes the cut, add it to the track and update
696  // fit information.
697 
698  bool update_ok = false;
699  if(best_hit.get() != 0) {
700  KFitTrack trf0(trf);
701  best_hit->update(trf);
702  update_ok = trf.isValid();
703  if(!update_ok)
704  trf = trf0;
705  }
706  if(update_ok) {
707  ds += best_hit->getPredDistance();
708  tchisq += best_chisq;
709  trf.setChisq(tchisq);
710  if(dir == Propagator::FORWARD)
712  else {
714  }
715 
716  // If the pointing error got too large, and there is no
717  // reference track, quit.
718 
719  if(pref == 0 && trf.PointingError() > fMaxPErr) {
720  if(fTrace)
721  log << "Quitting because pointing error got too large.\n";
722  break;
723  }
724 
725  // Test number of consecutive measurements in the same plane.
726 
727  if(gr.getPlane() >= 0) {
728  if(gr.getPlane() == last_plane)
729  ++nsame;
730  else {
731  nsame = 1;
732  last_plane = gr.getPlane();
733  }
734  }
735  else {
736  nsame = 0;
737  last_plane = -1;
738  }
739  if(nsame <= fMaxSamePlane) {
740 
741  // Turn best hit red.
742 
743  if(fGTrace && fCanvases.size() > 0) {
744  int pl = best_hit->getMeasPlane();
745  if(pl >= 0 && pl < int(fPads.size())) {
746  auto marker_it = fMarkerMap.find(best_hit->getID());
747  if(marker_it != fMarkerMap.end()) {
748  TMarker* marker = marker_it->second;
749  marker->SetMarkerColor(kRed);
750 
751  // Redraw marker so that it will be on top.
752 
753  fPads[pl]->cd();
754  marker->Draw();
755  }
756  }
757  fCanvases.back()->Update();
758  }
759 
760  // Make a KHitTrack and add it to the KGTrack.
761 
762  KHitTrack trh(trf, best_hit);
763  trg.addTrack(trh);
764  if(fPlane == gr.getPlane())
765  has_pref_plane = true;
766 
767  // Decide if we want to kill the reference track.
768 
769  if(!linear && pref != 0 && int(trg.numHits()) >= fMinLHits &&
770  (trf.PointingError() < fGoodPErr || path > fMaxLDist)) {
771  pref = 0;
772  if(fTrace)
773  log << "Killing reference track.\n";
774  }
775 
776  if(fTrace) {
777  log << "After update\n";
778  log << "KGTrack has " << trg.numHits() << " hits.\n";
779  log << trf;
780  }
781  }
782  }
783  }
784 
785  // The current KHitGroup is now resolved.
786  // Move it to unused list.
787 
788  hits.getUnused().splice(hits.getUnused().end(), hits.getSorted(), it);
789 
790  // If the propagation distance was the wrong direction, resort the measurements.
791 
792  if(pref == 0 && !!dist &&
793  ((dir == Propagator::FORWARD && (ds < fMinSortDist || ds > fMaxSortDist)) ||
794  (dir == Propagator::BACKWARD && (-ds < fMinSortDist || -ds > fMaxSortDist)))) {
795  if(fTrace)
796  log << "Resorting measurements.\n";
797  hits.sort(trf, true, prop, dir);
798  }
799  }
800 
801  // Clean track.
802 
803  cleanTrack(trg);
804 
805  // Set the fit status of the last added KHitTrack to optimal and get
806  // the final chisquare and path length.
807 
808  double fchisq = 0.;
809  path = 0.;
810  if(trg.isValid()) {
811  path = trg.endTrack().getPath() - trg.startTrack().getPath();
812  if(dir == Propagator::FORWARD) {
814  fchisq = trg.endTrack().getChisq();
815  }
816  else {
818  fchisq = trg.startTrack().getChisq();
819  }
820  }
821 
822  // Summary.
823 
824  log << "KalmanFilterAlg build track summary.\n"
825  << "Build direction = " << (dir == Propagator::FORWARD ? "FORWARD" : "BACKWARD") << "\n"
826  << "Track has " << trg.numHits() << " hits.\n"
827  << "Track length = " << path << "\n"
828  << "Track chisquare = " << fchisq << "\n";
829  // log << trg << "\n";
830 
831  // Done. Return success if we added at least one measurement.
832 
833  bool ok = trg.numHits() > 0;
834 
835  if(fGTrace && fCanvases.size() > 0) {
836  TText* t = 0;
837  if(ok)
838  t = fMessages->AddText("Exit buildTrack, status success");
839  else
840  t = fMessages->AddText("Exit buildTrack, status fail");
841  t->SetBit(kCanDelete);
842  fInfoPad->Modified();
843  fCanvases.back()->Update();
844  }
845 
846  return ok;
847 }
848 
883  KGTrack* trg1,
884  const Propagator* prop) const
885 {
886  if (!prop)
887  throw cet::exception("KalmanFilterAlg") << "trkf::KalmanFilterAlg::smoothTrack(): no propagator\n";
888 
889  // Default result failure.
890 
891  bool result = false;
892 
893  //if(fGTrace && fCanvases.size() > 0) {
894  // TText* t = fMessages->AddText("Enter smoothTrack");
895  // t->SetBit(kCanDelete);
896  // fInfoPad->Modified();
897  // fCanvases.back()->Update();
898  // }
899 
900  // It is an error if the KGTrack is not valid.
901 
902  if(trg.isValid()) {
903 
904  // Examine the track endpoints and figure out which end of the track
905  // to start from. The fit always starts at the optimal end. It is
906  // an error if neither end point is optimal. Do nothing and return
907  // success if both end points are optimal.
908 
909  const KHitTrack& trh0 = trg.startTrack();
910  const KHitTrack& trh1 = trg.endTrack();
911  KFitTrack::FitStatus stat0 = trh0.getStat();
912  KFitTrack::FitStatus stat1 = trh1.getStat();
913  bool dofit = false;
914 
915  // Remember starting direction, track, and distance.
916 
918  const KTrack* trk = 0;
919  double path = 0.;
920 
921  if(stat0 == KFitTrack::OPTIMAL) {
922  if(stat1 == KFitTrack::OPTIMAL) {
923 
924  // Both ends optimal (do nothing, return success).
925 
926  dofit = false;
927  result = true;
928 
929  }
930  else {
931 
932  // Start optimal.
933 
934  dofit = true;
935  dir = Propagator::FORWARD;
936  trk = &trh0;
937  path = 0.;
938  }
939  }
940  else {
941  if(stat1 == KFitTrack::OPTIMAL) {
942 
943  // End optimal.
944 
945  dofit = true;
946  dir = Propagator::BACKWARD;
947  trk = &trh1;
948  path = trh1.getPath();
949  }
950  else {
951 
952  // Neither end optimal (do nothing, return failure).
953 
954  dofit = false;
955  result = false;
956  }
957  }
958  if(dofit) {
959  if (!trk)
960  throw cet::exception("KalmanFilterAlg") << "KalmanFilterAlg::smoothTrack(): no track!\n";
961 
962  // Cumulative chisquare.
963 
964  double tchisq = 0.;
965 
966  // Construct starting KFitTrack with track information and distance
967  // taken from the optimal end, but with "infinite" errors.
968 
969  TrackError err;
970  trk->getSurface()->getStartingError(err);
971  KETrack tre(*trk, err);
972  KFitTrack trf(tre, path, tchisq);
973 
974  // Make initial reference track to be same as initial fit track.
975 
976  KTrack ref(trf);
977 
978  // Loop over KHitTracks contained in KGTrack.
979 
982  switch (dir) {
983  case Propagator::FORWARD:
984  it = trg.getTrackMap().begin();
985  itend = trg.getTrackMap().end();
986  break;
988  it = trg.getTrackMap().end();
989  itend = trg.getTrackMap().begin();
990  break;
991  default:
992  throw cet::exception("KalmanFilterAlg") << "KalmanFilterAlg::smoothTrack(): invalid direction\n";
993  } // switch
994 
995  mf::LogInfo log("KalmanFilterAlg");
996 
997  // Loop starts here.
998 
999  result = true; // Result success unless we find an error.
1000  int step = 0; // Step count.
1001  while(dofit && it != itend) {
1002  ++step;
1003  if(fTrace) {
1004  log << "Smooth Step " << step << "\n";
1005  log << "Reverse fit track:\n";
1006  log << trf;
1007  }
1008 
1009  // For backward fit, decrement iterator at start of loop.
1010 
1011  if(dir == Propagator::BACKWARD)
1012  --it;
1013 
1014  KHitTrack& trh = (*it).second;
1015  if(fTrace) {
1016  log << "Forward track:\n";
1017  log << trh;
1018  }
1019 
1020  // Extract measurement.
1021 
1022  const KHitBase& hit = *(trh.getHit());
1023 
1024  // Propagate KFitTrack to the next track surface.
1025 
1026  std::shared_ptr<const Surface> psurf = trh.getSurface();
1027  boost::optional<double> dist = prop->noise_prop(trf, psurf, Propagator::UNKNOWN,
1028  true, &ref);
1029 
1030  // Check if propagation succeeded. If propagation fails, this
1031  // measurement will be dropped from the unidirectional fit
1032  // track. This measurement will still be in the original
1033  // track, but with a status other than optimal.
1034 
1035  if(!!dist) {
1036 
1037  // Propagation succeeded.
1038  // Update cumulative path distance and track status.
1039 
1040  double ds = *dist;
1041  path += ds;
1042  trf.setPath(path);
1043  if(dir == Propagator::FORWARD)
1045  else {
1047  }
1048  if(fTrace) {
1049  log << "Reverse fit track after propagation:\n";
1050  log << " Propagation distance = " << ds << "\n";
1051  log << trf;
1052  }
1053 
1054  // See if we have the proper information to calculate an optimal track
1055  // at this surface (should normally be possible).
1056 
1057  KFitTrack::FitStatus stat = trh.getStat();
1058  KFitTrack::FitStatus newstat = trf.getStat();
1059 
1060  if((newstat == KFitTrack::FORWARD_PREDICTED && stat == KFitTrack::BACKWARD) ||
1061  (newstat == KFitTrack::BACKWARD_PREDICTED && stat == KFitTrack::FORWARD)) {
1062 
1063  // Update stored KHitTrack to be optimal.
1064 
1065  bool ok = trh.combineFit(trf);
1066 
1067  // Update the stored path distance to be from the currently fitting track.
1068 
1069  trh.setPath(trf.getPath());
1070 
1071  // Update reference track.
1072 
1073  ref = trh;
1074 
1075  // If combination failed, abandon the fit and return failure.
1076 
1077  if(!ok) {
1078  dofit = false;
1079  result = false;
1080  break;
1081  }
1082  if(fTrace) {
1083  log << "Combined track:\n";
1084  log << trh;
1085  }
1086  }
1087 
1088  // Update measurement predction using current track hypothesis.
1089 
1090  bool ok = hit.predict(trf, prop, &ref);
1091  if(!ok) {
1092 
1093  // If prediction failed, abandon the fit and return failure.
1094 
1095  dofit = false;
1096  result = false;
1097  break;
1098  }
1099  else {
1100 
1101  // Prediction succeeded. Get incremental chisquare. If
1102  // this hit fails incremental chisquare cut, this hit will
1103  // be dropped from the unidirecitonal Kalman fit track,
1104  // but may still be in the smoothed track.
1105 
1106  double chisq = hit.getChisq();
1107  if(chisq < fMaxSmoothIncChisq) {
1108 
1109  // Update the reverse fitting track using the current measurement
1110  // (both track parameters and status).
1111 
1112  KFitTrack trf0(trf);
1113  hit.update(trf);
1114  bool update_ok = trf.isValid();
1115  if(!update_ok)
1116  trf = trf0;
1117  else {
1118  tchisq += chisq;
1119  trf.setChisq(tchisq);
1120 
1121  if(dir == Propagator::FORWARD)
1123  else {
1125  }
1126  if(fTrace) {
1127  log << "Reverse fit track after update:\n";
1128  log << trf;
1129  }
1130  if(fGTrace && fCanvases.size() > 0) {
1131  auto marker_it = fMarkerMap.find(hit.getID());
1132  if(marker_it != fMarkerMap.end()) {
1133  TMarker* marker = marker_it->second;
1134  marker->SetMarkerColor(kOrange);
1135  }
1136  fCanvases.back()->Update();
1137  }
1138 
1139  // If unidirectional track pointer is not null, make a
1140  // KHitTrack and save it in the unidirectional track.
1141 
1142  if(trg1 != 0) {
1143  KHitTrack trh1(trf, trh.getHit());
1144  trg1->addTrack(trh1);
1145  }
1146  }
1147  }
1148  }
1149  }
1150 
1151  // For forward fit, increment iterator at end of loop.
1152 
1153  if(dir == Propagator::FORWARD)
1154  ++it;
1155 
1156  } // Loop over KHitTracks.
1157 
1158  // If fit was successful and the unidirectional track pointer
1159  // is not null and the track is valid, set the fit status of
1160  // the last added KHitTrack to optimal.
1161 
1162  if(result && trg1 != 0 && trg1->isValid()) {
1163  if(dir == Propagator::FORWARD)
1165  else {
1167  }
1168  }
1169 
1170  // Recalibrate track map.
1171 
1172  trg.recalibrate();
1173 
1174  } // Do fit.
1175 
1176  // Get the final chisquare.
1177 
1178  double fchisq = 0.5 * (trg.startTrack().getChisq() + trg.endTrack().getChisq());
1179 
1180  // Summary.
1181 
1182  mf::LogInfo log("KalmanFilterAlg");
1183  log << "KalmanFilterAlg smooth track summary.\n"
1184  << "Smooth direction = " << (dir == Propagator::FORWARD ? "FORWARD" : "BACKWARD") << "\n"
1185  << "Track has " << trg.numHits() << " hits.\n"
1186  << "Track length = " << trg.endTrack().getPath() - trg.startTrack().getPath() << "\n"
1187  << "Track chisquare = " << fchisq << "\n";
1188  // log << trg << "\n";
1189  }
1190 
1191  //if(fGTrace && fCanvases.size() > 0) {
1192  // TText* t = 0;
1193  // if(result)
1194  // t = fMessages->AddText("Exit smoothTrack, status success");
1195  // else
1196  // t = fMessages->AddText("Exit smoothTrack, status fail");
1197  // t->SetBit(kCanDelete);
1198  // fInfoPad->Modified();
1199  // fCanvases.back()->Update();
1200  // }
1201 
1202  // Done.
1203 
1204  return result;
1205 }
1206 
1224  const Propagator* prop,
1225  KHitContainer& hits) const
1226 {
1227  if (!prop)
1228  throw cet::exception("KalmanFilterAlg") << "trkf::KalmanFilterAlg::extendTrack(): no propagator\n";
1229 
1230  // Default result failure.
1231 
1232  bool result = false;
1233 
1234  if(fGTrace && fCanvases.size() > 0) {
1235  TText* t = fMessages->AddText("Enter extendTrack");
1236  t->SetBit(kCanDelete);
1237  fInfoPad->Modified();
1238  fCanvases.back()->Update();
1239  }
1240 
1241  // Remember the original number of measurement.
1242 
1243  unsigned int nhits0 = trg.numHits();
1244 
1245  // It is an error if the KGTrack is not valid.
1246 
1247  if(trg.isValid()) {
1248  mf::LogInfo log("KalmanFilterAlg");
1249 
1250  // Examine the track endpoints and figure out which end of the
1251  // track to extend. The track is always extended from the optimal
1252  // end. It is an error if neither end point is optimal, or both
1253  // endoints are optimal. Reset the status of the optimal, and
1254  // make a copy of the starting track fit. Also get starting path
1255  // and chisquare.
1256 
1257  KHitTrack& trh0 = trg.startTrack();
1258  KHitTrack& trh1 = trg.endTrack();
1259  KFitTrack::FitStatus stat0 = trh0.getStat();
1260  KFitTrack::FitStatus stat1 = trh1.getStat();
1261  bool dofit = false;
1263  KFitTrack trf;
1264  double path = 0.;
1265  double tchisq = 0.;
1266 
1267  if(stat0 == KFitTrack::OPTIMAL) {
1268  if(stat1 == KFitTrack::OPTIMAL) {
1269 
1270  // Both ends optimal (do nothing, return failure).
1271 
1272  dofit = false;
1273  result = false;
1274  return result;
1275  }
1276  else {
1277 
1278  // Start optimal. Extend backward.
1279 
1280  dofit = true;
1281  dir = Propagator::BACKWARD;
1283  trf = trh0;
1284  path = trh0.getPath();
1285  tchisq = trh0.getChisq();
1286  }
1287  }
1288  else {
1289  if(stat1 == KFitTrack::OPTIMAL) {
1290 
1291  // End optimal. Extend forward.
1292 
1293  dofit = true;
1294  dir = Propagator::FORWARD;
1296  trf = trh1;
1297  path = trh1.getPath();
1298  tchisq = trh1.getChisq();
1299 
1300  // Make sure forward extend track momentum is over some
1301  // minimum value.
1302 
1303  if(trf.getVector()(4) > 5.) {
1304  trf.getVector()(4) = 5.;
1305  trf.getError()(4,4) = 5.;
1306  }
1307  }
1308  else {
1309 
1310  // Neither end optimal (do nothing, return failure).
1311 
1312  dofit = false;
1313  result = false;
1314  return result;
1315  }
1316  }
1317  if(dofit) {
1318 
1319  // Sort hit container using starting track.
1320 
1321  hits.sort(trf, true, prop, dir);
1322 
1323  // Draw and add hits in hit->marker map that are not already there.
1324 
1325  if(fGTrace && fCanvases.size() > 0) {
1326 
1327  // Loop over sorted KHitGroups.
1328  // Paint sorted hits black.
1329 
1330  const std::list<KHitGroup>& groups = hits.getSorted();
1331  for(auto const& gr : groups) {
1332 
1333  // Loop over hits in this group.
1334 
1335  const std::vector<std::shared_ptr<const KHitBase> >& phits = gr.getHits();
1336  for(auto const& phit : phits) {
1337  const KHitBase& hit = *phit;
1338  int pl = hit.getMeasPlane();
1339  if(pl >= 0 && pl < int(fPads.size())) {
1340 
1341  // Is this hit already in map?
1342 
1343  TMarker* marker = 0;
1344  auto marker_it = fMarkerMap.find(hit.getID());
1345  if(marker_it == fMarkerMap.end()) {
1346  double z = 0.;
1347  double x = 0.;
1348  hit_position(hit, z, x);
1349  marker = new TMarker(z, x, 20);
1350  fMarkerMap[hit.getID()] = marker;
1351  fPads[pl]->cd();
1352  marker->SetBit(kCanDelete); // Give away ownership.
1353  marker->SetMarkerSize(0.5);
1354  marker->Draw();
1355  }
1356  else
1357  marker = marker_it->second;
1358  marker->SetMarkerColor(kBlack);
1359  }
1360  }
1361  }
1362 
1363  // Loop over unsorted KHitGroups.
1364  // Paint unsorted hits blue.
1365 
1366  const std::list<KHitGroup>& ugroups = hits.getUnsorted();
1367  for(auto const& gr : ugroups) {
1368 
1369  // Loop over hits in this group.
1370 
1371  const std::vector<std::shared_ptr<const KHitBase> >& phits = gr.getHits();
1372  for(auto const& phit : phits) {
1373  const KHitBase& hit = *phit;
1374  int pl = hit.getMeasPlane();
1375  if(pl >= 0 && pl < int(fPads.size())) {
1376 
1377  // Is this hit already in map?
1378 
1379  TMarker* marker = 0;
1380  auto marker_it = fMarkerMap.find(hit.getID());
1381  if(marker_it == fMarkerMap.end()) {
1382  double z = 0.;
1383  double x = 0.;
1384  hit_position(hit, z, x);
1385  marker = new TMarker(z, x, 20);
1386  fMarkerMap[hit.getID()] = marker;
1387  fPads[pl]->cd();
1388  marker->SetBit(kCanDelete); // Give away ownership.
1389  marker->SetMarkerSize(0.5);
1390  marker->Draw();
1391  }
1392  else
1393  marker = marker_it->second;
1394  marker->SetMarkerColor(kBlue);
1395  }
1396  }
1397  }
1398  fCanvases.back()->Update();
1399  }
1400 
1401  //std::cout << "extendTrack: marker map has " << fMarkerMap.size() << " entries." << std::endl;
1402 
1403  // Extend loop starts here.
1404 
1405  int step = 0;
1406  int nsame = 0;
1407  int last_plane = -1;
1408  while(hits.getSorted().size() > 0) {
1409  ++step;
1410  if(fTrace) {
1411  log << "Extend Step " << step << "\n";
1412  log << "KGTrack has " << trg.numHits() << " hits.\n";
1413  log << trf;
1414  }
1415 
1416  // Get an iterator for the next KHitGroup.
1417 
1419  switch (dir) {
1420  case Propagator::FORWARD:
1421  it = hits.getSorted().begin();
1422  break;
1423  case Propagator::BACKWARD:
1424  it = hits.getSorted().end();
1425  --it;
1426  break;
1427  default:
1428  throw cet::exception("KalmanFilterAlg") << "KalmanFilterAlg::extendTrack(): invalid direction\n";
1429  } // switch
1430  const KHitGroup& gr = *it;
1431 
1432  if(fTrace) {
1433  double path_est = gr.getPath();
1434  log << "Next surface: " << *(gr.getSurface()) << "\n";
1435  log << " Estimated path length of hit group = " << path_est << "\n";
1436  }
1437 
1438  // Get the next prediction surface. If this KHitGroup is on the
1439  // preferred plane, use that as the prediction surface.
1440  // Otherwise, use the current track surface as the prediction
1441  // surface.
1442 
1443  std::shared_ptr<const Surface> psurf = trf.getSurface();
1444  if (gr.getPlane() < 0)
1445  throw cet::exception("KalmanFilterAlg") << "KalmanFilterAlg::extendTrack(): negative plane?\n";
1446  if(fPlane < 0 || gr.getPlane() < 0 || fPlane == gr.getPlane())
1447  psurf = gr.getSurface();
1448 
1449  // Propagate track to the prediction surface.
1450 
1451  boost::optional<double> dist = prop->noise_prop(trf, psurf, Propagator::UNKNOWN, true);
1452  if(!!dist && std::abs(*dist) > fMaxPropDist)
1453  dist = boost::optional<double>(false, 0.);
1454  double ds = 0.;
1455 
1456  if(!!dist) {
1457 
1458  // Propagation succeeded.
1459  // Update cumulative path distance and track status.
1460 
1461  ds = *dist;
1462  path += ds;
1463  trf.setPath(path);
1464  if(dir == Propagator::FORWARD)
1466  else {
1468  }
1469  if(fTrace) {
1470  log << "After propagation\n";
1471  log << " Incremental distance = " << ds << "\n";
1472  log << " Track path length = " << path << "\n";
1473  log << "KGTrack has " << trg.numHits() << " hits.\n";
1474  log << trf;
1475  }
1476 
1477  // Loop over measurements in this group.
1478 
1479  const std::vector<std::shared_ptr<const KHitBase> >& hits = gr.getHits();
1480  double best_chisq = 0.;
1481  std::shared_ptr<const KHitBase> best_hit;
1482  for(std::vector<std::shared_ptr<const KHitBase> >::const_iterator ihit = hits.begin();
1483  ihit != hits.end(); ++ihit) {
1484  const KHitBase& hit = **ihit;
1485 
1486  // Turn this hit blue.
1487 
1488  if(fGTrace && fCanvases.size() > 0) {
1489  auto marker_it = fMarkerMap.find(hit.getID());
1490  if(marker_it != fMarkerMap.end()) {
1491  TMarker* marker = marker_it->second;
1492  marker->SetMarkerColor(kBlue);
1493  }
1494  //fCanvases.back()->Update();
1495  }
1496 
1497  // Update predction using current track hypothesis and get
1498  // incremental chisquare.
1499 
1500  bool ok = hit.predict(trf, prop);
1501  if(ok) {
1502  double chisq = hit.getChisq();
1503  double preddist = hit.getPredDistance();
1504  if(abs(preddist) < fMaxPredDist &&
1505  (best_hit.get() == 0 || chisq < best_chisq)) {
1506  best_chisq = chisq;
1507  if(chisq < fMaxIncChisq)
1508  best_hit = *ihit;
1509  }
1510  }
1511  }
1512  if(fTrace) {
1513  log << "Best hit incremental chisquare = " << best_chisq << "\n";
1514  if(best_hit.get() != 0) {
1515  log << "Hit after prediction\n";
1516  log << *best_hit;
1517  }
1518  else
1519  log << "No hit passed chisquare cut.\n";
1520  }
1521  if(fGTrace && fCanvases.size() > 0)
1522  fCanvases.back()->Update();
1523 
1524  // If we found a best measurement, and if the incremental
1525  // chisquare passes the cut, add it to the track and update
1526  // fit information.
1527 
1528  bool update_ok = false;
1529  if(best_hit.get() != 0) {
1530  KFitTrack trf0(trf);
1531  best_hit->update(trf);
1532  update_ok = trf.isValid();
1533  if(!update_ok)
1534  trf = trf0;
1535  }
1536  if(update_ok) {
1537  ds += best_hit->getPredDistance();
1538  tchisq += best_chisq;
1539  trf.setChisq(tchisq);
1540  if(dir == Propagator::FORWARD)
1542  else {
1544  }
1545 
1546  // If the pointing error got too large, quit.
1547 
1548  if(trf.PointingError() > fMaxPErr) {
1549  if(fTrace)
1550  log << "Quitting because pointing error got too large.\n";
1551  break;
1552  }
1553 
1554  // Test number of consecutive measurements in the same plane.
1555 
1556  if(gr.getPlane() >= 0) {
1557  if(gr.getPlane() == last_plane)
1558  ++nsame;
1559  else {
1560  nsame = 1;
1561  last_plane = gr.getPlane();
1562  }
1563  }
1564  else {
1565  nsame = 0;
1566  last_plane = -1;
1567  }
1568  if(nsame <= fMaxSamePlane) {
1569 
1570  // Turn best hit red.
1571 
1572  if(fGTrace && fCanvases.size() > 0) {
1573  int pl = best_hit->getMeasPlane();
1574  if(pl >= 0 && pl < int(fPads.size())) {
1575  auto marker_it = fMarkerMap.find(best_hit->getID());
1576  if(marker_it != fMarkerMap.end()) {
1577  TMarker* marker = marker_it->second;
1578  marker->SetMarkerColor(kRed);
1579 
1580  // Redraw marker so that it will be on top.
1581 
1582  fPads[pl]->cd();
1583  marker->Draw();
1584  }
1585  }
1586  fCanvases.back()->Update();
1587  }
1588 
1589  // Make a KHitTrack and add it to the KGTrack.
1590 
1591  KHitTrack trh(trf, best_hit);
1592  trg.addTrack(trh);
1593 
1594  if(fTrace) {
1595  log << "After update\n";
1596  log << "KGTrack has " << trg.numHits() << " hits.\n";
1597  log << trf;
1598  }
1599  }
1600  }
1601  }
1602 
1603  // The current KHitGroup is now resolved.
1604  // Move it to unused list.
1605 
1606  hits.getUnused().splice(hits.getUnused().end(), hits.getSorted(), it);
1607 
1608  // If the propagation distance was the wrong direction, resort the measurements.
1609 
1610  if(!!dist &&
1611  ((dir == Propagator::FORWARD && (ds < fMinSortDist || ds > fMaxSortDist)) ||
1612  (dir == Propagator::BACKWARD && (-ds < fMinSortDist || -ds > fMaxSortDist)))) {
1613  if(fTrace)
1614  log << "Resorting measurements.\n";
1615  hits.sort(trf, true, prop, dir);
1616  }
1617  }
1618  }
1619 
1620  // Clean track.
1621 
1622  cleanTrack(trg);
1623 
1624  // Set the fit status of the last added KHitTrack to optimal and
1625  // get the final chisquare and path length.
1626 
1627  double fchisq = 0.;
1628  path = 0.;
1629  if(trg.isValid()) {
1630  path = trg.endTrack().getPath() - trg.startTrack().getPath();
1631  switch (dir) {
1632  case Propagator::FORWARD:
1634  fchisq = trg.endTrack().getChisq();
1635  break;
1636  case Propagator::BACKWARD:
1638  fchisq = trg.startTrack().getChisq();
1639  break;
1640  default:
1641  throw cet::exception("KalmanFilterAlg") << "KalmanFilterAlg::extendTrack(): invalid direction [II]\n";
1642  } // switch
1643  }
1644 
1645  // Summary.
1646 
1647  log << "KalmanFilterAlg extend track summary.\n"
1648  << "Extend direction = " << (dir == Propagator::FORWARD ? "FORWARD" : "BACKWARD") << "\n"
1649  << "Track has " << trg.numHits() << " hits.\n"
1650  << "Track length = " << path << "\n"
1651  << "Track chisquare = " << fchisq << "\n";
1652  // log << trg << "\n";
1653  }
1654 
1655  // Done.
1656 
1657  result = (trg.numHits() > nhits0);
1658 
1659  if(fGTrace && fCanvases.size() > 0) {
1660  TText* t = 0;
1661  if(result)
1662  t = fMessages->AddText("Exit extendTrack, status success");
1663  else
1664  t = fMessages->AddText("Exit extendTrack, status fail");
1665  t->SetBit(kCanDelete);
1666  fInfoPad->Modified();
1667  fCanvases.back()->Update();
1668  }
1669 
1670  return result;
1671 }
1672 
1688  const Propagator* /*prop*/,
1689  KETrack& tremom) const
1690 {
1691  if(!trg.isValid())
1692  return false;
1693 
1694  // Extract track with lowest momentum.
1695 
1696  const KHitTrack& trh = trg.endTrack();
1697  if (trh.getStat() == KFitTrack::INVALID)
1698  throw cet::exception("KalmanFilterAlg") << "KalmanFilterAlg::fitMomentumRange(): invalid end track\n";
1699  tremom = trh;
1700 
1701  // Set track momentum to a small value.
1702 
1703  tremom.getVector()(4) = 100.;
1704  tremom.getError()(4,0) = 0.;
1705  tremom.getError()(4,1) = 0.;
1706  tremom.getError()(4,2) = 0.;
1707  tremom.getError()(4,3) = 0.;
1708  tremom.getError()(4,4) = 10000.;
1709 
1710  // Done.
1711 
1712  return true;
1713 }
1714 
1743  const Propagator* prop,
1744  KETrack& tremom) const
1745 {
1746  // Get iterators pointing to the first and last tracks.
1747 
1748  const std::multimap<double, KHitTrack>& trackmap = trg.getTrackMap();
1749  if(trackmap.size() < 2)
1750  return false;
1752  itend[0] = trackmap.begin();
1753  itend[1] = trackmap.end();
1754  --itend[1];
1755 
1756  // Check the fit status and error matrix of the first and last
1757  // track.
1758 
1759  bool result = true;
1760 
1761  for(int i=0; result && i<2; ++i) {
1762  const KHitTrack& trh = itend[i]->second;
1763  KFitTrack::FitStatus stat = trh.getStat();
1764  if(stat != KFitTrack::OPTIMAL)
1765  result = false;
1766  const TrackError& err = trh.getError();
1767  for(int j=0; j<4; ++j) {
1768  if(err(4,j) != 0.)
1769  result = false;
1770  }
1771  }
1772  if(!result)
1773  return result;
1774 
1775  // We will periodically sample the track trajectory. At each sample
1776  // point, collect the following information.
1777  //
1778  // 1. The path distance at the sample point.
1779  // 2. The original momentum of the track at the sample point and its error.
1780  // 3. One copy of the track (KETrack) that will be propagated without noise
1781  // (infinite momentum track).
1782  // 3. A second copy of the track (KETrack) that will be propagated with the
1783  // minimum allowed momentum (range out track).
1784  // 4. A third copy of the track (KETrack) that will propagated with noise
1785  // with some intermediate momentum (noise track).
1786  //
1787  // Collect the first sample from the maximum path distance track.
1788 
1789  double s_sample = itend[1]->first;
1790  const KETrack& tre = itend[1]->second;
1791  KETrack tre_inf(tre);
1792  KTrack trk_range(tre);
1793  KETrack tre_noise(tre);
1794  tre_inf.getVector()(4) = 0.;
1795  tre_inf.getError()(4,4) = 0.;
1796  trk_range.getVector()(4) = 100.;
1797  tre_noise.getError()(4,4) = 0.;
1798  tre_noise.getVector()(4) = 1.;
1799  tre_noise.getError()(4,4) = 10.;
1800  double invp0 = tre_noise.getVector()(4);
1801  double var_invp0 = tre_noise.getError()(4,4);
1802 
1803  // Loop over fits, starting at the high path distance (low momentum)
1804  // end.
1805 
1806  for(std::multimap<double, KHitTrack>::const_reverse_iterator it = trackmap.rbegin();
1807  it != trackmap.rend(); ++it) {
1808  double s = it->first;
1809  const KHitTrack& trh = it->second;
1810 
1811  // Ignore non-optimal fits.
1812 
1813  KFitTrack::FitStatus stat = trh.getStat();
1814  if(stat != KFitTrack::OPTIMAL)
1815  continue;
1816 
1817  // See if this track is far enough from the previous sample to
1818  // make a new sample point.
1819 
1820  if(std::abs(s - s_sample) > fMinSampleDist) {
1821 
1822  // Propagate tracks to the current track surface.
1823 
1824  std::shared_ptr<const Surface> psurf = trh.getSurface();
1825  boost::optional<double> dist_inf = prop->err_prop(tre_inf, psurf,
1826  Propagator::UNKNOWN, false);
1827  boost::optional<double> dist_range = prop->vec_prop(trk_range, psurf,
1828  Propagator::UNKNOWN, false);
1829  boost::optional<double> dist_noise = prop->noise_prop(tre_noise, psurf,
1830  Propagator::UNKNOWN, true);
1831 
1832  // All propagations should normally succeed. If they don't,
1833  // ignore this sample for the purpose of updating the momentum.
1834 
1835  bool momentum_updated = false;
1836  if(!!dist_inf && !!dist_range && !!dist_noise) {
1837 
1838  // Extract the momentum at the new sample point.
1839 
1840  double invp1 = tre_noise.getVector()(4);
1841  double var_invp1 = tre_noise.getError()(4,4);
1842 
1843  // Get the average momentum and error for this pair of
1844  // sample points, and other data.
1845 
1846  double invp = 0.5 * (invp0 + invp1);
1847  double var_invp = 0.5 * (var_invp0 + var_invp1);
1848  double mass = tre_inf.Mass();
1849  double beta = std::sqrt(1. + mass*mass*invp*invp);
1850  double invbp = invp / beta;
1851 
1852  // Extract slope subvectors and sub-error-matrices.
1853  // We have the following variables.
1854  //
1855  // slope0 - Predicted slope vector (from infinite momentum track).
1856  // slope1 - Measured slope vector (from new sample point).
1857  // defl - Deflection (slope residual = difference between measured
1858  // and predicted slope vector).
1859  // err0 - Slope error matrix of prediction.
1860  // err1 - Slope error matrix of measurement
1861  // errc - Slope residual error matrix = err0 + err1.
1862  // errn - Noise slope error matrix divided by (1/beta*momentum).
1863 
1864  KVector<2>::type slope0 = project(tre_inf.getVector(), ublas::range(2, 4));
1865  KVector<2>::type slope1 = project(trh.getVector(), ublas::range(2, 4));
1866  KVector<2>::type defl = slope1 - slope0;
1867  KSymMatrix<2>::type err0 =
1868  project(tre_inf.getError(), ublas::range(2, 4), ublas::range(2, 4));
1869  KSymMatrix<2>::type err1 =
1870  project(trh.getError(), ublas::range(2, 4), ublas::range(2, 4));
1871  KSymMatrix<2>::type errc = err0 + err1;
1872  KSymMatrix<2>::type errn =
1873  project(tre_noise.getError(), ublas::range(2, 4), ublas::range(2, 4));
1874  errn -= err0;
1875  errn /= invbp;
1876 
1877  // Calculate updated average momentum and error.
1878 
1879  double new_invp = invp;
1880  double new_var_invp = var_invp;
1881  update_momentum(defl, errc, errn, mass, new_invp, new_var_invp);
1882 
1883  // Calculate updated momentum and error at the second sample
1884  // point.
1885 
1886  double dp = 1./new_invp - 1./invp;
1887  invp0 = 1./(1./invp1 + dp);
1888  var_invp0 = new_var_invp;
1889  momentum_updated = true;
1890 
1891  // Make sure that updated momentum is not less than minimum
1892  // allowed momentum.
1893 
1894  double invp_range = trk_range.getVector()(4);
1895  if(invp0 > invp_range)
1896  invp0 = invp_range;
1897  }
1898 
1899  // Update sample.
1900 
1901  if(momentum_updated) {
1902  s_sample = s;
1903  tre_inf = trh;
1904  tre_inf.getVector()(4) = 0.;
1905  tre_inf.getError()(4,4) = 0.;
1906  double invp_range = trk_range.getVector()(4);
1907  trk_range = trh;
1908  trk_range.getVector()(4) = invp_range;
1909  tre_noise = trh;
1910  tre_noise.getVector()(4) = invp0;
1911  tre_noise.getError()(4,4) = var_invp0;
1912  }
1913  }
1914  }
1915 
1916  // Propagate noise track to starting (high momentum) track surface
1917  // to get final starting momentum. This propagation should normally
1918  // always succeed, but if it doesn't, don't update the track.
1919 
1920  const KHitTrack& trh0 = itend[0]->second;
1921  std::shared_ptr<const Surface> psurf = trh0.getSurface();
1922  boost::optional<double> dist_noise = prop->noise_prop(tre_noise, psurf,
1923  Propagator::UNKNOWN, true);
1924  result = !!dist_noise;
1925 
1926  // Update momentum-estimating track.
1927 
1928  mf::LogInfo log("KalmanFilterAlg");
1929  if(result)
1930  tremom = tre_noise;
1931 
1932  // Done.
1933 
1934  return result;
1935 }
1936 
1948  const Propagator* prop,
1949  KETrack& tremom) const
1950 {
1951  mf::LogInfo log("KalmanFilterAlg");
1952  double invp_range = 0.;
1953  double invp_ms = 0.;
1954 
1955  // Get multiple scattering momentum estimate.
1956 
1957  KETrack tremom_ms;
1958  bool ok_ms = false;
1959  if(fFitMomMS) {
1960  ok_ms = fitMomentumMS(trg, prop, tremom_ms);
1961  if(ok_ms) {
1962  KGTrack trg_ms(trg);
1963  ok_ms = updateMomentum(tremom_ms, prop, trg_ms);
1964  if(ok_ms) {
1965  invp_ms = trg_ms.startTrack().getVector()(4);
1966  double var_invp = trg_ms.startTrack().getError()(4,4);
1967  double p = 0.;
1968  if(invp_ms != 0.)
1969  p = 1./invp_ms;
1970  double err_p = p*p * std::sqrt(var_invp);
1971  log << "Multiple scattering momentum estimate = " << p << "+-" << err_p << "\n";
1972  }
1973  }
1974  }
1975 
1976  // Get range momentum estimate.
1977 
1978  KETrack tremom_range;
1979  bool ok_range = false;
1980  if(fFitMomRange) {
1981  ok_range = fitMomentumRange(trg, prop, tremom_range);
1982  if(ok_range) {
1983  KGTrack trg_range(trg);
1984  ok_range = updateMomentum(tremom_range, prop, trg_range);
1985  if(ok_range) {
1986  invp_range = trg_range.startTrack().getVector()(4);
1987  double var_invp = trg_range.startTrack().getError()(4,4);
1988  double p = 0.;
1989  if(invp_range != 0.)
1990  p = 1./invp_range;
1991  double err_p = p*p * std::sqrt(var_invp);
1992  log << "Range momentum estimate = " << p << "+-" << err_p << "\n";
1993  }
1994  }
1995  }
1996 
1997  bool result = false;
1998  if(ok_range) {
1999  tremom = tremom_range;
2000  result = ok_range;
2001  }
2002  else if(ok_ms) {
2003  tremom = tremom_ms;
2004  result = ok_ms;
2005  }
2006  return result;
2007 }
2008 
2031  const Propagator* prop,
2032  KGTrack& trg) const
2033 {
2034  // Get modifiable track map.
2035 
2036  std::multimap<double, KHitTrack>& trackmap = trg.getTrackMap();
2037 
2038  // If track map is empty, immediately return failure.
2039 
2040  if(trackmap.size() == 0)
2041  return false;
2042 
2043  // Make trial propagations to the first and last track fit to figure
2044  // out which track fit is closer to the momentum estimating track.
2045 
2046  // Find distance to first track fit.
2047 
2048  KETrack tre0(tremom);
2049  boost::optional<double> dist0 = prop->vec_prop(tre0, trackmap.begin()->second.getSurface(),
2050  Propagator::UNKNOWN, false, 0, 0);
2051  // Find distance to last track fit.
2052 
2053  KETrack tre1(tremom);
2054  boost::optional<double> dist1 = prop->vec_prop(tre1, trackmap.rbegin()->second.getSurface(),
2055  Propagator::UNKNOWN, false, 0, 0);
2056 
2057  // Based on distances, make starting iterator and direction flag.
2058 
2059  bool forward = true;
2060  std::multimap<double, KHitTrack>::iterator it = trackmap.begin();
2061  if(!!dist0) {
2062 
2063  // Propagation to first track succeeded.
2064 
2065  if(!!dist1) {
2066 
2067  // Propagation to both ends succeeded. If the last track is
2068  // closer, initialize iterator and direction flag for reverse
2069  // direction.
2070 
2071  if(std::abs(*dist0) > std::abs(*dist1)) {
2072  it = trackmap.end();
2073  --it;
2074  forward = false;
2075  }
2076  }
2077  }
2078  else {
2079 
2080  // Propagation to first track failed. Initialize iterator and
2081  // direction flag for reverse direction, provided that the
2082  // propagation to the last track succeeded.
2083 
2084  if(!!dist1) {
2085  it = trackmap.end();
2086  --it;
2087  forward = false;
2088  }
2089  else {
2090 
2091  // Propagation to both ends failed. Return failure.
2092 
2093  return false;
2094  }
2095  }
2096 
2097  // Loop over track fits in global track.
2098 
2099  KETrack tre(tremom);
2100  bool done = false;
2101  while(!done) {
2102  KHitTrack& trh = it->second;
2103  if (trh.getStat() == KFitTrack::INVALID)
2104  throw cet::exception("KalmanFilterAlg") << "KalmanFilterAlg::updateMomentum(): invalid track\n";
2105 
2106  // Propagate momentum-estimating track to current track surface
2107  // and update momentum.
2108 
2109  boost::optional<double> dist = prop->noise_prop(tre, trh.getSurface(),
2110  Propagator::UNKNOWN, true);
2111 
2112  // Copy momentum to global track.
2113 
2114  std::multimap<double, KHitTrack>::iterator erase_it = trackmap.end();
2115  if(!!dist) {
2116  trh.getVector()(4) = tre.getVector()(4);
2117  trh.getError()(4,0) = 0.;
2118  trh.getError()(4,1) = 0.;
2119  trh.getError()(4,2) = 0.;
2120  trh.getError()(4,3) = 0.;
2121  trh.getError()(4,4) = tre.getError()(4,4);
2122  }
2123  else {
2124 
2125  // If the propagation failed, remember that we are supposed to
2126  // erase this track from the global track.
2127 
2128  erase_it = it;
2129  }
2130 
2131  // Advance the iterator and set the done flag.
2132 
2133  if(forward) {
2134  ++it;
2135  done = (it == trackmap.end());
2136  }
2137  else {
2138  done = (it == trackmap.begin());
2139  if(!done)
2140  --it;
2141  }
2142 
2143  // Update momentum-estimating track from just-updated global track
2144  // fit, or erase global track fit.
2145 
2146  if(erase_it == trackmap.end())
2147  tre = trh;
2148  else
2149  trackmap.erase(erase_it);
2150  }
2151 
2152  bool result = (trackmap.size() > 0);
2153 
2154  // Print value of momentum at start of track.
2155 
2156  //if(result) {
2157  // mf::LogInfo log("KalmanFilterAlg");
2158  // double invp = trg.startTrack().getVector()(4);
2159  // double var_invp = trg.startTrack().getError()(4,4);
2160  // double p = 0.;
2161  // if(invp != 0.)
2162  // p = 1./invp;
2163  // double err_p = p*p * std::sqrt(var_invp);
2164  // log << "Updated momentum estimate = " << p << "+-" << err_p;
2165  //}
2166 
2167  return result;
2168 }
2169 
2183  KGTrack& trg,
2184  const Propagator* prop) const
2185 {
2186  bool ok = true;
2187 
2188  // Call smoothTrack method in a loop.
2189 
2190  for(int ismooth = 0; ok && ismooth < nsmooth-1; ++ismooth) {
2191  KGTrack trg1(trg.getPrefPlane());
2192  ok = smoothTrack(trg, &trg1, prop);
2193  if(ok)
2194  trg = trg1;
2195  }
2196 
2197  // Do one final smooth without generating a new unidirectional
2198  // track.
2199 
2200  if(ok)
2201  ok = smoothTrack(trg, 0, prop);
2202 
2203  // Done.
2204 
2205  return ok;
2206 }
2207 
2215 {
2216  // Get hold of a modifiable track map from trg.
2217 
2218  std::multimap<double, KHitTrack>& trackmap = trg.getTrackMap();
2219 
2220  // Do an indefinite loop until we no longer find any dirt.
2221 
2222  bool done = false;
2223  while(!done) {
2224 
2225  // If track map has fewer than fMaxNoiseHits tracks, then this is a
2226  // noise track. Clear the map, making the whole track invalid.
2227 
2228  int ntrack = trackmap.size();
2229  if(ntrack <= fMaxNoiseHits) {
2230  for(auto const& trackmap_entry : trackmap) {
2231  const KHitTrack& trh = trackmap_entry.second;
2232  const KHitBase& hit = *(trh.getHit());
2233  auto marker_it = fMarkerMap.find(hit.getID());
2234  if(marker_it != fMarkerMap.end()) {
2235  TMarker* marker = marker_it->second;
2236  marker->SetMarkerColor(kGreen);
2237  }
2238  }
2239  trackmap.clear();
2240  done = true;
2241  break;
2242  }
2243 
2244  // Make sure the first two and last two tracks belong to different
2245  // views. If not, remove the first or last track.
2246 
2247  if(ntrack >= 2) {
2248 
2249  // Check start.
2250 
2251  std::multimap<double, KHitTrack>::iterator it = trackmap.begin();
2252  const KHitTrack& trh1a = (*it).second;
2253  const KHitBase& hit1a = *(trh1a.getHit());
2254  int plane1 = hit1a.getMeasPlane();
2255  double chisq1 = hit1a.getChisq();
2256  ++it;
2257  const KHitTrack& trh2a = (*it).second;
2258  const KHitBase& hit2a = *(trh2a.getHit());
2259  int plane2 = hit2a.getMeasPlane();
2260  double chisq2 = hit2a.getChisq();
2261  if((plane1 >= 0 && plane2 >= 0 && plane1 == plane2) ||
2262  chisq1 > fMaxEndChisq || chisq2 > fMaxEndChisq) {
2263  auto marker_it = fMarkerMap.find(hit1a.getID());
2264  if(marker_it != fMarkerMap.end()) {
2265  TMarker* marker = marker_it->second;
2266  marker->SetMarkerColor(kGreen);
2267  }
2268  trackmap.erase(trackmap.begin(), it);
2269  done = false;
2270  continue;
2271  }
2272 
2273  // Check end.
2274 
2275  it = trackmap.end();
2276  --it;
2277  const KHitTrack& trh1b = (*it).second;
2278  const KHitBase& hit1b = *(trh1b.getHit());
2279  plane1 = hit1b.getMeasPlane();
2280  chisq1 = hit1b.getChisq();
2281  --it;
2282  const KHitTrack& trh2b = (*it).second;
2283  const KHitBase& hit2b = *(trh2b.getHit());
2284  plane2 = hit2b.getMeasPlane();
2285  chisq2 = hit2b.getChisq();
2286  if((plane1 >= 0 && plane2 >= 0 && plane1 == plane2) ||
2287  chisq1 > fMaxEndChisq || chisq2 > fMaxEndChisq) {
2288  ++it;
2289  auto marker_it = fMarkerMap.find(hit1b.getID());
2290  if(marker_it != fMarkerMap.end()) {
2291  TMarker* marker = marker_it->second;
2292  marker->SetMarkerColor(kGreen);
2293  }
2294  trackmap.erase(it, trackmap.end());
2295  done = false;
2296  continue;
2297  }
2298  }
2299 
2300  // Loop over successive pairs of elements of track map. Look for
2301  // adjacent elements with distance separation greater than
2302  // fGapDist.
2303 
2304  std::multimap<double, KHitTrack>::iterator it = trackmap.begin();
2305  std::multimap<double, KHitTrack>::iterator jt = trackmap.end();
2306  int nb = 0; // Number of elements from begin to jt.
2307  int ne = ntrack; // Number of elements it to end.
2308  bool found_noise = false;
2309  for(; it != trackmap.end(); ++it, ++nb, --ne) {
2310  if(jt == trackmap.end())
2311  jt = trackmap.begin();
2312  else {
2313  if (nb < 1)
2314  throw cet::exception("KalmanFilterAlg") << "KalmanFilterAlg::cleanTrack(): nb not positive\n";
2315  if (ne < 1)
2316  throw cet::exception("KalmanFilterAlg") << "KalmanFilterAlg::cleanTrack(): ne not positive\n";
2317 
2318  double disti = (*it).first;
2319  double distj = (*jt).first;
2320  double sep = disti - distj;
2321  if (sep < 0.)
2322  throw cet::exception("KalmanFilterAlg") << "KalmanFilterAlg::fitMomentumRange(): negative separation\n";
2323 
2324  if(sep > fGapDist) {
2325 
2326  // Found a gap. See if we want to trim track.
2327 
2328  if(nb <= fMaxNoiseHits) {
2329 
2330  // Trim front.
2331 
2332  found_noise = true;
2333  for(auto jt = trackmap.begin(); jt != it; ++jt) {
2334  const KHitTrack& trh = jt->second;
2335  const KHitBase& hit = *(trh.getHit());
2336  auto marker_it = fMarkerMap.find(hit.getID());
2337  if(marker_it != fMarkerMap.end()) {
2338  TMarker* marker = marker_it->second;
2339  marker->SetMarkerColor(kGreen);
2340  }
2341  }
2342  trackmap.erase(trackmap.begin(), it);
2343  break;
2344  }
2345  if(ne <= fMaxNoiseHits) {
2346 
2347  // Trim back.
2348 
2349  found_noise = true;
2350  for(auto jt = it; jt != trackmap.end(); ++jt) {
2351  const KHitTrack& trh = jt->second;
2352  const KHitBase& hit = *(trh.getHit());
2353  auto marker_it = fMarkerMap.find(hit.getID());
2354  if(marker_it != fMarkerMap.end()) {
2355  TMarker* marker = marker_it->second;
2356  marker->SetMarkerColor(kGreen);
2357  }
2358  }
2359  trackmap.erase(it, trackmap.end());
2360  break;
2361  }
2362  }
2363  ++jt;
2364  }
2365  }
2366 
2367  // Decide if we are done.
2368 
2369  done = !found_noise;
2370  }
2371  if(fGTrace && fCanvases.size() > 0)
2372  fCanvases.back()->Update();
2373 }
Float_t x
Definition: compare.C:6
bool fGTrace
Graphical trace flag.
ublas::symmetric_matrix< double, ublas::lower, ublas::row_major, ublas::bounded_array< double, N *(N+1)/2 > > type
int getPrefPlane() const
Definition: KGTrack.h:51
const TrackError & getError() const
Track error matrix.
Definition: KETrack.h:54
Float_t s
Definition: plot.C:23
const std::shared_ptr< const KHitBase > & getHit() const
Measurement.
Definition: KHitTrack.h:53
bool fFitMomRange
Fit momentum using range.
bool fitMomentumRange(const KGTrack &trg, const Propagator *prop, KETrack &tremom) const
Estimate track momentum using range.
double fMaxPropDist
Maximum propagation distance to candidate surface.
double fGapDist
Minimum gap distance.
geo::Length_t DetHalfWidth(geo::TPCID const &tpcid) const
Returns the half width of the active volume of the specified TPC.
bool fFitMomMS
Fit momentum using multiple scattering.
void sort(const KTrack &trk, bool addUnsorted, const Propagator *prop, Propagator::PropDirection dir=Propagator::UNKNOWN)
(Re)sort objects in unsorted and sorted lists.
double Mass() const
Based on pdg code.
Definition: KTrack.cxx:128
const std::shared_ptr< const Surface > & getSurface() const
Surface.
Definition: KTrack.h:55
double PointingError() const
Pointing error (radians).
Definition: KETrack.cxx:74
double getPredDistance() const
Prediction distance.
Definition: KHitBase.h:78
void recalibrate()
Recalibrate track map.
Definition: KGTrack.cxx:97
std::map< int, TMarker * > fMarkerMap
Markers in current canvas.
int getMeasPlane() const
Measurement plane index.
Definition: KHitBase.h:84
const std::list< KHitGroup > & getUnused() const
Unused list.
Definition: KHitContainer.h:73
ublas::matrix< double, ublas::row_major, ublas::bounded_array< double, N *M > > type
const KHitTrack & endTrack() const
Track at end point.
Definition: KGTrack.cxx:46
intermediate_table::iterator iterator
KSymMatrix< 5 >::type TrackError
Track error matrix, dimension 5x5.
const std::vector< std::shared_ptr< const KHitBase > > & getHits() const
Measurement collection accessor.
Definition: KHitGroup.h:56
double fMaxEndChisq
Maximum incremental chisquare for endpoint hit.
bool fTrace
Trace flag.
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
Planar surface parallel to x-axis.
bool smoothTrack(KGTrack &trg, KGTrack *trg1, const Propagator *prop) const
Smooth track.
KalmanFilterAlg(const fhicl::ParameterSet &pset)
Constructor.
Double_t z
Definition: plot.C:279
TLegend * leg
Definition: compare.C:67
bool extendTrack(KGTrack &trg, const Propagator *prop, KHitContainer &hits) const
Add hits to existing track.
void cleanTrack(KGTrack &trg) const
Clean track by removing noise hits near endpoints.
void addTrack(const KHitTrack &trh)
Add track.
Definition: KGTrack.cxx:85
~KalmanFilterAlg()
Destructor.
double getPath() const
Estimated path distance.
Definition: KHitGroup.h:62
bool fitMomentum(const KGTrack &trg, const Propagator *prop, KETrack &tremom) const
Estimate track momentum using either range or multiple scattering.
FitStatus
Fit status enum.
Definition: KFitTrack.h:41
int getID() const
Unique id.
Definition: KHitBase.h:87
Double_t beta
std::vector< double > fGTraceZMin
Graphical trace minimum z for each view.
const std::multimap< double, KHitTrack > & getTrackMap() const
KHitTrack collection, indexed by path distance.
Definition: KGTrack.h:54
boost::optional< double > noise_prop(KETrack &tre, const std::shared_ptr< const Surface > &psurf, PropDirection dir, bool doDedx, KTrack *ref=0) const
Propagate with error and noise.
Definition: Propagator.cxx:394
double fMaxLDist
Maximum distance for linearized propagation.
boost::optional< double > err_prop(KETrack &tre, const std::shared_ptr< const Surface > &psurf, PropDirection dir, bool doDedx, KTrack *ref=0, TrackMatrix *prop_matrix=0) const
Propagate with error, but without noise.
Definition: Propagator.cxx:354
double fMaxSortDist
Sort high distance threshold.
double fMaxSeedPredDist
Maximum prediciton distance to accept a hit in seed phase.
double fMaxPredDist
Maximum prediciton distance to accept a hit.
M::value_type trace(const M &m)
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
void hits()
Definition: readHits.C:15
void setChisq(double chisq)
Set chisquare.
Definition: KFitTrack.h:73
intermediate_table::const_iterator const_iterator
TCanvas * c2
Definition: plot_hist.C:75
double getPath() const
Propagation distance.
Definition: KFitTrack.h:66
Kalman filter measurement class template.
ublas::vector< double, ublas::bounded_array< double, N > > type
bool syminvert(ublas::symmetric_matrix< T, TRI, L, A > &m)
double fGTraceWH
Window height.
TVirtualPad * fInfoPad
Information pad.
T get(std::string const &key) const
Definition: ParameterSet.h:231
void reconfigure(const fhicl::ParameterSet &pset)
Reconfigure method.
std::vector< std::unique_ptr< TCanvas > > fCanvases
Graphical trace canvases.
const std::list< KHitGroup > & getUnsorted() const
Unsorted list.
Definition: KHitContainer.h:72
bool updateMomentum(const KETrack &tremom, const Propagator *prop, KGTrack &trg) const
Set track momentum at each track surface.
double fGTraceXMin
Graphical trace minimum x.
double fGoodPErr
Pointing error threshold for switching to free propagation.
TPaveText * fMessages
Message box.
bool smoothTrackIter(int niter, KGTrack &trg, const Propagator *prop) const
Iteratively smooth a track.
void setStat(FitStatus stat)
Set fit status.
Definition: KFitTrack.h:74
double fMaxSeedIncChisq
Maximum incremental chisquare to accept a hit in seed phase.
double fMaxSmoothIncChisq
Maximum incremental chisquare to accept a hit in smooth phase.
double fMaxIncChisq
Maximum incremental chisquare to accept a hit.
boost::optional< double > vec_prop(KTrack &trk, const std::shared_ptr< const Surface > &psurf, PropDirection dir, bool doDedx, TrackMatrix *prop_matrix=0, TrackError *noise_matrix=0) const
Propagate without error (long distance).
Definition: Propagator.cxx:52
double fMinSampleDist
Minimum sample distance (for momentum measurement).
Kalman Filter.
Detector simulation of raw signals on wires.
double fMinSortDist
Sort low distance threshold.
const TrackVector & getVector() const
Track state vector.
Definition: KTrack.h:56
virtual void update(KETrack &tre) const =0
Update track method.
virtual double getChisq() const =0
Return incremental chisquare.
const KVector< N >::type & getMeasVector() const
Measurement vector.
Definition: KHit.h:102
bool fitMomentumMS(const KGTrack &trg, const Propagator *prop, KETrack &tremom) const
Estimate track momentum using multiple scattering.
TDirectory * dir
Definition: macro.C:5
double fGTraceXMax
Graphical trace maximum x.
std::vector< TVirtualPad * > fPads
View pads in current canvas.
size_t numHits() const
Number of measurements in track.
Definition: KGTrack.h:57
double fGTraceWW
Window width.
const std::shared_ptr< const Surface > & getSurface() const
Surface accessor.
Definition: KHitGroup.h:50
bool combineFit(const KFitTrack &trf)
Combine two tracks.
Definition: KFitTrack.cxx:76
void setPath(double path)
Set propagation distance.
Definition: KFitTrack.h:72
std::vector< double > fGTraceZMax
Graphical trace maximum z for each view.
bool buildTrack(const KTrack &trk, KGTrack &trg, const Propagator *prop, const Propagator::PropDirection dir, KHitContainer &hits, bool linear) const
Make a new track.
int fMaxSamePlane
Maximum consecutive hits in same plane.
Line surface perpendicular to x-axis.
int fMaxNoiseHits
Maximum number of hits in noise cluster.
double fMaxPErr
Maximum pointing error for free propagation.
bool isValid() const
Validity flag.
Definition: KGTrack.h:66
double getChisq() const
Fit chisquare.
Definition: KFitTrack.h:67
const KHitTrack & startTrack() const
Track at start point.
Definition: KGTrack.cxx:33
art framework interface to geometry description
const std::shared_ptr< const Surface > & getMeasSurface() const
Measurement surface.
Definition: KHitBase.h:81
virtual bool predict(const KETrack &tre, const Propagator *prop=0, const KTrack *ref=0) const =0
Prediction method (return false if fail).
int fMinLHits
Minimum number of hits to turn off linearized propagation.
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
bool isValid() const
Test if track is valid.
Definition: KTrack.cxx:90
PropDirection
Propagation direction enum.
Definition: Propagator.h:92
FitStatus getStat() const
Fit status.
Definition: KFitTrack.h:68
int getPlane() const
Plane index.
Definition: KHitGroup.h:53
int fPlane
Preferred view plane.
const std::list< KHitGroup > & getSorted() const
Sorted list.
Definition: KHitContainer.h:71