Belle II Software  release-05-02-19
TrackCombiner.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2015 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Oliver Frost *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 #include <tracking/trackFindingCDC/findlets/minimal/TrackCombiner.h>
11 
12 #include <tracking/trackFindingCDC/eventdata/tracks/CDCTrack.h>
13 #include <tracking/trackFindingCDC/eventdata/segments/CDCSegment3D.h>
14 #include <tracking/trackFindingCDC/eventdata/hits/CDCRLWireHit.h>
15 #include <tracking/trackFindingCDC/eventdata/hits/CDCWireHit.h>
16 
17 #include <tracking/trackFindingCDC/numerics/Index.h>
18 
19 #include <tracking/trackFindingCDC/utilities/WeightedRelation.h>
20 #include <tracking/trackFindingCDC/utilities/Functional.h>
21 #include <tracking/trackFindingCDC/utilities/Range.h>
22 #include <tracking/trackFindingCDC/utilities/StringManipulation.h>
23 
24 #include <framework/core/ModuleParamList.templateDetails.h>
25 
26 #include <map>
27 #include <deque>
28 
29 using namespace Belle2;
30 using namespace TrackFindingCDC;
31 
32 namespace {
33  std::array<int, ISuperLayerUtil::c_N> getNHitsByISuperLayer(const CDCTrack& track)
34  {
35  std::array<int, ISuperLayerUtil::c_N> nHitsBySLayer = {0};
36  for (const CDCRecoHit3D& hit : track) {
37  nHitsBySLayer[hit.getISuperLayer()]++;
38  }
39  return nHitsBySLayer;
40  }
41 
42  CDCTrack condense(const TrackFindingCDC::Path<const CDCSegment3D>& segmentPath)
43  {
44  CDCTrack result;
45  for (const CDCSegment3D* segment : segmentPath) {
46  for (const CDCRecoHit3D& recoHit3D : *segment) {
47  result.push_back(recoHit3D);
48  }
49  }
50  if (segmentPath.size()) {
51  result.setStartTrajectory3D(segmentPath.front()->getTrajectory3D());
52  }
53  return result;
54  }
55 
56  std::vector<CDCRLWireHit> getRLWireHitSegment(const CDCSegment3D& segment3D)
57  {
58  std::vector<CDCRLWireHit> result;
59  result.reserve(segment3D.size());
60  for (const CDCRecoHit3D& recoHit3D : segment3D) {
61  // cppcheck-suppress useStlAlgorithm
62  result.push_back(recoHit3D.getRLWireHit());
63  }
64  return result;
65  }
66 
67  std::vector<std::pair<std::pair<Index, Index>, CDCRLWireHit>> getCommonRLWireHits(const std::vector<CDCRLWireHit>& rlWireHits1,
68  const std::vector<CDCRLWireHit>& rlWireHits2)
69  {
70  std::vector<std::pair<std::pair<Index, Index>, CDCRLWireHit>> result;
71  Index index1 = -1;
72  for (const CDCRLWireHit& rlWireHit : rlWireHits1) {
73  ++index1;
74  auto itRLWireHits2 = std::find(rlWireHits2.begin(), rlWireHits2.end(), rlWireHit);
75  if (itRLWireHits2 == rlWireHits2.end()) continue;
76  Index index2 = std::distance(rlWireHits2.begin(), itRLWireHits2);
77  assert(index2 >= 0);
78  result.push_back({{index1, index2}, rlWireHit});
79  }
80  return result;
81  }
82 }
83 
85 
87 {
88  return "Combines two sets of tracks to one final set by merging tracks that have large overlaps.";
89 }
90 
92  const std::string& prefix)
93 {
94  moduleParamList->addParameter(prefixed(prefix, "identifyCommonSegments"),
96  "Activate the identification of common segments",
98 }
99 
100 void TrackCombiner::apply(const std::vector<CDCTrack>& inputTracks,
101  const std::vector<CDCTrack>& secondInputTracks,
102  std::vector<CDCTrack>& outputTracks)
103 {
104  using InTracks = std::array<const CDCTrack*, 2>;
105 
106  // Constructing map of back links
107  std::map<const CDCWireHit*, InTracks> inTracksByWireHit;
108  for (const CDCTrack& track : inputTracks) {
109  for (const CDCRecoHit3D& recoHit3D : track) {
110  const CDCWireHit& wireHit = recoHit3D.getWireHit();
111  // cppcheck-suppress stlFindInsert
112  if (inTracksByWireHit.count(&wireHit) == 0) inTracksByWireHit[&wireHit] = {nullptr, nullptr};
113  inTracksByWireHit[&wireHit][0] = &track;
114  // Prepare hits for the cellular automaton
115  wireHit->unsetTemporaryFlags();
116  wireHit->unsetMaskedFlag();
117  }
118  }
119 
120  for (const CDCTrack& track : secondInputTracks) {
121  for (const CDCRecoHit3D& recoHit3D : track) {
122  const CDCWireHit& wireHit = recoHit3D.getWireHit();
123  // cppcheck-suppress stlFindInsert
124  if (inTracksByWireHit.count(&wireHit) == 0) inTracksByWireHit[&wireHit] = {nullptr, nullptr};
125  inTracksByWireHit[&wireHit][1] = &track;
126  // Prepare hits for the cellular automaton
127  wireHit->unsetTemporaryFlags();
128  wireHit->unsetMaskedFlag();
129  }
130  }
131 
132  // Rank tracks by number of superlayers touched first and number of hits second
133  std::vector<std::pair<std::pair<int, size_t>, const CDCTrack*> > rankedTracks;
134  for (const CDCTrack& track : inputTracks) {
135  std::array<int, ISuperLayerUtil::c_N> nHitsBySLayer = getNHitsByISuperLayer(track);
136  int nSL = std::count_if(nHitsBySLayer.begin(), nHitsBySLayer.end(), Id() > 0);
137  rankedTracks.push_back({{nSL, track.size()}, &track});
138  }
139  for (const CDCTrack& track : secondInputTracks) {
140  std::array<int, ISuperLayerUtil::c_N> nHitsBySLayer = getNHitsByISuperLayer(track);
141  int nSL = std::count_if(nHitsBySLayer.begin(), nHitsBySLayer.end(), Id() > 0);
142  rankedTracks.push_back({{nSL, track.size()}, &track});
143  }
144  std::sort(rankedTracks.begin(), rankedTracks.end(), GreaterOf<First>());
145 
146  // Memory for the splitted segments
147  std::deque<CDCSegment3D> segments;
148 
149  // Memory for the relations between tracks to be followed on linking
150  std::vector<WeightedRelation<const CDCSegment3D>> segmentRelations;
151 
152  // Also keep a record to which of the tracks the segment
153  std::map<const CDCSegment3D*, InTracks> inTracksBySegment;
154 
155  // Split tracks into segments - break segment such that there will be matching pieces with the other tracks
156  for (const std::pair<std::pair<int, size_t>, const CDCTrack*> rankedTrack : rankedTracks) {
157  // const std::pair<ISuperLayer, size_t> rank = rankedTrack.first;
158  const CDCTrack* track = rankedTrack.second;
159  std::vector<std::pair<InTracks, CDCSegment3D> > segmentsInTrack;
160 
161  // Split track into segments
162  CDCSegment3D* currentSegment = nullptr;
163  ISuperLayer lastISuperLayer = -1;
164  InTracks lastTracksForHit{{nullptr, nullptr}};
165  for (const CDCRecoHit3D& recoHit3D : *track) {
166  ISuperLayer iSuperLayer = recoHit3D.getISuperLayer();
167  std::array<const CDCTrack*, 2> tracksForWireHit = inTracksByWireHit[&recoHit3D.getWireHit()];
168  if (not currentSegment or iSuperLayer != lastISuperLayer or tracksForWireHit != lastTracksForHit) {
169  // Make new segments
170  segmentsInTrack.push_back({tracksForWireHit, CDCSegment3D()});
171  currentSegment = &segmentsInTrack.back().second;
172  currentSegment->setTrajectory3D(track->getStartTrajectory3D());
173  }
174  currentSegment->push_back(recoHit3D);
175  lastISuperLayer = iSuperLayer;
176  lastTracksForHit = tracksForWireHit;
177  }
178 
179  // Merge small segments
180  auto absorbsSegment = [](std::pair<InTracks, CDCSegment3D>& segment1,
181  std::pair<InTracks, CDCSegment3D>& segment2) {
182 
183  if (segment1.second.getISuperLayer() != segment2.second.getISuperLayer()) return false;
184  if (segment1.second.size() < 3) {
185  segment1.first = segment2.first;
186  }
187  // Absorb segment1 into segment2
188  if (segment1.second.size() < 3 or segment2.second.size() < 3 or
189  segment1.first == segment2.first) {
190  segment1.second.insert(segment1.second.end(),
191  segment2.second.begin(),
192  segment2.second.end());
193  return true;
194  }
195  return false;
196  };
197  auto itSegmentToDrop = std::unique(segmentsInTrack.begin(), segmentsInTrack.end(), absorbsSegment);
198  segmentsInTrack.erase(itSegmentToDrop, segmentsInTrack.end());
199 
200  size_t nHits = 0;
201  for (std::pair<InTracks, CDCSegment3D>& segment : segmentsInTrack) {
202  nHits += segment.second.size();
203  }
204  B2ASSERT("Expected the number of hits to be the same", nHits == track->size());
205 
206  // Push segments to the common pool
207  const CDCSegment3D* lastSegment = nullptr;
208  for (std::pair<InTracks, CDCSegment3D>& segmentInTrack : segmentsInTrack) {
209  const InTracks& inTracks = segmentInTrack.first;
210  const CDCSegment3D& segment = segmentInTrack.second;
211  segment->setCellWeight(segment.size());
212  segments.push_back(std::move(segment));
213  inTracksBySegment[&segments.back()] = inTracks;
214  if (lastSegment != nullptr) {
215  segmentRelations.push_back({lastSegment, 0, &segments.back()});
216  }
217  lastSegment = &segments.back();
218  }
219  }
220 
221  // Sort the relations for the lookup
222  std::sort(segmentRelations.begin(), segmentRelations.end());
223 
224  // Identify common segments, also checking whether they have the same orientation
226  std::vector<std::pair<const CDCSegment3D*, const CDCSegment3D*>> segmentContainmentRelation;
227  for (auto itSegment1 = segments.begin(); itSegment1 != segments.end(); ++itSegment1) {
228  const CDCSegment3D& segment1 = *itSegment1;
229  std::vector<CDCRLWireHit> rlWireHits1 = getRLWireHitSegment(segment1);
230  ISuperLayer iSL1 = segment1.getISuperLayer();
231  InTracks inTracks1 = inTracksBySegment[&segment1];
232  for (auto itSegment2 = itSegment1 + 1; itSegment2 != segments.end(); ++itSegment2) {
233  const CDCSegment3D& segment2 = *itSegment2;
234 
235  // Should not happen - here for safety reasons
236  if (&segment1 == &segment2) continue;
237 
238  ISuperLayer iSL2 = segment2.getISuperLayer();
239  if (iSL1 != iSL2) continue;
240 
241  InTracks inTracks2 = inTracksBySegment[&segment2];
242  if (inTracks1 != inTracks2) continue;
243 
244  // Now answering the question if segment 1 is contained in segment 2
245  std::vector<CDCRLWireHit> rlWireHits2 = getRLWireHitSegment(segment2);
246  std::vector<std::pair<std::pair<int, int>, CDCRLWireHit>> commonRLWireHits =
247  getCommonRLWireHits(rlWireHits1, rlWireHits2);
248 
249  // Check for containment, requiring that the majority of the wire hits of one is in two
250  // However also require that the two is not too much larger compared to the first one
251  bool contains = commonRLWireHits.size() > 2 and
252  commonRLWireHits.size() > rlWireHits1.size() * 0.8 and
253  commonRLWireHits.size() > rlWireHits2.size() * 0.8;
254  if (not contains) continue;
255 
256  // Now finally check whether both segments point in the same direction
257  double n = commonRLWireHits.size();
258  double prod11 = 0;
259  double prod12 = 0;
260  double prod22 = 0;
261  double sum1 = 0;
262  double sum2 = 0;
263  for (const auto& commonRLWireHit : commonRLWireHits) {
264  const std::pair<int, int>& indices = commonRLWireHit.first;
265  prod11 += indices.first * indices.first;
266  prod12 += indices.first * indices.second;
267  prod22 += indices.second * indices.second;
268 
269  sum1 += indices.first;
270  sum2 += indices.second;
271  }
272  double var1 = (prod11 - sum1 * sum1 / n);
273  double var2 = (prod22 - sum2 * sum2 / n);
274  double cov12 = (prod12 - sum1 * sum2 / n);
275  double cor = cov12 / std::sqrt(var1 * var2);
276  if (not(cor > 0.75)) continue;
277 
278  segmentContainmentRelation.push_back({&segment1, &segment2});
279  }
280  }
281 
282  // Create additional edges
283  std::vector<WeightedRelation<const CDCSegment3D>> additionalSegmentRelations;
284  for (std::pair<const CDCSegment3D*, const CDCSegment3D*>& rel : segmentContainmentRelation) {
286  asRange(std::equal_range(segmentRelations.begin(), segmentRelations.end(), rel.first))) {
287  additionalSegmentRelations.push_back({rel.second, 0, rel1.getTo()});
288  }
289 
290  for (WeightedRelation<const CDCSegment3D> rel2 : asRange(
291  std::equal_range(segmentRelations.begin(), segmentRelations.end(), rel.second))) {
292  additionalSegmentRelations.push_back({rel.first, 0, rel2.getFrom()});
293  }
294  }
295  segmentRelations.insert(segmentRelations.end(),
296  additionalSegmentRelations.begin(),
297  additionalSegmentRelations.end());
298  std::sort(segmentRelations.begin(), segmentRelations.end());
299  }
300 
301  // Extract paths
302  // Obtain the segments as pointers
303  std::vector<const CDCSegment3D*> segmentPtrs = as_pointers<const CDCSegment3D>(segments);
304 
305  // Memory for the track paths generated from the graph.
306  std::vector<TrackFindingCDC::Path<const CDCSegment3D>> segmentPaths;
307  m_cellularPathFinder.apply(segmentPtrs, segmentRelations, segmentPaths);
308 
309  // Put the linked segments together
310  outputTracks.clear();
311  for (const std::vector<const CDCSegment3D*>& segmentPath : segmentPaths) {
312  // Reject single left over segments
313  if (segmentPath.size() < 2) continue;
314  outputTracks.push_back(condense(segmentPath));
315  }
316 
317  // Simple approach
318  // Incoporate the second input tracks in to the first input tracks by looking for large overlaps
319  // Very simple approach use the first tracks and add the ones from the second tracks with no overlap to the first
320  // outputTracks.insert(outputTracks.end(), inputTracks.begin(), inputTracks.end());
321  // for (const CDCTrack& secondTrack : secondInputTracks) {
322  // std::map<const CDCTrack*, int> overlappingTracks;
323  // for (const CDCRecoHit3D& recoHit3D : secondTrack) {
324  // const CDCWireHit& wireHit = recoHit3D.getWireHit();
325  // inTracksByWireHit.equal_range(&recoHit3D.getWireHit());
326  // auto tracksForWireHit = asRange(inTracksByWireHit.equal_range(&wireHit));
327  // for (const std::pair<const CDCWireHit*, InTracks>& trackForWireHit : inTracksByWireHit) {
328  // const CDCTrack* track = trackForWireHit.second[0];
329  // if (not track) continue;
330  // overlappingTracks[track]++;
331  // }
332  // }
333  // if (overlappingTracks.size() == 0) {
334  // outputTracks.push_back(secondTrack);
335  // }
336  // }
337 }
Belle2::TrackFindingCDC::CDCRecoHit3D
Class representing a three dimensional reconstructed hit.
Definition: CDCRecoHit3D.h:62
Belle2::TrackFindingCDC::CDCTrack
Class representing a sequence of three dimensional reconstructed hits.
Definition: CDCTrack.h:51
Belle2::TrackFindingCDC::BinaryJoin
Functor factory turning a binary functor and two functors into a new functor which executes the binar...
Definition: Functional.h:137
Belle2::TrackFindingCDC::Id
Generic identity functor.
Definition: Functional.h:35
Belle2::TrackFindingCDC::TrackCombiner::TrackCombiner
TrackCombiner()
Default constructor.
Belle2::TrackFindingCDC::AutomatonCell::unsetMaskedFlag
void unsetMaskedFlag()
Resets the masked flag to false.
Definition: AutomatonCell.h:222
Belle2::TrackFindingCDC::TrackCombiner::m_param_identifyCommonSegments
bool m_param_identifyCommonSegments
Parameter : Activate the identification of common segments.
Definition: TrackCombiner.h:62
Belle2::TrackFindingCDC::CDCSegment3D
A segment consisting of three dimensional reconstructed hits.
Definition: CDCSegment3D.h:36
Belle2::TrackFindingCDC::AutomatonCell::unsetTemporaryFlags
void unsetTemporaryFlags()
Resets the assigned, start and cycle marker flag.
Definition: AutomatonCell.h:210
Belle2::ModuleParamList::addParameter
void addParameter(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module list.
Definition: ModuleParamList.templateDetails.h:38
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::TrackFindingCDC::CDCRLWireHit
Class representing an oriented hit wire including a hypotheses whether the causing track passes left ...
Definition: CDCRLWireHit.h:51
Belle2::TrackFindingCDC::CDCSegment::getISuperLayer
ISuperLayer getISuperLayer() const
Returns the common super layer id of all stored tracking hits.
Definition: CDCSegment.h:67
Belle2::TrackFindingCDC::TrackCombiner::apply
void apply(const std::vector< CDCTrack > &inputTracks, const std::vector< CDCTrack > &secondInputTracks, std::vector< CDCTrack > &tracks) final
Main algorithm.
Definition: TrackCombiner.cc:100
Belle2::TrackFindingCDC::TrackCombiner::exposeParameters
void exposeParameters(ModuleParamList *moduleParamList, const std::string &prefix) final
Expose the parameters to a module.
Definition: TrackCombiner.cc:91
Belle2::TrackFindingCDC::TrackCombiner::m_cellularPathFinder
MultipassCellularPathFinder< const CDCSegment3D > m_cellularPathFinder
Instance of the cellular automaton path finder.
Definition: TrackCombiner.h:66
Belle2::TrackFindingCDC::WeightedRelation
Type for two related objects with a weight.
Definition: CDCSegment2D.h:36
Belle2::TrackFindingCDC::TrackCombiner::getDescription
std::string getDescription() final
Short description of the findlet.
Definition: TrackCombiner.cc:86
Belle2::TrackFindingCDC::CDCWireHit
Class representing a hit wire in the central drift chamber.
Definition: CDCWireHit.h:65
Belle2::ModuleParamList
The Module parameter list class.
Definition: ModuleParamList.h:46