CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
TrackCollectionMerger.cc
Go to the documentation of this file.
2 
3 
6 
11 
20 
21 
22 #include<vector>
23 #include<memory>
24 #include<cassert>
25 namespace {
26  class TrackCollectionMerger final : public edm::global::EDProducer<> {
27  public:
28  explicit TrackCollectionMerger(const edm::ParameterSet& conf) :
29  collectionCloner(*this, conf, true),
30  m_foundHitBonus(conf.getParameter<double>("foundHitBonus")),
31  m_lostHitPenalty(conf.getParameter<double>("lostHitPenalty")),
32  m_shareFrac(conf.getParameter<double>("shareFrac")),
33  m_minShareHits(conf.getParameter<unsigned int>("minShareHits")),
34  m_minQuality(reco::TrackBase::qualityByName(conf.getParameter<std::string>("minQuality"))),
35  m_allowFirstHitShare(conf.getParameter<bool>("allowFirstHitShare"))
36 {
37  for (auto const & it : conf.getParameter<std::vector<edm::InputTag> >("trackProducers") )
38  srcColls.emplace_back(it,consumesCollector());
39  for (auto const & it : conf.getParameter<std::vector<std::string> >("inputClassifiers")) {
40  srcMVAs.push_back(consumes<MVACollection>(edm::InputTag(it,"MVAValues")));
41  srcQuals.push_back(consumes<QualityMaskCollection>(edm::InputTag(it,"QualityMasks")));
42  }
43 
44  assert(srcColls.size()==srcQuals.size());
45 
46 
47  produces<MVACollection>("MVAValues");
48  produces<QualityMaskCollection>("QualityMasks");
49 
50  }
51 
52  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
54  desc.add<std::vector<edm::InputTag> >("trackProducers",std::vector<edm::InputTag>());
55  desc.add<std::vector<std::string> >("inputClassifiers",std::vector<std::string>());
56  desc.add<double>("shareFrac",.19);
57  desc.add<double>("foundHitBonus",10.);
58  desc.add<double>("lostHitPenalty",5.);
59  desc.add<unsigned int>("minShareHits",2);
60  desc.add<bool>("allowFirstHitShare",true);
61  desc.add<std::string>("minQuality","loose");
62  descriptions.add("TrackCollectionMerger", desc);
63  }
64 
65  private:
66 
67 
68  TrackCollectionCloner collectionCloner;
69  std::vector<TrackCollectionCloner::Tokens> srcColls;
70 
71  using MVACollection = std::vector<float>;
72  using QualityMaskCollection = std::vector<unsigned char>;
73 
74  using IHit = std::pair<unsigned int, TrackingRecHit const *>;
75  using IHitV = std::vector<IHit>;
76 
77  std::vector<edm::EDGetTokenT<MVACollection>> srcMVAs;
78  std::vector<edm::EDGetTokenT<QualityMaskCollection>> srcQuals;
79 
80 
81  float m_foundHitBonus;
82  float m_lostHitPenalty;
83  float m_shareFrac;
84  unsigned int m_minShareHits;
85  reco::TrackBase::TrackQuality m_minQuality;
86  bool m_allowFirstHitShare;
87 
88  virtual void produce(edm::StreamID, edm::Event& evt, const edm::EventSetup&) const override;
89 
90 
91  bool areDuplicate(IHitV const& rh1, IHitV const& rh2) const;
92 
93 
94  };
95 
96 }
97 
99 
100 
101 namespace {
102 
103  void TrackCollectionMerger::produce(edm::StreamID, edm::Event& evt, const edm::EventSetup&) const {
104 
105  TrackCollectionCloner::Producer producer(evt, collectionCloner);
106 
107  // load collections
108  auto collsSize = srcColls.size();
109  auto rSize=0U;
110  declareDynArray(reco::TrackCollection const *, collsSize, trackColls);
111  for (auto i=0U; i< collsSize; ++i) {
112  trackColls[i] = &srcColls[i].tracks(evt);
113  rSize += (*trackColls[i]).size();
114  }
115 
116 
117  unsigned char qualMask = ~0;
118  if (m_minQuality!=reco::TrackBase::undefQuality) qualMask = 1<<m_minQuality;
119 
120 
121  // load tracks
122  initDynArray(unsigned int,collsSize,nGoods,0);
123  declareDynArray(float,rSize, mvas);
124  declareDynArray(unsigned char,rSize, quals);
125  declareDynArray(unsigned int,rSize, tkInds);
126  auto k=0U;
127  for (auto i=0U; i< collsSize; ++i) {
128  auto const & tkColl = *trackColls[i];
129  auto size = tkColl.size();
131  evt.getByToken(srcMVAs[i], hmva);
132  assert((*hmva).size()==size);
134  evt.getByToken(srcQuals[i], hqual);
135  for (auto j=0U; j<size; ++j) {
136  if (! (qualMask&(* hqual)[j]) ) continue;
137  mvas[k]=(*hmva)[j];
138  quals[k] = (*hqual)[j];
139  tkInds[k]=j;
140  ++k;
141  ++nGoods[i];
142  }
143  }
144 
145  auto ntotTk=k;
146  std::vector<bool> selected(ntotTk,true);
147 
150  declareDynArray(reco::TrackBase::AlgoMask, ntotTk, algoMask);
151 
152 
153  // merge (if more than one collection...)
154 
155  auto merger = [&]()->void {
156 
157  // load hits and score
158  declareDynArray(float,ntotTk,score);
159  declareDynArray(IHitV, ntotTk, rh1);
160 
161  k=0U;
162  for (auto i=0U; i< collsSize; ++i) {
163  auto const & tkColl = *trackColls[i];
164  for (auto j=0U; j< nGoods[i]; ++j) {
165  auto const & track = tkColl[tkInds[k]];
166  algo[k] = track.algo();
167  oriAlgo[k] = track.originalAlgo();
168  algoMask[k] = track.algoMask();
169 
170  auto validHits=track.numberOfValidHits();
171  auto validPixelHits=track.hitPattern().numberOfValidPixelHits();
172  auto lostHits=track.numberOfLostHits();
173  score[k] = m_foundHitBonus*validPixelHits+m_foundHitBonus*validHits - m_lostHitPenalty*lostHits - track.chi2();
174 
175  auto & rhv = rh1[k];
176  rhv.reserve(validHits) ;
177  auto compById = [](IHit const & h1, IHit const & h2) {return h1.first < h2.first;};
178  for (auto it = track.recHitsBegin(); it != track.recHitsEnd(); ++it) {
179  auto const & hit = *(*it);
180  auto id = hit.rawId() ;
181  if(hit.geographicalId().subdetId()>2) id &= (~3); // mask mono/stereo in strips...
182  if likely(hit.isValid()) { rhv.emplace_back(id,&hit); std::push_heap(rhv.begin(),rhv.end(),compById); }
183  }
184  std::sort_heap(rhv.begin(),rhv.end(),compById);
185 
186 
187  ++k;
188  }
189  }
190  assert(ntotTk==k);
191 
192  auto seti = [&](unsigned int ii, unsigned int jj) {
193  selected[jj]=false;
194  selected[ii]=true;
195  if (trackAlgoPriorityOrder[oriAlgo[jj]] < trackAlgoPriorityOrder[oriAlgo[ii]]) oriAlgo[ii] = oriAlgo[jj];
196  algoMask[ii] |= algoMask[jj];
197  quals[ii] |= (1<<reco::TrackBase::confirmed);
198  algoMask[jj] = algoMask[ii]; // in case we keep discarded
199  quals[jj] |= (1<<reco::TrackBase::discarded);
200  };
201 
202 
203 
204  auto iStart2=0U;
205  for (auto i=0U; i<collsSize-1; ++i) {
206  auto iStart1=iStart2;
207  iStart2=iStart1+nGoods[i];
208  for (auto t1=iStart1; t1<iStart2; ++t1) {
209  if (!selected[t1]) continue;
210  auto score1 = score[t1];
211  for (auto t2=iStart2; t2 <ntotTk; ++t2) {
212  if (!selected[t1]) break;
213  if (!selected[t2]) continue;
214  if (!areDuplicate(rh1[t1],rh1[t2])) continue;
215  auto score2 = score[t2];
216  constexpr float almostSame = 0.01f; // difference rather than ratio due to possible negative values for score
217 
218  if ( score1 - score2 > almostSame ) {
219  seti(t1,t2);
220  } else if ( score2 - score1 > almostSame ) {
221  seti(t2,t1);
222  } else { // take best
224  if ( (quals[t1]&qmask) == (quals[t2]&qmask) ) {
225  // take first
227  seti(t1,t2);
228  } else {
229  seti(t2,t1);
230  }
231  } else if ( (quals[t1]&qmask) > (quals[t2]&qmask) )
232  seti(t1,t2);
233  else
234  seti(t2,t1);
235  } // end ifs...
236 
237  } // end t2
238  } // end t1
239  } // end colls
240  }; // end merger;
241 
242 
243  if (collsSize>1) merger();
244 
245  // products
246  auto pmvas = std::make_unique<MVACollection>();
247  auto pquals = std::make_unique<QualityMaskCollection>();
248 
249  // clone selected tracks...
250  auto nsel=0U;
251  auto iStart2=0U;
252  auto isel=0U;
253  for (auto i=0U; i<collsSize; ++i) {
254  std::vector<unsigned int> selId;
255  std::vector<unsigned int> tid;
256  auto iStart1=iStart2;
257  iStart2=iStart1+nGoods[i];
258  assert(producer.selTracks_->size()==isel);
259  for (auto t1=iStart1; t1<iStart2; ++t1) {
260  if (!selected[t1]) continue;
261  ++nsel;
262  tid.push_back(t1);
263  selId.push_back(tkInds[t1]);
264  pmvas->push_back(mvas[t1]);
265  pquals->push_back(quals[t1]);
266  }
267  producer(srcColls[i],selId);
268  assert(producer.selTracks_->size()==nsel);
269  assert(tid.size()==nsel-isel);
270  auto k=0U;
271  for (;isel<nsel;++isel) {
272  auto & otk = (*producer.selTracks_)[isel];
273  otk.setQualityMask((*pquals)[isel]);
274  otk.setOriginalAlgorithm(oriAlgo[tid[k]]);
275  otk.setAlgoMask(algoMask[tid[k++]]);
276  }
277  assert(tid.size()==k);
278  }
279 
280  assert(producer.selTracks_->size()==pmvas->size());
281 
282  evt.put(std::move(pmvas),"MVAValues");
283  evt.put(std::move(pquals),"QualityMasks");
284 
285 
286  }
287 
288 
289 
290  bool TrackCollectionMerger::areDuplicate(IHitV const& rh1, IHitV const& rh2) const {
291  auto nh1=rh1.size();
292  auto nh2=rh2.size();
293 
294 
295  auto share = // use_sharesInput_ ?
296  [](const TrackingRecHit* it,const TrackingRecHit* jt)->bool { return it->sharesInput(jt,TrackingRecHit::some); };
297  //:
298  // [](const TrackingRecHit* it,const TrackingRecHit* jt)->bool {
299  // float delta = std::abs ( it->localPosition().x()-jt->localPosition().x() );
300  // return (it->geographicalId()==jt->geographicalId())&&(delta<epsilon_);
301  // };
302 
303 
304  //loop over rechits
305  int noverlap=0;
306  int firstoverlap=0;
307  // check first hit (should use REAL first hit?)
308  if unlikely(m_allowFirstHitShare && rh1[0].first==rh2[0].first ) {
309  if (share( rh1[0].second, rh2[0].second)) firstoverlap=1;
310  }
311 
312  // exploit sorting
313  unsigned int jh=0;
314  unsigned int ih=0;
315  while (ih!=nh1 && jh!=nh2) {
316  // break if not enough to go...
317  // if ( nprecut-noverlap+firstoverlap > int(nh1-ih)) break;
318  // if ( nprecut-noverlap+firstoverlap > int(nh2-jh)) break;
319  auto const id1 = rh1[ih].first;
320  auto const id2 = rh2[jh].first;
321  if (id1<id2) ++ih;
322  else if (id2<id1) ++jh;
323  else {
324  // in case of split-hit do full conbinatorics
325  auto li=ih; while( (++li)!=nh1 && id1 == rh1[li].first);
326  auto lj=jh; while( (++lj)!=nh2 && id2 == rh2[lj].first);
327  for (auto ii=ih; ii!=li; ++ii)
328  for (auto jj=jh; jj!=lj; ++jj) {
329  if (share( rh1[ii].second, rh2[jj].second)) noverlap++;
330  }
331  jh=lj; ih=li;
332  } // equal ids
333 
334  } //loop over ih & jh
335 
336  return noverlap >= int(m_minShareHits) &&
337  (noverlap-firstoverlap) > (std::min(nh1,nh2)-firstoverlap)*m_shareFrac;
338 
339  }
340 
341 
342 }
343 
344 
347 
348 DEFINE_FWK_MODULE(TrackCollectionMerger);
T getParameter(std::string const &) const
int i
Definition: DBlmapReader.cc:9
#define initDynArray(T, n, x, i)
Definition: DynArray.h:29
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:464
TrackQuality
track quality
Definition: TrackBase.h:149
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:17
assert(m_qm.get())
std::vector< Track > TrackCollection
collection of Tracks
Definition: TrackFwd.h:14
virtual bool sharesInput(const TrackingRecHit *other, SharedInputType what) const
int ii
Definition: cuy.py:588
#define constexpr
TrackAlgorithm
track algorithm
Definition: TrackBase.h:99
#define unlikely(x)
U second(std::pair< T, U > const &p)
#define likely(x)
OrphanHandle< PROD > put(std::auto_ptr< PROD > product)
Put a new product.
Definition: Event.h:120
ConsumesCollector consumesCollector()
Use a ConsumesCollector to gather consumes information from helper functions.
def move
Definition: eostools.py:510
int j
Definition: DBlmapReader.cc:9
T min(T a, T b)
Definition: MathUtil.h:58
ParameterDescriptionBase * add(U const &iLabel, T const &value)
static void fillDescriptions(ConfigurationDescriptions &descriptions)
tuple conf
Definition: dbtoconf.py:185
std::bitset< algoSize > AlgoMask
algo mask
Definition: TrackBase.h:143
virtual void produce(StreamID, Event &, EventSetup const &) const =0
std::array< unsigned int, reco::TrackBase::algoSize > trackAlgoPriorityOrder
#define declareDynArray(T, n, x)
Definition: DynArray.h:28
tuple size
Write out results.