CMS 3D CMS Logo

KFFittingSmoother.h
Go to the documentation of this file.
1 
12 
15 
20 
21 
22 namespace {
23 
24  struct KFFittingSmootherParam {
25 
26  explicit KFFittingSmootherParam(const edm::ParameterSet & conf) :
27  theEstimateCut(conf.getParameter<double>("EstimateCut"))
28  ,theMaxFractionOutliers(conf.getParameter<double>("MaxFractionOutliers"))
29  ,theMaxNumberOfOutliers(conf.getParameter<int>("MaxNumberOfOutliers"))
30  ,theNoOutliersBeginEnd(conf.getParameter<bool>("NoOutliersBeginEnd"))
31  ,theMinDof(conf.getParameter<int>("MinDof"))
32  ,theMinNumberOfHits(conf.getParameter<int>("MinNumberOfHits"))
33  ,rejectTracksFlag(conf.getParameter<bool>("RejectTracks"))
34  ,breakTrajWith2ConsecutiveMissing(conf.getParameter<bool>("BreakTrajWith2ConsecutiveMissing"))
35  ,noInvalidHitsBeginEnd(conf.getParameter<bool>("NoInvalidHitsBeginEnd"))
36  {}
37 
38  double theEstimateCut;
39 
40  float theMaxFractionOutliers;
41  int theMaxNumberOfOutliers;
42  bool theNoOutliersBeginEnd;
43  int theMinDof;
44 
45  int theMinNumberOfHits;
46  bool rejectTracksFlag;
47  bool breakTrajWith2ConsecutiveMissing;
48  bool noInvalidHitsBeginEnd;
49 
50 
51  };
52 
53  class KFFittingSmoother final : public TrajectoryFitter, private KFFittingSmootherParam {
54 
55  public:
56  ~KFFittingSmoother() {}
57 
58  private:
59  KFFittingSmoother(const TrajectoryFitter& aFitter,
60  const TrajectorySmoother& aSmoother,
61  const edm::ParameterSet & conf) :
62  KFFittingSmootherParam(conf),
63  theFitter(aFitter.clone()),
64  theSmoother(aSmoother.clone())
65  {}
66 
67 
68 
69  static void fillDescriptions(edm::ParameterSetDescription & desc) {
70  desc.add<double>("EstimateCut",-1);
71  desc.add<double>("MaxFractionOutliers",0.3);
72  desc.add<int>("MaxNumberOfOutliers",3);
73  desc.add<int>("MinDof",2);
74  desc.add<bool>("NoOutliersBeginEnd",false);
75  desc.add<int>("MinNumberOfHits",5);
76  desc.add<bool>("RejectTracks",true);
77  desc.add<bool>("BreakTrajWith2ConsecutiveMissing",true);
78  desc.add<bool>("NoInvalidHitsBeginEnd",true);
79  desc.add<double>("LogPixelProbabilityCut",0);
80 
81  }
82 
83 
84  Trajectory fitOne(const Trajectory& t, fitType type) const override;
85  Trajectory fitOne(const TrajectorySeed& aSeed,
86  const RecHitContainer& hits,
87  const TrajectoryStateOnSurface& firstPredTsos, fitType type) const override;
88  Trajectory fitOne(const TrajectorySeed& aSeed,
89  const RecHitContainer& hits, fitType type) const override;
90 
91  const TrajectoryFitter* fitter() const {return theFitter.get();}
92  const TrajectorySmoother* smoother() const {return theSmoother.get();}
93 
94  std::unique_ptr<TrajectoryFitter> clone() const override {
95  return std::unique_ptr<TrajectoryFitter>(
96  new KFFittingSmoother(*theFitter,
97  *theSmoother,
98  *this)
99  );
100  }
101 
102 
103  virtual void setHitCloner(TkCloner const * hc) override {
104  theFitter->setHitCloner(hc);
105  theSmoother->setHitCloner(hc);
106  }
107 
108  KFFittingSmoother(const TrajectoryFitter& aFitter,
109  const TrajectorySmoother& aSmoother,
110  KFFittingSmootherParam const & other) :
111  KFFittingSmootherParam(other),
112  theFitter(aFitter.clone()),
113  theSmoother(aSmoother.clone())
114  {}
115 
116 
117 
118  Trajectory smoothingStep(Trajectory && fitted) const {
119  if (theEstimateCut>0) {
120  // remove "outlier" at the end of Traj
121  while (!fitted.empty() && fitted.foundHits()>=theMinNumberOfHits &&
122  ( !fitted.lastMeasurement().recHitR().isValid()
123  || ( fitted.lastMeasurement().recHitR().det()!=nullptr && fitted.lastMeasurement().estimate()>theEstimateCut)
124  )
125  )
126  fitted.pop();
127  if (fitted.foundHits() < theMinNumberOfHits ) return Trajectory();
128  }
129  return theSmoother->trajectory(fitted);
130  }
131 
132  private:
133 
134  const std::unique_ptr<TrajectoryFitter> theFitter;
135  const std::unique_ptr<TrajectorySmoother> theSmoother;
136 
137 
139  static bool checkForNans(const Trajectory &theTraj);
140 
141  friend class KFFittingSmootherESProducer;
142 
143  };
144 
145 
146 // #define VI_DEBUG
147 
148 #ifdef VI_DEBUG
149 #define DPRINT(x) std::cout << x << ": "
150 #define PRINT std::cout
151 #else
152 #define DPRINT(x) LogTrace(x)
153 #define PRINT LogTrace("")
154 #endif
155 
156 Trajectory KFFittingSmoother::fitOne(const Trajectory& t, fitType type) const {
157  if (!t.isValid() ) return Trajectory();
158  return smoothingStep(theFitter->fitOne(t,type));
159 }
160 
161 bool KFFittingSmoother::checkForNans(const Trajectory & theTraj)
162 {
163  if (edm::isNotFinite(theTraj.chiSquared ())) return false;
164  auto const & vtm = theTraj.measurements();
165  for (auto const & tm : vtm) {
166  if (edm::isNotFinite(tm.estimate())) return false;
167  auto const & v = tm.updatedState ().localParameters ().vector();
168  for (int i=0;i<5;++i) if (edm::isNotFinite(v[i])) return false;
169  auto const & m = tm.updatedState ().curvilinearError ().matrix();
170  for (int i=0;i<5;++i)
171  for (int j=0;j<(i+1);++j) if (edm::isNotFinite(m(i,j))) return false;
172  }
173  return true;
174 }
175 
176 
177 namespace {
178  inline
179  void print(const std::string& header, const TrajectoryStateOnSurface & tsos) {
180  DPRINT("TrackFitters") << header << tsos.globalPosition().perp() << ' ' << tsos.globalPosition().z()
181  << ' ' << 1./tsos.signedInverseMomentum() << ' ' << 1./tsos.transverseCurvature()
182  << ' ' << tsos.globalMomentum().eta() << std::endl;
183  }
184 }
185 
186 
187 Trajectory KFFittingSmoother::fitOne(const TrajectorySeed& aSeed,
188  const RecHitContainer& hits,
189  const TrajectoryStateOnSurface& firstPredTsos,
190  fitType type) const
191 {
192  LogDebug("TrackFitters") << "In KFFittingSmoother::fit";
193 
194  print("firstPred ", firstPredTsos);
195 
196  if ( hits.empty() ) return Trajectory();
197 
198  RecHitContainer myHits = hits;
199  Trajectory tmp_first;
200 
201  //call the fitter
202  Trajectory smoothed = smoothingStep(theFitter->fitOne(aSeed, myHits, firstPredTsos));
203 
204 
205  do {
206 
207 #ifdef EDM_ML_DEBUG
208  //if no outliers the fit is done only once
209  for (unsigned int j=0;j<myHits.size();j++) {
210  if (myHits[j]->det())
211  LogTrace("TrackFitters") << "hit #:" << j+1 << " rawId=" << myHits[j]->det()->geographicalId().rawId()
212  << " validity=" << myHits[j]->isValid();
213  else
214  LogTrace("TrackFitters") << "hit #:" << j+1 << " Hit with no Det information";
215  }
216 #endif
217 
218 #if defined(VI_DEBUG) || defined(EDM_ML_DEBUG)
219 if (smoothed.isValid()) {
220  print("first state ",smoothed.firstMeasurement().updatedState());
221  print("last state ",smoothed.lastMeasurement().updatedState());
222 }
223 #endif
224 
225  bool hasNaN = false;
226  if ( !smoothed.isValid() || (hasNaN = !checkForNans(smoothed)) || ( smoothed.foundHits() < theMinNumberOfHits ) ) {
227  if(hasNaN) edm::LogWarning("TrackNaN")<<"Track has NaN";
228  if ( smoothed.foundHits() < theMinNumberOfHits ) LogTrace("TrackFitters") << "smoothed.foundHits()<theMinNumberOfHits";
229  DPRINT("TrackFitters") << "smoothed invalid => trajectory rejected with nhits/chi2 " << smoothed.foundHits() << '/' << smoothed.chiSquared() << "\n";
230  if (rejectTracksFlag) {
231  return Trajectory();
232  } else {
233  std::swap(smoothed, tmp_first); // if first attempt, tmp_first would be invalid anyway
234  DPRINT("TrackFitters") << "smoothed invalid => returning orignal trajectory with nhits/chi2 " << smoothed.foundHits() << '/' << smoothed.chiSquared() << "\n";
235  }
236  break;
237  }
238 #ifdef EDM_ML_DEBUG
239  else {
240  LogTrace("TrackFitters") << "dump hits after smoothing";
241  Trajectory::DataContainer meas = smoothed.measurements();
242  for (Trajectory::DataContainer::iterator it=meas.begin();it!=meas.end();++it) {
243  LogTrace("TrackFitters") << "hit #" << meas.end()-it-1 << " validity=" << it->recHit()->isValid()
244  << " det=" << it->recHit()->geographicalId().rawId();
245  }
246  }
247 #endif
248 
249  if (myHits.size() !=smoothed.measurements().size())
250  DPRINT("TrackFitters") << "lost hits. before/after: " << myHits.size() <<'/' << smoothed.measurements().size()<< "\n";
251 
252  if ( theEstimateCut <= 0) break;
253 
254 
255  // Check if there are outliers
256 
257  auto msize = smoothed.measurements().size();
258  declareDynArray(unsigned int, msize, bad);
259  unsigned int nbad=0;
260  unsigned int ind=0;
261  unsigned int lastValid=smoothed.measurements().size();
262  for (auto const & tm : smoothed.measurements() ) {
263  if (tm.estimate()>theEstimateCut
264  && tm.recHitR().det()!=nullptr // do not consider outliers constraints and other special "hits"
265  ) bad[nbad++]=ind;
266  if (ind<lastValid && tm.recHitR().det()!=nullptr && tm.recHitR().isValid()) lastValid=ind;
267  ++ind;
268  }
269 
270  if (0==nbad) break;
271 
272  DPRINT("TrackFitters") << "size/found/outliers list " << smoothed.measurements().size() <<'/' << smoothed.foundHits() << ' ' << nbad << ": ";
273  for (auto i=0U; i<nbad; ++i) PRINT << bad[i] <<',';
274  PRINT << std::endl;
275 
276 
277 
278  if (
279  // (smoothed.foundHits() == theMinNumberOfHits) ||
280  int(nbad)>theMaxNumberOfOutliers ||
281  float(nbad) > theMaxFractionOutliers*float(smoothed.foundHits())
282  ) {
283  DPRINT("TrackFitters") << "smoothed low quality => trajectory with nhits/chi2 " << smoothed.foundHits() << '/' << smoothed.chiSquared() << "\n";
284  PRINT << "try to remove " << lastValid << std::endl;
285  nbad = 0; // try to short the traj... (below lastValid will be added)
286 
287  // do not perform outliers rejection if track is already low quality
288  /*
289  if ( rejectTracksFlag && (smoothed.chiSquared() > theEstimateCut*smoothed.ndof()) ) {
290  DPRINT("TrackFitters") << "smoothed low quality => trajectory rejected with nhits/chi2 " << smoothed.foundHits() << '/' << smoothed.chiSquared() << "\n";
291  return Trajectory();
292  } else {
293  DPRINT("TrackFitters") << "smoothed low quality => return original trajectory with nhits/chi2 " << smoothed.foundHits() << '/' << smoothed.chiSquared() << "\n";
294  }
295  break;
296  */
297  }
298 
299 
300  // always add last valid hit as outlier candidate
301  bad[nbad++]=lastValid;
302 
303  // if ( (smoothed.ndof()<theMinDof) | ) break;
304 
305 
306 
307  assert(smoothed.measurements().size() <= myHits.size());
308 
309  myHits.resize(smoothed.measurements().size()); // hits are only removed from the back...
310 
311  assert(smoothed.measurements().size() == myHits.size());
312 
313  declareDynArray(Trajectory,nbad,smoothedCand);
314 
315 
316  auto NHits = myHits.size();
318 
319  auto loc = nbad;
320  for (auto i=0U; i<nbad; ++i) {
321  auto j = NHits-bad[i]-1;
322  assert(myHits[j]->geographicalId() == smoothed.measurements()[bad[i]].recHitR().geographicalId());
323  auto removedHit = myHits[j];
324  myHits[j] = std::make_shared<InvalidTrackingRecHit>(*removedHit->det(), TrackingRecHit::missing);
325  smoothedCand[i] = smoothingStep(theFitter->fitOne(aSeed, myHits, firstPredTsos));
326  myHits[j] = removedHit;
327  if (smoothedCand[i].isValid() && smoothedCand[i].chiSquared()< minChi2) {
328  minChi2 = smoothedCand[i].chiSquared();
329  loc=i;
330  }
331  }
332 
333  if (loc == nbad) {
334  DPRINT("TrackFitters") <<"New trajectories all invalid"<< "\n";
335  return Trajectory();
336  }
337 
338  DPRINT("TrackFitters") << "outlier removed " << bad[loc] << '/' << minChi2 << " was " << smoothed.chiSquared()<< "\n";
339 
340  if (minChi2>smoothed.chiSquared()) {
341 
342  DPRINT("TrackFitters") << "removing outlier makes chi2 worse " << minChi2 << '/' << smoothed.chiSquared() << "\nOri: ";
343  for (auto const & tm : smoothed.measurements() )
344  PRINT << tm.recHitR().geographicalId() << '/' << tm.estimate() <<' ';
345  PRINT << "\nNew: ";
346  for (auto const & tm : smoothedCand[loc].measurements() )
347  PRINT << tm.recHitR().geographicalId() << '/' << tm.estimate() <<' ';
348  PRINT << "\n";
349 
350  // return Trajectory();
351  // break;
352  }
353 
354  std::swap(smoothed,tmp_first);
355  myHits[NHits-bad[loc]-1] = std::make_shared<InvalidTrackingRecHit>(*myHits[NHits-bad[loc]-1]->det(), TrackingRecHit::missing);
356  std::swap(smoothed,smoothedCand[loc]);
357  // firstTry=false;
358 
359  DPRINT("TrackFitters") << "new trajectory with nhits/chi2 " << smoothed.foundHits() << '/' << smoothed.chiSquared() << "\n";
360 
361 
362 
363 
364  // Look if there are two consecutive invalid hits FIXME: take into account split matched hits!!!
365  if ( breakTrajWith2ConsecutiveMissing ) {
366  unsigned int firstinvalid = myHits.size();
367  for ( unsigned int j=0; j<myHits.size()-1; ++j )
368  {
369  if ( ((myHits[j ]->type() == TrackingRecHit::missing) && (myHits[j ]->geographicalId().rawId() != 0)) &&
370  ((myHits[j+1]->type() == TrackingRecHit::missing) && (myHits[j+1]->geographicalId().rawId() != 0))
371  && ( (myHits[j ]->geographicalId().rawId()&(~3)) != (myHits[j+1]->geographicalId().rawId()&(~3) ) ) // same gluedDet
372  )
373  {
374  firstinvalid = j;
375  DPRINT("TrackFitters") << "Found two consecutive missing hits. First invalid: " << firstinvalid << "\n";
376  break;
377  }
378  }
379 
380  //reject all the hits after the last valid before two consecutive invalid (missing) hits
381  //hits are sorted in the same order as in the track candidate FIXME??????
382  if (firstinvalid != myHits.size()) {
383  myHits.erase(myHits.begin()+firstinvalid,myHits.end());
384  smoothed = smoothingStep(theFitter->fitOne(aSeed, myHits, firstPredTsos));
385  DPRINT("TrackFitters") << "Trajectory shortened " << smoothed.foundHits() << '/' << smoothed.chiSquared() << "\n";
386  }
387  }
388 
389  } // do
390  while ( true );
391 
392  if ( smoothed.isValid() ) {
393  if ( noInvalidHitsBeginEnd
394  && !smoothed.empty() //should we send a warning ?
395  ) {
396  // discard latest dummy measurements
397  if (!smoothed.empty() && !smoothed.lastMeasurement().recHitR().isValid() )
398  LogTrace("TrackFitters") << "Last measurement is invalid";
399 
400  while (!smoothed.empty() && !smoothed.lastMeasurement().recHitR().isValid() )
401  smoothed.pop();
402 
403  //remove the invalid hits at the begin of the trajectory
404  if (!smoothed.empty() && !smoothed.firstMeasurement().recHitR().isValid() ) {
405  LogTrace("TrackFitters") << "First measurement is in`valid";
406  Trajectory tmpTraj(smoothed.seed(),smoothed.direction());
407  Trajectory::DataContainer & meas = smoothed.measurements();
408  auto it = meas.begin();
409  for ( ; it!=meas.end(); ++it )
410  if ( it->recHitR().isValid() ) break;
411  tmpTraj.push(std::move(*it),smoothed.chiSquared());//push the first valid measurement and set the same global chi2
412 
413  for (auto itt=it+1; itt!=meas.end();++itt)
414  tmpTraj.push(std::move(*itt),0);//add all the other measurements
415 
416  std::swap(smoothed,tmpTraj);
417 
418  } // if ( !smoothed.firstMeasurement().recHit()->isValid() )
419 
420  } // if ( noInvalidHitsBeginEnd )
421 
422  LogTrace("TrackFitters") << "end: returning smoothed trajectory with chi2="
423  << smoothed.chiSquared() ;
424 
425  //LogTrace("TrackFitters") << "dump hits before return";
426  //Trajectory::DataContainer meas = smoothed.measurements();
427  //for (Trajectory::DataContainer::iterator it=meas.begin();it!=meas.end();++it) {
428  //LogTrace("TrackFitters") << "hit #" << meas.end()-it-1 << " validity=" << it->recHit()->isValid()
429  //<< " det=" << it->recHit()->geographicalId().rawId();
430  //}
431 
432  }
433 
434  return smoothed;
435 
436 }
437 
438 
439 Trajectory KFFittingSmoother::fitOne(const TrajectorySeed& aSeed,
440  const RecHitContainer& hits,fitType type) const{
441 
442  throw cms::Exception("TrackFitters",
443  "KFFittingSmoother::fit(TrajectorySeed, <TransientTrackingRecHit>) not implemented");
444 
445  return Trajectory();
446 }
447 
448 } // namespace
#define LogDebug(id)
bool empty() const
True if trajectory has no measurements.
Definition: Trajectory.h:254
type
Definition: HCALResponse.h:21
int foundHits() const
Definition: Trajectory.h:225
T perp() const
Definition: PV3DBase.h:72
TrajectorySeed const & seed() const
Access to the seed used to reconstruct the Trajectory.
Definition: Trajectory.h:285
std::string print(const Track &, edm::Verbosity=edm::Concise)
Track print utility.
Definition: print.cc:10
GlobalPoint globalPosition() const
PropagationDirection const & direction() const
Definition: Trajectory.cc:140
DataContainer const & measurements() const
Definition: Trajectory.h:196
std::vector< TrajectoryMeasurement > DataContainer
Definition: Trajectory.h:44
bool isNotFinite(T x)
Definition: isFinite.h:10
void swap(edm::DataFrameContainer &lhs, edm::DataFrameContainer &rhs)
TrajectoryMeasurement const & lastMeasurement() const
Definition: Trajectory.h:174
T z() const
Definition: PV3DBase.h:64
ParameterDescriptionBase * add(U const &iLabel, T const &value)
#define LogTrace(id)
bool isValid() const
Definition: Trajectory.h:279
TrajectoryMeasurement const & firstMeasurement() const
Definition: Trajectory.h:187
void pop()
Definition: Trajectory.cc:29
TEveGeoShape * clone(const TEveElement *element, TEveElement *parent)
Definition: eve_macros.cc:135
ConstRecHitPointer::element_type const & recHitR() const
#define DPRINT(x)
float chiSquared() const
Definition: Trajectory.h:262
T eta() const
Definition: PV3DBase.h:76
#define PRINT
GlobalVector globalMomentum() const
susybsm::HSCParticleCollection hc
Definition: classes.h:25
TrajectoryStateOnSurface const & updatedState() const
#define declareDynArray(T, n, x)
Definition: DynArray.h:59
def move(src, dest)
Definition: eostools.py:510