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