CMS 3D CMS Logo

DuplicateTrackMerger.cc
Go to the documentation of this file.
1 
9 
14 
15 
19 
21 
25 #include "TrackMerger.h"
26 
27 #include <vector>
28 #include <algorithm>
29 #include <string>
30 #include <iostream>
31 #include <atomic>
32 
34 
35 using namespace reco;
36 namespace {
37  class DuplicateTrackMerger final : public edm::stream::EDProducer<> {
38  public:
40  explicit DuplicateTrackMerger(const edm::ParameterSet& iPara);
42  virtual ~DuplicateTrackMerger();
43 
44  using CandidateToDuplicate = std::vector<std::pair<int, int>>;
45 
46  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
47 
48 
49  private:
51  void produce( edm::Event &, const edm::EventSetup &) override;
52 
53  bool checkForDisjointTracks(const reco::Track *t1, const reco::Track *t2, TSCPBuilderNoMaterial& tscpBuilder) const;
54  bool checkForOverlappingTracks(const reco::Track *t1, const reco::Track *t2, const float cosT) const;
55 
56  private:
58  const GBRForest* forest_;
59 
60 
62  std::string dbFileName_;
63  bool useForestFromDB_;
64  std::string forestLabel_;
65 
66  std::string propagatorName_;
67  std::string chi2EstimatorName_;
68 
72  double minDeltaR3d2_;
74  double minBDTG_;
76  double minpT2_;
78  double minP_;
80  float maxDCA2_;
82  float maxDPhi_;
84  float maxDLambda_;
86  float maxDdxy_;
88  float maxDdsz_;
90  float maxDQoP_;
92  unsigned int overlapCheckMaxHits_;
94  unsigned int overlapCheckMaxMissingLayers_;
96  float overlapCheckMinCosT_;
97 
98  const MagneticField *magfield_;
99  const TrackerTopology *ttopo_;
100  const TrackerGeometry *geom_;
101  const Propagator *propagator_;
102  const Chi2MeasurementEstimatorBase *chi2Estimator_;
103 
105  TrackMerger merger_;
106 
107 #ifdef EDM_ML_DEBUG
108  bool debug_;
109 #endif
110  };
111  }
112 
121 #include "TFile.h"
122 
125 
126 #include "DuplicateTrackType.h"
127 
128 namespace {
129 
130 
131 void
133 {
135  desc.add<edm::InputTag>("source",edm::InputTag());
136  desc.add<double>("minDeltaR3d",-4.0);
137  desc.add<double>("minBDTG",-0.1);
138  desc.add<double>("minpT",0.2);
139  desc.add<double>("minP",0.4);
140  desc.add<double>("maxDCA",30.0);
141  desc.add<double>("maxDPhi",0.30);
142  desc.add<double>("maxDLambda",0.30);
143  desc.add<double>("maxDdsz",10.0);
144  desc.add<double>("maxDdxy",10.0);
145  desc.add<double>("maxDQoP",0.25);
146  desc.add<unsigned>("overlapCheckMaxHits", 4);
147  desc.add<unsigned>("overlapCheckMaxMissingLayers", 1);
148  desc.add<double>("overlapCheckMinCosT", 0.99);
149  desc.add<std::string>("forestLabel","MVADuplicate");
150  desc.add<std::string>("GBRForestFileName","");
151  desc.add<bool>("useInnermostState",true);
152  desc.add<std::string>("ttrhBuilderName","WithAngleAndTemplate");
153  desc.add<std::string>("propagatorName", "PropagatorWithMaterial");
154  desc.add<std::string>("chi2EstimatorName", "DuplicateTrackMergerChi2Est");
155  descriptions.add("DuplicateTrackMerger", desc);
156 }
157 
158 
159 DuplicateTrackMerger::DuplicateTrackMerger(const edm::ParameterSet& iPara) : forest_(nullptr), merger_(iPara)
160 {
161 
162  trackSource_ = consumes<reco::TrackCollection>(iPara.getParameter<edm::InputTag>("source"));
163  minDeltaR3d2_ = iPara.getParameter<double>("minDeltaR3d"); minDeltaR3d2_*=std::abs(minDeltaR3d2_);
164  minBDTG_ = iPara.getParameter<double>("minBDTG");
165  minpT2_ = iPara.getParameter<double>("minpT"); minpT2_ *= minpT2_;
166  minP_ = iPara.getParameter<double>("minP");
167  maxDCA2_ = iPara.getParameter<double>("maxDCA"); maxDCA2_*=maxDCA2_;
168  maxDPhi_ = iPara.getParameter<double>("maxDPhi");
169  maxDLambda_ = iPara.getParameter<double>("maxDLambda");
170  maxDdsz_ = iPara.getParameter<double>("maxDdsz");
171  maxDdxy_ = iPara.getParameter<double>("maxDdxy");
172  maxDQoP_ = iPara.getParameter<double>("maxDQoP");
173  overlapCheckMaxHits_ = iPara.getParameter<unsigned>("overlapCheckMaxHits");
174  overlapCheckMaxMissingLayers_ = iPara.getParameter<unsigned>("overlapCheckMaxMissingLayers");
175  overlapCheckMinCosT_ = iPara.getParameter<double>("overlapCheckMinCosT");
176 
177  produces<std::vector<TrackCandidate> >("candidates");
178  produces<CandidateToDuplicate>("candidateMap");
179 
180  forestLabel_ = iPara.getParameter<std::string>("forestLabel");
181 
182  dbFileName_ = iPara.getParameter<std::string>("GBRForestFileName");
183  useForestFromDB_ = dbFileName_.empty();
184 
185  propagatorName_ = iPara.getParameter<std::string>("propagatorName");
186  chi2EstimatorName_ = iPara.getParameter<std::string>("chi2EstimatorName");
187 
188  /*
189  tmvaReader_ = new TMVA::Reader("!Color:Silent");
190  tmvaReader_->AddVariable("ddsz",&tmva_ddsz_);
191  tmvaReader_->AddVariable("ddxy",&tmva_ddxy_);
192  tmvaReader_->AddVariable("dphi",&tmva_dphi_);
193  tmvaReader_->AddVariable("dlambda",&tmva_dlambda_);
194  tmvaReader_->AddVariable("dqoverp",&tmva_dqoverp_);
195  tmvaReader_->AddVariable("delta3d_r",&tmva_d3dr_);
196  tmvaReader_->AddVariable("delta3d_z",&tmva_d3dz_);
197  tmvaReader_->AddVariable("outer_nMissingInner",&tmva_outer_nMissingInner_);
198  tmvaReader_->AddVariable("inner_nMissingOuter",&tmva_inner_nMissingOuter_);
199  tmvaReader_->BookMVA("BDTG",mvaFilePath);
200  */
201 
202 
203 }
204 
205 DuplicateTrackMerger::~DuplicateTrackMerger()
206 {
207 
208  if(!useForestFromDB_) delete forest_;
209 
210 }
211 
212 
213 #ifdef VI_STAT
214  struct Stat {
215  Stat() : maxCos(1.1), nCand(0),nLoop0(0) {}
216  ~Stat() {
217  std::cout << "Stats " << nCand << ' ' << nLoop0 << ' ' << maxCos << std::endl;
218  }
219  std::atomic<float> maxCos;
220  std::atomic<int> nCand, nLoop0;
221  };
222  Stat stat;
223 #endif
224 
225 template<typename T>
226 void update_maximum(std::atomic<T>& maximum_value, T const& value) noexcept
227 {
228  T prev_value = maximum_value;
229  while(prev_value < value &&
230  !maximum_value.compare_exchange_weak(prev_value, value))
231  ;
232 }
233 
234  template<typename T>
235 void update_minimum(std::atomic<T>& minimum_value, T const& value) noexcept
236 {
237  T prev_value = minimum_value;
238  while(prev_value > value &&
239  !minimum_value.compare_exchange_weak(prev_value, value))
240  ;
241 }
242 
243 
244 void DuplicateTrackMerger::produce(edm::Event& iEvent, const edm::EventSetup& iSetup)
245 {
246 
247  merger_.init(iSetup);
248 
249  if(!forest_){
250  if(useForestFromDB_){
251  edm::ESHandle<GBRForest> forestHandle;
252  iSetup.get<GBRWrapperRcd>().get(forestLabel_,forestHandle);
253  forest_ = forestHandle.product();
254  }else{
255  TFile gbrfile(dbFileName_.c_str());
256  forest_ = dynamic_cast<const GBRForest*>(gbrfile.Get(forestLabel_.c_str()));
257  }
258  }
259 
260  //edm::Handle<edm::View<reco::Track> >handle;
262  iEvent.getByToken(trackSource_,handle);
263  auto const & tracks = *handle;
264 
266  iSetup.get<IdealMagneticFieldRecord>().get(hmagfield);
267  magfield_ = hmagfield.product();
268 
270  iSetup.get<TrackerTopologyRcd>().get(httopo);
271  ttopo_ = httopo.product();
272 
274  iSetup.get<TrackerDigiGeometryRecord>().get(hgeom);
275  geom_ = hgeom.product();
276 
277  edm::ESHandle<Propagator> hpropagator;
278  iSetup.get<TrackingComponentsRecord>().get(propagatorName_, hpropagator);
279  propagator_ = hpropagator.product();
280 
282  iSetup.get<TrackingComponentsRecord>().get(chi2EstimatorName_, hestimator);
283  chi2Estimator_ = hestimator.product();
284 
285  TSCPBuilderNoMaterial tscpBuilder;
286  auto out_duplicateCandidates = std::make_unique<std::vector<TrackCandidate>>();
287 
288  auto out_candidateMap = std::make_unique<CandidateToDuplicate>();
289  LogDebug("DuplicateTrackMerger") << "Number of tracks to be checked for merging: " << tracks.size();
290 
291 #ifdef EDM_ML_DEBUG
292  auto test = [&](const reco::Track *a, const reco::Track *b) {
293  const auto ev = iEvent.id().event();
294  const auto aOriAlgo = a->originalAlgo();
295  const auto bOriAlgo = b->originalAlgo();
296  const auto aSeed = a->seedRef().key();
297  const auto bSeed = b->seedRef().key();
298  return ((ev == 6903 && ((aOriAlgo == 23 && aSeed == 695 && bOriAlgo == 5 && bSeed == 652) ||
299  (aOriAlgo == 23 && aSeed == 400 && bOriAlgo == 7 && bSeed == 156) ||
300  (aOriAlgo == 4 && aSeed == 914 && bOriAlgo == 22 && bSeed == 503) ||
301  (aOriAlgo == 5 && aSeed == 809 && bOriAlgo == 4 && bSeed == 1030) ||
302  (aOriAlgo == 23 && aSeed == 749 && bOriAlgo == 5 && bSeed == 659) ||
303  (aOriAlgo == 4 && aSeed == 1053 && bOriAlgo == 23 && bSeed == 1035) ||
304  (aOriAlgo == 4 && aSeed == 810 && bOriAlgo == 5 && bSeed == 666) ||
305  (aOriAlgo == 4 && aSeed == 974 && bOriAlgo == 5 && bSeed == 778))) ||
306  (ev == 6904 && ((aOriAlgo == 23 && aSeed == 526 && bOriAlgo == 5 && bSeed == 307) ||
307  (aOriAlgo == 4 && aSeed == 559 && bOriAlgo == 22 && bSeed == 472))) ||
308  (ev == 6902 && ((aOriAlgo == 4 && aSeed == 750 && bOriAlgo == 22 && bSeed == 340) ||
309  (aOriAlgo == 4 && aSeed == 906 && bOriAlgo == 5 && bSeed == 609) ||
310  (aOriAlgo == 4 && aSeed == 724 && bOriAlgo == 5 && bSeed == 528) ||
311  (aOriAlgo == 4 && aSeed == 943 && bOriAlgo == 23 && bSeed == 739) ||
312  (aOriAlgo == 8 && aSeed == 2 && bOriAlgo == 9 && bSeed == 2282) ||
313  (aOriAlgo == 23 && aSeed == 827 && bOriAlgo == 5 && bSeed == 656) ||
314  (aOriAlgo == 22 && aSeed == 667 && bOriAlgo == 7 && bSeed == 516))));
315  };
316 #endif
317 
318  for(int i = 0; i < (int)tracks.size(); i++){
319  const reco::Track *rt1 = &tracks[i];
320 
321  if(rt1->innerMomentum().perp2() < minpT2_)continue;
322  // if(rt1->innerMomentum().R() < minP_)continue;
323  for(int j = i+1; j < (int)tracks.size();j++){
324  const reco::Track *rt2 = &tracks[j];
325 
326 #ifdef EDM_ML_DEBUG
327  debug_ = false;
328  if(test(rt1, rt2) || test(rt2, rt1)) {
329  debug_ = true;
330  LogTrace("DuplicateTrackMerger") << "Track1 " << i << " originalAlgo " << rt1->originalAlgo() << " seed " << rt1->seedRef().key() << " pT " << std::sqrt(rt1->innerMomentum().perp2()) << " charge " << rt1->charge() << " outerPosition2 " << rt1->outerPosition().perp2() << "\n"
331  << "Track2 " << j << " originalAlgo " << rt2->originalAlgo() << " seed " << rt2->seedRef().key() << " pT " << std::sqrt(rt2->innerMomentum().perp2()) << " charge " << rt2->charge() << " outerPosition2 " << rt2->outerPosition().perp2();
332  }
333 #endif
334 
335  if(rt1->charge() != rt2->charge())continue;
336  auto cosT = (*rt1).momentum().unit().Dot((*rt2).momentum().unit());
337  IfLogTrace(debug_, "DuplicateTrackMerger") << " cosT " << cosT;
338  if (cosT<0.) continue;
339  if(rt2->innerMomentum().perp2() < minpT2_)continue;
340  // if(rt2->innerMomentum().R() < minP_)continue;
341  const reco::Track* t1,*t2;
342  if(rt1->outerPosition().perp2() < rt2->outerPosition().perp2()){
343  t1 = rt1;
344  t2 = rt2;
345  }else{
346  t1 = rt2;
347  t2 = rt1;
348  }
349  auto deltaR3d2 = (t1->outerPosition() - t2->innerPosition()).mag2();
350 
351  if(t1->outerPosition().perp2() > t2->innerPosition().perp2()) deltaR3d2 *= -1.0;
352  IfLogTrace(debug_, "DuplicateTrackMerger") << " deltaR3d2 " << deltaR3d2 << " t1.outerPos2 " << t1->outerPosition().perp2() << " t2.innerPos2 " << t2->innerPosition().perp2();
353 
354  bool compatible = false;
355  DuplicateTrackType duplType;
356  if(deltaR3d2 >= minDeltaR3d2_) {
357  compatible = checkForDisjointTracks(t1, t2, tscpBuilder);
358  duplType = DuplicateTrackType::Disjoint;
359  }
360  else {
361  compatible = checkForOverlappingTracks(t1, t2, cosT);
363  }
364  if(!compatible) continue;
365 
366 
367  IfLogTrace(debug_, "DuplicateTrackMerger") << " marking as duplicates";
368  out_duplicateCandidates->push_back(merger_.merge(*t1,*t2, duplType));
369  out_candidateMap->emplace_back(i,j);
370 
371 #ifdef VI_STAT
372  ++stat.nCand;
373  // auto cosT = float((*t1).momentum().unit().Dot((*t2).momentum().unit()));
374  if (cosT>0) update_minimum(stat.maxCos,float(cosT));
375  else ++stat.nLoop0;
376 #endif
377 
378  }
379  }
380  iEvent.put(std::move(out_duplicateCandidates),"candidates");
381  iEvent.put(std::move(out_candidateMap),"candidateMap");
382 
383 
384 }
385 
386 
387  bool DuplicateTrackMerger::checkForDisjointTracks(const reco::Track *t1, const reco::Track *t2, TSCPBuilderNoMaterial& tscpBuilder) const {
388  IfLogTrace(debug_, "DuplicateTrackMerger") << " Checking for disjoint duplicates";
389 
390  FreeTrajectoryState fts1 = trajectoryStateTransform::outerFreeState(*t1, &*magfield_,false);
391  FreeTrajectoryState fts2 = trajectoryStateTransform::innerFreeState(*t2, &*magfield_,false);
392  GlobalPoint avgPoint((t1->outerPosition().x()+t2->innerPosition().x())*0.5,(t1->outerPosition().y()+t2->innerPosition().y())*0.5,(t1->outerPosition().z()+t2->innerPosition().z())*0.5);
393  TrajectoryStateClosestToPoint TSCP1 = tscpBuilder(fts1, avgPoint);
394  TrajectoryStateClosestToPoint TSCP2 = tscpBuilder(fts2, avgPoint);
395  IfLogTrace(debug_, "DuplicateTrackMerger") << " TSCP1.isValid " << TSCP1.isValid() << " TSCP2.isValid " << TSCP2.isValid();
396  if(!TSCP1.isValid()) return false;
397  if(!TSCP2.isValid()) return false;
398 
399  const FreeTrajectoryState ftsn1 = TSCP1.theState();
400  const FreeTrajectoryState ftsn2 = TSCP2.theState();
401 
402  IfLogTrace(debug_, "DuplicateTrackMerger") << " DCA2 " << (ftsn2.position()-ftsn1.position()).mag2();
403  if ( (ftsn2.position()-ftsn1.position()).mag2() > maxDCA2_ ) return false;
404 
405  auto qoverp1 = ftsn1.signedInverseMomentum();
406  auto qoverp2 = ftsn2.signedInverseMomentum();
407  float tmva_dqoverp_ = qoverp1-qoverp2;
408  IfLogTrace(debug_, "DuplicateTrackMerger") << " dqoverp " << tmva_dqoverp_;
409  if ( std::abs(tmva_dqoverp_) > maxDQoP_ ) return false;
410 
411 
412  //auto pp = [&](TrajectoryStateClosestToPoint const & ts) { std::cout << ' ' << ts.perigeeParameters().vector()[0] << '/' << ts.perigeeError().transverseCurvatureError();};
413  //if(qoverp1*qoverp2 <0) { std::cout << "charge different " << qoverp1 <<',' << qoverp2; pp(TSCP1); pp(TSCP2); std::cout << std::endl;}
414 
415  auto lambda1 = M_PI/2 - ftsn1.momentum().theta();
416  auto lambda2 = M_PI/2 - ftsn2.momentum().theta();
417  float tmva_dlambda_ = lambda1-lambda2;
418  IfLogTrace(debug_, "DuplicateTrackMerger") << " dlambda " << tmva_dlambda_;
419  if ( std::abs(tmva_dlambda_) > maxDLambda_ ) return false;
420 
421  auto phi1 = ftsn1.momentum().phi();
422  auto phi2 = ftsn2.momentum().phi();
423  float tmva_dphi_ = phi1-phi2;
424  if(std::abs(tmva_dphi_) > float(M_PI)) tmva_dphi_ = 2.f*float(M_PI) - std::abs(tmva_dphi_);
425  IfLogTrace(debug_, "DuplicateTrackMerger") << " dphi " << tmva_dphi_;
426  if (std::abs(tmva_dphi_) > maxDPhi_ ) return false;
427 
428  auto dxy1 = (-ftsn1.position().x() * ftsn1.momentum().y() + ftsn1.position().y() * ftsn1.momentum().x())/TSCP1.pt();
429  auto dxy2 = (-ftsn2.position().x() * ftsn2.momentum().y() + ftsn2.position().y() * ftsn2.momentum().x())/TSCP2.pt();
430  float tmva_ddxy_ = dxy1-dxy2;
431  IfLogTrace(debug_, "DuplicateTrackMerger") << " ddxy " << tmva_ddxy_;
432  if ( std::abs(tmva_ddxy_) > maxDdxy_ ) return false;
433 
434  auto dsz1 = ftsn1.position().z() * TSCP1.pt() / TSCP1.momentum().mag()
435  - (ftsn1.position().x() * ftsn1.momentum().y() + ftsn1.position().y() * ftsn1.momentum().x())/TSCP1.pt() * ftsn1.momentum().z()/ftsn1.momentum().mag();
436  auto dsz2 = ftsn2.position().z() * TSCP2.pt() / TSCP2.momentum().mag()
437  - (ftsn2.position().x() * ftsn2.momentum().y() + ftsn2.position().y() * ftsn2.momentum().x())/TSCP2.pt() * ftsn2.momentum().z()/ftsn2.momentum().mag();
438  float tmva_ddsz_ = dsz1-dsz2;
439  IfLogTrace(debug_, "DuplicateTrackMerger") << " ddsz " << tmva_ddsz_;
440  if ( std::abs(tmva_ddsz_) > maxDdsz_ ) return false;
441 
442  float tmva_d3dr_ = avgPoint.perp();
443  float tmva_d3dz_ = avgPoint.z();
444  float tmva_outer_nMissingInner_ = t2->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_INNER_HITS);
445  float tmva_inner_nMissingOuter_ = t1->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_OUTER_HITS);
446 
447  float gbrVals_[9];
448  gbrVals_[0] = tmva_ddsz_;
449  gbrVals_[1] = tmva_ddxy_;
450  gbrVals_[2] = tmva_dphi_;
451  gbrVals_[3] = tmva_dlambda_;
452  gbrVals_[4] = tmva_dqoverp_;
453  gbrVals_[5] = tmva_d3dr_;
454  gbrVals_[6] = tmva_d3dz_;
455  gbrVals_[7] = tmva_outer_nMissingInner_;
456  gbrVals_[8] = tmva_inner_nMissingOuter_;
457 
458  auto mvaBDTG = forest_->GetClassifier(gbrVals_);
459  IfLogTrace(debug_, "DuplicateTrackMerger") << " mvaBDTG " << mvaBDTG;
460  if(mvaBDTG < minBDTG_) return false;
461 
462  // std::cout << "to merge " << mvaBDTG << ' ' << std::copysign(std::sqrt(std::abs(deltaR3d2)),deltaR3d2) << ' ' << tmva_dphi_ << ' ' << TSCP1.pt() <<'/'<<TSCP2.pt() << std::endl;
463  return true;
464  }
465 
466  bool DuplicateTrackMerger::checkForOverlappingTracks(const reco::Track *t1, const reco::Track *t2, float cosT) const {
467  // ensure t1 is the shorter track
468  if(t2->numberOfValidHits() < t1->numberOfValidHits())
469  std::swap(t1, t2);
470 
471  IfLogTrace(debug_, "DuplicateTrackMerger") << " Checking for overlapping duplicates, cosT " << cosT << " t1 hits " << t1->numberOfValidHits();
472  if(cosT < overlapCheckMinCosT_) return false;
473  if(t1->numberOfValidHits() > overlapCheckMaxHits_) return false;
474 
475  // find the hit on the longer track on layer of the first hit of the shorter track
476  auto findHitOnT2 = [&](const TrackingRecHit *hit1) {
477  const auto hitDet = hit1->geographicalId().det();
478  const auto hitSubdet = hit1->geographicalId().subdetId();
479  const auto hitLayer = ttopo_->layer(hit1->geographicalId());
480  return std::find_if(t2->recHitsBegin(), t2->recHitsEnd(), [&](const TrackingRecHit *hit2) {
481  const auto& detId = hit2->geographicalId();
482  return (detId.det() == hitDet && detId.subdetId() == hitSubdet &&
483  ttopo_->layer(detId) == hitLayer);
484  });
485  };
486 
487  auto t1HitIter = t1->recHitsBegin();
488  if(!(*t1HitIter)->isValid()) {
489  IfLogTrace(debug_, "DuplicateTrackMerger") << " first t1 hit invalid";
490  return false;
491  }
492  auto t2HitIter = findHitOnT2(*t1HitIter);
493  if(t2HitIter == t2->recHitsEnd()) {
494  // if first hit not found, try with second
495  // if that fails, then reject
496  ++t1HitIter;
497  assert(t1HitIter != t1->recHitsEnd());
498 
499  if(!(*t1HitIter)->isValid()) {
500  IfLogTrace(debug_, "DuplicateTrackMerger") << " second t1 hit invalid";
501  return false;
502  }
503  t2HitIter = findHitOnT2(*t1HitIter);
504  if(t2HitIter == t2->recHitsEnd()) return false;
505  }
506  IfLogTrace(debug_, "DuplicateTrackMerger") << " starting overlap check from t1 hit " << std::distance(t1->recHitsBegin(), t1HitIter)
507  << " t2 hit " << std::distance(t2->recHitsBegin(), t2HitIter);
508 
509  auto prevSubdet = (*t1HitIter)->geographicalId().subdetId();
510  const TrajectoryStateOnSurface tsosInner = trajectoryStateTransform::innerStateOnSurface(*t2, *geom_, magfield_);
511 
512  ++t1HitIter; ++t2HitIter;
513  unsigned int missedLayers = 0;
514  while(t1HitIter != t1->recHitsEnd() && t2HitIter != t2->recHitsEnd()) {
515  // in case of invalid hits, reject immediately
516  if((*t1HitIter)->getType() != TrackingRecHit::valid || trackerHitRTTI::isUndef(**t1HitIter) ||
517  (*t2HitIter)->getType() != TrackingRecHit::valid || trackerHitRTTI::isUndef(**t2HitIter)) {
518  IfLogTrace(debug_, "DuplicateTrackMerger") << " t1 hit " << std::distance(t1->recHitsBegin(), t1HitIter)
519  << " t2 hit " << std::distance(t2->recHitsBegin(), t2HitIter)
520  << " either is invalid, types t1 " << (*t1HitIter)->getType() << " t2 " << (*t2HitIter)->getType();
521  return false;
522  }
523 
524  const auto& t1DetId = (*t1HitIter)->geographicalId();
525  const auto& t2DetId = (*t2HitIter)->geographicalId();
526 
527  const auto t1Det = t1DetId.det();
528  const auto t2Det = t2DetId.det();
529  if(t1Det != DetId::Tracker || t2Det != DetId::Tracker) {
530  IfLogTrace(debug_, "DuplicateTrackMerger") << " t1 hit " << std::distance(t1->recHitsBegin(), t1HitIter)
531  << " t2 hit " << std::distance(t2->recHitsBegin(), t2HitIter)
532  << " either not from Tracker, dets t1 " << t1Det << " t2 " << t2Det;
533  return false;
534  }
535 
536  const auto t1Subdet = t1DetId.subdetId();
537  const auto t1Layer = ttopo_->layer(t1DetId);
538 
539  // reject if hits have the same DetId but are different
540  if(t1DetId == t2DetId) {
541  if(!(*t1HitIter)->sharesInput(*t2HitIter, TrackingRecHit::all)) {
542  IfLogTrace(debug_, "DuplicateTrackMerger") << " t1 hit " << std::distance(t1->recHitsBegin(), t1HitIter)
543  << " t2 hit " << std::distance(t2->recHitsBegin(), t2HitIter)
544  << " same DetId (" << t1DetId.rawId() << ") but do not share all input";
545  return false;
546  }
547  }
548  else {
549  const auto t2Subdet = t2DetId.subdetId();
550  const auto t2Layer = ttopo_->layer(t2DetId);
551 
552  // reject if hits are on different layers
553  if(t1Subdet != t2Subdet || t1Layer != t2Layer) {
554  bool recovered = false;
555  // but try to recover first by checking if either one has skipped over a layer
556  if(t1Subdet == prevSubdet && t2Subdet != prevSubdet) {
557  // t1 has a layer t2 doesn't
558  ++t1HitIter;
559  recovered = true;
560  }
561  else if(t1Subdet != prevSubdet && t2Subdet == prevSubdet) {
562  // t2 has a layer t1 doesn't
563  ++t2HitIter;
564  recovered = true;
565  }
566  else if(t1Subdet == t2Subdet) {
567  prevSubdet = t1Subdet;
568  // same subdet, so layer must be different
569  if(t2Layer > t1Layer) {
570  // t1 has a layer t2 doesn't
571  ++t1HitIter;
572  recovered = true;
573  }
574  else if(t1Layer > t2Layer) {
575  // t2 has a layer t1 doesn't
576  ++t2HitIter;
577  recovered = true;
578  }
579  }
580  if(recovered) {
581  ++missedLayers;
582  if(missedLayers > overlapCheckMaxMissingLayers_) {
583  IfLogTrace(debug_, "DuplicateTrackMerger") << " max number of missed layers exceeded";
584  return false;
585  }
586  continue;
587  }
588 
589  IfLogTrace(debug_, "DuplicateTrackMerger") << " t1 hit " << std::distance(t1->recHitsBegin(), t1HitIter)
590  << " t2 hit " << std::distance(t2->recHitsBegin(), t2HitIter)
591  << " are on different layers (subdet, layer) t1 " << t1Subdet << "," << t1Layer
592  << " t2 " << t2Subdet << "," << t2Layer;
593  return false;
594  }
595  // reject if same layer (but not same hit) in non-pixel detector
596  else if(t1Subdet != PixelSubdetector::PixelBarrel && t1Subdet != PixelSubdetector::PixelEndcap) {
597  IfLogTrace(debug_, "DuplicateTrackMerger") << " t1 hit " << std::distance(t1->recHitsBegin(), t1HitIter)
598  << " t2 hit " << std::distance(t2->recHitsBegin(), t2HitIter)
599  << " are on same layer, but in non-pixel detector (det " << t1Det << " subdet " << t1Subdet << " layer " << t1Layer << ")";
600  return false;
601  }
602  }
603 
604  // Propagate longer track to the shorter track hit surface, check compatibility
605  TrajectoryStateOnSurface tsosPropagated = propagator_->propagate(tsosInner, (*t1HitIter)->det()->surface());
606  if(!tsosPropagated.isValid()) { // reject immediately if TSOS is not valid
607  IfLogTrace(debug_, "DuplicateTrackMerger") << " t1 hit " << std::distance(t1->recHitsBegin(), t1HitIter)
608  << " t2 hit " << std::distance(t2->recHitsBegin(), t2HitIter)
609  << " TSOS not valid";
610  return false;
611  }
612  auto passChi2Pair = chi2Estimator_->estimate(tsosPropagated, **t1HitIter);
613  if(!passChi2Pair.first) {
614  IfLogTrace(debug_, "DuplicateTrackMerger") << " t1 hit " << std::distance(t1->recHitsBegin(), t1HitIter)
615  << " t2 hit " << std::distance(t2->recHitsBegin(), t2HitIter)
616  << " hit chi2 compatibility failed with chi2 " << passChi2Pair.second;
617  return false;
618  }
619 
620  prevSubdet = t1Subdet;
621  ++t1HitIter; ++t2HitIter;
622  }
623  if(t1HitIter != t1->recHitsEnd()) {
624  IfLogTrace(debug_, "DuplicateTrackMerger") << " hits on t2 ended before hits on t1";
625  return false;
626  }
627 
628  IfLogTrace(debug_, "DuplicateTrackMerger") << " all hits on t2 are on layers whre t1 has also a hit";
629  return true;
630  }
631 }
632 
635 
#define LogDebug(id)
const edm::RefToBase< TrajectorySeed > & seedRef() const
Definition: Track.h:213
T getParameter(std::string const &) const
EventNumber_t event() const
Definition: EventID.h:41
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:122
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:457
const FreeTrajectoryState & theState() const
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:17
Geom::Phi< T > phi() const
Definition: PV3DBase.h:69
static void fillDescriptions(ConfigurationDescriptions &descriptions)
T y() const
Definition: PV3DBase.h:63
#define noexcept
bool ev
#define IfLogTrace(cond, cat)
#define nullptr
const math::XYZPoint & outerPosition() const
position of the outermost hit
Definition: Track.h:65
DuplicateTrackType
Geom::Theta< T > theta() const
Definition: PV3DBase.h:75
const math::XYZPoint & innerPosition() const
position of the innermost hit
Definition: Track.h:55
int iEvent
Definition: GenABIO.cc:230
const SurfaceType & surface() const
T mag() const
Definition: PV3DBase.h:67
auto const T2 &decltype(t1.eta()) t2
Definition: deltaR.h:16
size_t key() const
Definition: RefToBase.h:250
void swap(edm::DataFrameContainer &lhs, edm::DataFrameContainer &rhs)
T sqrt(T t)
Definition: SSEVec.h:18
T z() const
Definition: PV3DBase.h:64
T mag2() const
The vector magnitude squared. Equivalent to vec.dot(vec)
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
unsigned short numberOfValidHits() const
number of valid hits found
Definition: TrackBase.h:815
Definition: value.py:1
trackingRecHit_iterator recHitsBegin() const
Iterator to first hit on the track.
Definition: Track.h:104
ParameterDescriptionBase * add(U const &iLabel, T const &value)
GlobalVector momentum() const
#define LogTrace(id)
#define M_PI
GlobalPoint position() const
TrackAlgorithm originalAlgo() const
Definition: TrackBase.h:496
const HitPattern & hitPattern() const
Access the hit pattern, indicating in which Tracker layers the track has hits.
Definition: TrackBase.h:445
const T & get() const
Definition: EventSetup.h:56
double b
Definition: hdecay.h:120
int numberOfLostHits(HitCategory category) const
Definition: HitPattern.h:902
edm::EventID id() const
Definition: EventBase.h:58
fixed size matrix
const math::XYZVector & innerMomentum() const
momentum vector at the innermost hit position
Definition: Track.h:60
double a
Definition: hdecay.h:121
bool isUndef(TrackingRecHit const &hit)
int charge() const
track electric charge
Definition: TrackBase.h:562
FreeTrajectoryState innerFreeState(const reco::Track &tk, const MagneticField *field, bool withErr=true)
long double T
T x() const
Definition: PV3DBase.h:62
FreeTrajectoryState outerFreeState(const reco::Track &tk, const MagneticField *field, bool withErr=true)
double signedInverseMomentum() const
T const * product() const
Definition: ESHandle.h:86
def move(src, dest)
Definition: eostools.py:510
TrajectoryStateOnSurface innerStateOnSurface(const reco::Track &tk, const TrackingGeometry &geom, const MagneticField *field, bool withErr=true)
trackingRecHit_iterator recHitsEnd() const
Iterator to last hit on the track.
Definition: Track.h:109