Belle II Software  release-05-02-19
CDCTriggerRecoMatcherModule.cc
1 #include "trg/cdc/modules/mcmatcher/CDCTriggerRecoMatcherModule.h"
2 
3 #include <cdc/dataobjects/CDCHit.h>
4 
5 #include <Eigen/Dense>
6 
7 namespace {
8  //small anonymous helper construct making converting a pair of iterators usable
9  //with range based for
10  template<class Iter>
11  struct iter_pair_range : std::pair<Iter, Iter> {
12  iter_pair_range(std::pair<Iter, Iter> const& x) : std::pair<Iter, Iter>(x) {}
13  Iter begin() const {return this->first;}
14  Iter end() const {return this->second;}
15  };
16 
17  template<class Iter>
18  inline iter_pair_range<Iter> as_range(std::pair<Iter, Iter> const& x)
19  {
20  return iter_pair_range<Iter>(x);
21  }
22 
23  typedef int HitId;
24  typedef int TrackId;
25  typedef float Purity;
26  typedef float Efficiency;
27 }
28 
29 
30 
31 using namespace Belle2;
32 using namespace std;
33 
34 //this line registers the module with the framework and actually makes it available
35 //in steering files or the the module list (basf2 -m).
36 REG_MODULE(CDCTriggerRecoMatcher)
37 
39 {
40  setDescription("A module to match CDCTriggerTracks to RecoTracks.\n"
41  "First makes relations from RecoTracks to CDCTriggerSegmentHits, "
42  "then makes relations from RecoTracks to CDCTriggerTracks "
43  "and vice-versa.");
44  setPropertyFlags(c_ParallelProcessingCertified);
45 
46  addParam("RecoTrackCollectionName", m_RecoTrackCollectionName,
47  "Name of the RecoTrack StoreArray to be matched.",
48  string("RecoTracks"));
49  addParam("TrgTrackCollectionName", m_TrgTrackCollectionName,
50  "Name of the CDCTriggerTrack StoreArray to be matched.",
51  string("TRGCDC2DFinderTracks"));
52  addParam("hitCollectionName", m_hitCollectionName,
53  "Name of the StoreArray of CDCTriggerSegmentHits used for the matching.",
54  string(""));
55  addParam("axialOnly", m_axialOnly,
56  "Switch to ignore stereo hits (= 2D matching).",
57  false);
58  addParam("minPurity", m_minPurity,
59  "Minimum purity for reconstructed tracks.",
60  0.1);
61  addParam("minEfficiency", m_minEfficiency,
62  "Minimum efficiency for MC tracks.",
63  0.1);
64  addParam("relateClonesAndMerged", m_relateClonesAndMerged,
65  "If true, create relations for clones and merged tracks "
66  "(will get negative weight).",
67  true);
68  addParam("relateHitsByID", m_relateHitsByID,
69  "If true, compare ID of CDCTriggerSegmentHits and CDCHits "
70  "to create relations, otherwise use only existing relations.",
71  true);
72 }
73 
74 
75 void
77 {
78  m_segmentHits.isRequired(m_hitCollectionName);
79  m_trgTracks.isRequired(m_TrgTrackCollectionName);
80  m_recoTracks.isRequired(m_RecoTrackCollectionName);
81 
82  m_trgTracks.requireRelationTo(m_segmentHits);
83  m_recoTracks.registerRelationTo(m_segmentHits);
84  m_recoTracks.registerRelationTo(m_trgTracks);
85  m_trgTracks.registerRelationTo(m_recoTracks);
86 }
87 
88 
89 void
91 {
92  // create relations from RecoTracks to SegmentHits via CDCHits
93  for (int ireco = 0; ireco < m_recoTracks.getEntries(); ++ireco) {
94  RecoTrack* recoTrack = m_recoTracks[ireco];
95  // if relations exist already, skip this step
96  // (matching may be done several times with different trigger tracks)
97  if (recoTrack->getRelationsTo<CDCTriggerSegmentHit>(m_hitCollectionName).size() > 0)
98  continue;
99  vector<CDCHit*> cdcHits = recoTrack->getCDCHitList();
100  for (unsigned iHit = 0; iHit < cdcHits.size(); ++iHit) {
101  if (m_relateHitsByID) {
102  // loop over TS hits and compare ID
103  for (CDCTriggerSegmentHit& tsHit : m_segmentHits) {
104  if (tsHit.getID() == cdcHits[iHit]->getID()) {
105  recoTrack->addRelationTo(&tsHit);
106  }
107  }
108  } else {
109  // look for relations between CDC hits and TS hits
111  cdcHits[iHit]->getRelationsFrom<CDCTriggerSegmentHit>(m_hitCollectionName);
112  for (unsigned iTS = 0; iTS < relHits.size(); ++iTS) {
113  // create relations only for priority hits (relation weight 2)
114  if (relHits.weight(iTS) > 1)
115  recoTrack->addRelationTo(relHits[iTS]);
116  }
117  }
118  }
119  }
120 
121  // derive relations between trigger tracks and reco tracks,
122  // following the basic ideas of the MCMatcherTracksModule (tracking)
123 
124  B2DEBUG(100, "########## start matching ############");
125 
126  int nRecoTracks = m_recoTracks.getEntries();
127  int nTrgTracks = m_trgTracks.getEntries();
128 
129  B2DEBUG(100, "Number of trigger tracks is " << nTrgTracks);
130  B2DEBUG(100, "Number of reco tracks is " << nRecoTracks);
131 
132  if (not nRecoTracks or not nTrgTracks) {
133  // Either no trigger tracks
134  // or no reco tracks are present in this event
135  // Cannot perform matching.
136  return;
137  }
138 
139  //### Build a hit_id to track map for easier lookup later ###
140  std::multimap<HitId, TrackId> recoTrackId_by_hitId;
141  {
142  std::multimap<HitId, TrackId>::iterator itRecoInsertHit = recoTrackId_by_hitId.end();
143  TrackId recoTrackId = -1;
144  for (const RecoTrack& recoTrack : m_recoTracks) {
145  ++recoTrackId;
147  recoTrack.getRelationsTo<CDCTriggerSegmentHit>(m_hitCollectionName);
148  for (unsigned iHit = 0; iHit < relHits.size(); ++iHit) {
149  const HitId hitId = relHits[iHit]->getArrayIndex();
150  itRecoInsertHit = recoTrackId_by_hitId.insert(itRecoInsertHit,
151  make_pair(hitId, recoTrackId));
152  B2DEBUG(250, "hitId " << hitId << " in SL " << relHits[iHit]->getISuperLayer()
153  << ", recoTrackId " << recoTrackId);
154  }
155  }
156  }
157 
158  //### Build a hit_id to track map for easier lookup later ###
159  std::multimap<HitId, TrackId> trgTrackId_by_hitId;
160  {
161  std::multimap<HitId, TrackId>::iterator itTrgInsertHit = trgTrackId_by_hitId.end();
162  TrackId trgTrackId = -1;
163  for (const CDCTriggerTrack& trgTrack : m_trgTracks) {
164  ++trgTrackId;
166  trgTrack.getRelationsTo<CDCTriggerSegmentHit>(m_hitCollectionName);
167  for (unsigned int iHit = 0; iHit < relHits.size(); ++iHit) {
168  const HitId hitId = relHits[iHit]->getArrayIndex();
169  itTrgInsertHit = trgTrackId_by_hitId.insert(itTrgInsertHit,
170  make_pair(hitId, trgTrackId));
171  B2DEBUG(250, "hitId " << hitId << " in SL " << relHits[iHit]->getISuperLayer()
172  << ", trgTrackId " << trgTrackId);
173  }
174  }
175  }
176 
177  //### Build the confusion matrix ###
178 
179  // Reserve enough space for the confusion matrix
180  // In contrast to MC matching, background hits are not counted separately
181  Eigen::MatrixXi confusionMatrix = Eigen::MatrixXi::Zero(nTrgTracks, nRecoTracks);
182 
183  // Count total number of hits for each track separately
184  // to avoid double counting (in case tracks share hits)
185  Eigen::RowVectorXi totalHits_by_recoTrackId = Eigen::RowVectorXi::Zero(nRecoTracks);
186  Eigen::VectorXi totalHits_by_trgTrackId = Eigen::VectorXi::Zero(nTrgTracks);
187 
188  // examine every hit to which recoTrack and trgTrack it belongs.
189  for (HitId hitId = 0; hitId < m_segmentHits.getEntries(); ++hitId) {
190  // skip stereo hits
191  if (m_axialOnly && m_segmentHits[hitId]->getISuperLayer() % 2) continue;
192 
193  // Seek all recoTracks and trgTracks
194  auto range_trgTrackIds = trgTrackId_by_hitId.equal_range(hitId);
195  auto range_recoTrackIds = recoTrackId_by_hitId.equal_range(hitId);
196 
197  // Assign the hits to the total vector
198  for (const pair<HitId, TrackId>& hitId_and_trgTrackId :
199  as_range(range_trgTrackIds)) {
200  TrackId trgTrackId = hitId_and_trgTrackId.second;
201  totalHits_by_trgTrackId(trgTrackId) += 1;
202  B2DEBUG(200, " trgTrackId for total count: " << trgTrackId);
203  }
204  for (const pair<HitId, TrackId>& hitId_and_recoTrackId :
205  as_range(range_recoTrackIds)) {
206  TrackId recoTrackId = hitId_and_recoTrackId.second;
207  totalHits_by_recoTrackId(recoTrackId) += 1;
208  B2DEBUG(200, " recoTrackId for total count: " << recoTrackId);
209  }
210 
211  // Count matrix entries for all combinations
212  for (const pair<HitId, TrackId>& hitId_and_recoTrackId :
213  as_range(range_recoTrackIds)) {
214  for (const pair<HitId, TrackId>& hitId_and_trgTrackId :
215  as_range(range_trgTrackIds)) {
216  TrackId recoTrackId = hitId_and_recoTrackId.second;
217  TrackId trgTrackId = hitId_and_trgTrackId.second;
218  confusionMatrix(trgTrackId, recoTrackId) += 1;
219  B2DEBUG(200, " trgTrackId : " << trgTrackId << "; recoTrackId : " << recoTrackId);
220  }
221  }
222  } //end for hitId
223 
224  B2DEBUG(200, "Confusion matrix of the event : " << endl << confusionMatrix);
225 
226  B2DEBUG(200, "totalHits_by_trgTrackId : " << endl << totalHits_by_trgTrackId);
227  B2DEBUG(200, "totalHits_by_recoTrackId : " << endl << totalHits_by_recoTrackId);
228 
229  // ### Building the trg track to highest purity reco track relation ###
230  vector<pair<TrackId, Purity>> purestRecoTrackId_by_trgTrackId(nTrgTracks);
231 
232  for (TrackId trgTrackId = 0; trgTrackId < nTrgTracks; ++trgTrackId) {
233  Eigen::RowVectorXi trgTrackRow = confusionMatrix.row(trgTrackId);
234  Eigen::RowVectorXi::Index purestRecoTrackId;
235 
236  //Also sets the index of the highest entry in the row vector
237  int highestHits = trgTrackRow.maxCoeff(&purestRecoTrackId);
238  int totalHits = totalHits_by_trgTrackId(trgTrackId);
239 
240  Purity highestPurity = Purity(highestHits) / totalHits;
241 
242  purestRecoTrackId_by_trgTrackId[trgTrackId] =
243  pair<TrackId, Purity>(purestRecoTrackId, highestPurity);
244  }
245 
246  // Log the trg track to highest purity reco track
247  // relation to debug output
248  {
249  TrackId trgTrackId = -1;
250  B2DEBUG(200, "TrgTrack to highest purity RecoTrack relation");
251  for (const pair< TrackId, Purity>& purestRecoTrackId :
252  purestRecoTrackId_by_trgTrackId) {
253  ++trgTrackId;
254  const Purity& purity = purestRecoTrackId.second;
255  const TrackId& recoTrackId = purestRecoTrackId.first;
256  B2DEBUG(200, "trgTrackId : " << trgTrackId << " -> recoTrackId : " << recoTrackId
257  << " with purity " << purity);
258  }
259  }
260 
261  // ### Building the reco track to highest efficiency trg track relation ###
262  vector<pair<TrackId, Efficiency>> mostEfficientTrgTrackId_by_recoTrackId(nRecoTracks);
263 
264  for (TrackId recoTrackId = 0; recoTrackId < nRecoTracks; ++recoTrackId) {
265  Eigen::VectorXi recoTrackCol = confusionMatrix.col(recoTrackId);
266  Eigen::VectorXi::Index highestHitsTrgTrackId;
267 
268  //Also sets the index of the highest entry in the column vector
269  int highestHits = recoTrackCol.maxCoeff(&highestHitsTrgTrackId);
270  int totalHits = totalHits_by_recoTrackId(recoTrackId);
271 
272  Efficiency highestEfficiency = Efficiency(highestHits) / totalHits;
273 
274  mostEfficientTrgTrackId_by_recoTrackId[recoTrackId] =
275  pair<TrackId, Efficiency> (highestHitsTrgTrackId, highestEfficiency);
276  }
277 
278  // Log the reco track to highest efficiency trg track
279  // relation to debug output
280  {
281  TrackId recoTrackId = -1;
282  B2DEBUG(200, "RecoTrack to highest efficiency TrgTrack relation");
283  for (const pair<TrackId, Efficiency>& mostEfficientTrgTrackId :
284  mostEfficientTrgTrackId_by_recoTrackId) {
285  ++recoTrackId;
286  const Efficiency& efficiency = mostEfficientTrgTrackId.second;
287  const TrackId& trgTrackId = mostEfficientTrgTrackId.first;
288  B2DEBUG(200, "recoTrackId : " << recoTrackId << " -> trgTrackId : " << trgTrackId
289  << " with efficiency " << efficiency);
290  }
291  }
292 
293  // ### Classify the trg tracks ###
294  for (TrackId trgTrackId = 0; trgTrackId < nTrgTracks; ++trgTrackId) {
295  CDCTriggerTrack* trgTrack = m_trgTracks[trgTrackId];
296 
297  const pair<TrackId, Purity>& purestRecoTrackId = purestRecoTrackId_by_trgTrackId[trgTrackId];
298  const TrackId& recoTrackId = purestRecoTrackId.first;
299  const Purity& purity = purestRecoTrackId.second;
300 
301  if (!(purity >= m_minPurity)) {
302  // GHOST
303  B2DEBUG(100, "Classified TrgTrack " << trgTrackId << " as ghost because of too low purity.");
304  } else {
305  // check whether the highest purity reco track has in turn
306  // the highest efficiency trg track equal to this track.
307  RecoTrack* recoTrack = m_recoTracks[recoTrackId];
308 
309  const pair<TrackId, Efficiency>& mostEfficientTrgTrackId =
310  mostEfficientTrgTrackId_by_recoTrackId[recoTrackId];
311 
312  const TrackId& trgTrackIdCompare = mostEfficientTrgTrackId.first;
313 
314  if (trgTrackId != trgTrackIdCompare) {
315  // CLONE
316  if (m_relateClonesAndMerged) {
317  // Add the reco track matching relation with negative weight
318  trgTrack->addRelationTo(recoTrack, -purity);
319  }
320  B2DEBUG(100, "Classified TrgTrack " << trgTrackId << " as clone -> recoTrackId "
321  << recoTrackId << " : " << -purity);
322  } else {
323  // MATCHED
324  //Add the reco track matching relation
325  trgTrack->addRelationTo(recoTrack, purity);
326  B2DEBUG(100, "Classified TrgTrack " << trgTrackId << " as match -> recoTrackId "
327  << recoTrackId << " : " << purity);
328  }
329  }
330  }
331 
332  // ### Classify the reco tracks ###
333  for (TrackId recoTrackId = 0; recoTrackId < nRecoTracks; ++recoTrackId) {
334  RecoTrack* recoTrack = m_recoTracks[recoTrackId];
335 
336  const pair<TrackId, Efficiency>& mostEfficiencyTrgTrackId =
337  mostEfficientTrgTrackId_by_recoTrackId[recoTrackId];
338  const TrackId& trgTrackId = mostEfficiencyTrgTrackId.first;
339  const Efficiency& efficiency = mostEfficiencyTrgTrackId.second;
340 
341  if (!(efficiency >= m_minEfficiency)) {
342  // MISSING
343  B2DEBUG(100, "Classified RecoTrack " << recoTrackId << " as missing.");
344  } else {
345  // check whether the highest efficiency trg track has in turn
346  // the highest purity reco track equal to this track.
347  CDCTriggerTrack* trgTrack = m_trgTracks[trgTrackId];
348 
349  const pair<TrackId, Purity>& purestRecoTrackId =
350  purestRecoTrackId_by_trgTrackId[trgTrackId];
351  const TrackId& recoTrackIdCompare = purestRecoTrackId.first;
352 
353  if (recoTrackId != recoTrackIdCompare) {
354  // MERGED
355  if (m_relateClonesAndMerged) {
356  // Add the trg matching relation with negative weight
357  recoTrack->addRelationTo(trgTrack, -efficiency);
358  }
359  B2DEBUG(100, "Classifid RecoTrack " << recoTrackId << " as merge -> trgTrackId "
360  << trgTrackId << " : " << -efficiency);
361 
362  } else {
363  // MATCHED
364  // Add the trg matching relation
365  recoTrack->addRelationTo(trgTrack, efficiency);
366  B2DEBUG(100, "Classified RecoTrack " << recoTrackId << " as match -> trgTrackId "
367  << trgTrackId << " : " << efficiency);
368  }
369  }
370  }
371 
372  B2DEBUG(100, "########## end matching ############");
373 }
Belle2::RelationVector::size
size_t size() const
Get number of relations.
Definition: RelationVector.h:98
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::RecoTrack::getCDCHitList
std::vector< Belle2::RecoTrack::UsedCDCHit * > getCDCHitList() const
Return an unsorted list of cdc hits.
Definition: RecoTrack.h:446
Belle2::CDCTriggerTrack
Track created by the CDC trigger.
Definition: CDCTriggerTrack.h:15
Belle2::RelationsInterface::addRelationTo
void addRelationTo(const RelationsInterface< BASE > *object, float weight=1.0, const std::string &namedRelation="") const
Add a relation from this object to another object (with caching).
Definition: RelationsObject.h:144
Belle2::RelationsInterface::getRelationsTo
RelationVector< TO > getRelationsTo(const std::string &name="", const std::string &namedRelation="") const
Get the relations that point from this object to another store array.
Definition: RelationsObject.h:199
Belle2::Module
Base class for Modules.
Definition: Module.h:74
Belle2::CDCTriggerRecoMatcherModule::event
virtual void event() override
Called once for each event.
Definition: CDCTriggerRecoMatcherModule.cc:90
Belle2::RecoTrack
This is the Reconstruction Event-Data Model Track.
Definition: RecoTrack.h:78
Belle2::CDCTriggerRecoMatcherModule
A module to match CDCTriggerTracks to RecoTracks.
Definition: CDCTriggerRecoMatcherModule.h:22
Belle2::RelationVector
Class for type safe access to objects that are referred to in relations.
Definition: DataStore.h:38
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::CDCTriggerRecoMatcherModule::initialize
virtual void initialize() override
Initialize the module.
Definition: CDCTriggerRecoMatcherModule.cc:76
Belle2::RelationVector::weight
float weight(int index) const
Get weight with index.
Definition: RelationVector.h:120
Belle2::CDCTriggerSegmentHit
Combination of several CDCHits to a track segment hit for the trigger.
Definition: CDCTriggerSegmentHit.h:16