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