Belle II Software development
AxialTrackMerger.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/AxialTrackMerger.h>
9
10#include <tracking/trackFindingCDC/processing/AxialTrackUtil.h>
11
12#include <tracking/trackFindingCDC/fitting/CDCKarimakiFitter.h>
13
14#include <tracking/trackingUtilities/eventdata/tracks/CDCTrack.h>
15#include <tracking/trackingUtilities/eventdata/hits/CDCWireHit.h>
16#include <tracking/trackingUtilities/eventdata/trajectories/CDCTrajectory2D.h>
17
18#include <tracking/trackingUtilities/numerics/WeightComperator.h>
19
20#include <tracking/trackingUtilities/utilities/StringManipulation.h>
21
22#include <framework/core/ModuleParamList.templateDetails.h>
23
24#include <Math/Vector2D.h>
25
26using namespace Belle2;
27using namespace TrackFindingCDC;
28using namespace TrackingUtilities;
29
31{
32 return "Merges axial tracks found in the Legendre search";
33}
34
35void AxialTrackMerger::exposeParameters(ModuleParamList* moduleParamList, const std::string& prefix)
36{
37 moduleParamList->addParameter(prefixed(prefix, "minFitProb"),
39 "Minimal fit probability of the common fit "
40 "of two tracks to be eligible for merging",
42}
43
44void AxialTrackMerger::apply(std::vector<CDCTrack>& axialTracks,
45 const std::vector<const CDCWireHit*>& allAxialWireHits)
46{
47 // Check quality of the track basing on holes on the trajectory;
48 // if holes exist then track is split
49 for (CDCTrack& track : axialTracks) {
50 if (track.size() < 5) continue;
53 }
54
55 // Update tracks before storing to DataStore
56 for (CDCTrack& track : axialTracks) {
58 }
59
60 // Remove bad tracks
63
64 // Perform tracks merging
65 this->doTracksMerging(axialTracks, allAxialWireHits);
66
67 // Remove the consumed, now empty tracks.
69}
70
71void AxialTrackMerger::doTracksMerging(std::vector<CDCTrack>& axialTracks,
72 const std::vector<const CDCWireHit*>& allAxialWireHits)
73{
74 // Search for best matches - cannot use range for here :(.
75 for (auto itTrack = axialTracks.begin(); itTrack != axialTracks.end(); ++itTrack) {
76 CDCTrack& track = *itTrack;
77 auto followingTracks = asRange(std::next(itTrack), axialTracks.end());
78
79 WithWeight<MayBePtr<CDCTrack> > bestTrack = calculateBestTrackToMerge(track, followingTracks);
80 double fitProb = bestTrack.getWeight();
81
82 if (bestTrack != nullptr and fitProb > m_param_minFitProb) {
83 mergeTracks(track, *bestTrack, allAxialWireHits);
84 }
85 }
86
88}
89
91template <class ACDCTracks>
93{
94 std::vector<WithWeight<CDCTrack*>> weightedTracks;
95 for (CDCTrack& track2 : tracks) {
96 if (&track == &track2) continue;
97 if (track2.size() < 3) continue;
98
99 double fitProb = doTracksFitTogether(track, track2);
100 if (std::isnan(fitProb)) continue;
101
102 weightedTracks.emplace_back(&track2, fitProb);
103 }
104
105 auto bestMatch = std::max_element(weightedTracks.begin(), weightedTracks.end(), LessWeight());
106 if (bestMatch == weightedTracks.end()) return {nullptr, 0};
107 else return *bestMatch;
108}
109
111{
112 // First check whether most of the hits from the tracks lie in the backward direction
113 // even if though track is not curling -> tracks should not be merged
114 const CDCTrajectory3D& trajectory3D1 = track1.getStartTrajectory3D();
115 const CDCTrajectory3D& trajectory3D2 = track2.getStartTrajectory3D();
116
117 int fbVote12 = 0;
118 int fbVote21 = 0;
119
120 for (const CDCRecoHit3D& recoHit3D : track1) {
121 EForwardBackward fbInfo = VectorUtil::isForwardOrBackwardOf(VectorUtil::getXYVector(trajectory3D2.getFlightDirection3DAtSupport()),
122 recoHit3D.getRecoPos2D());
123 if (not isValid(fbInfo)) continue;
124 fbVote12 += fbInfo;
125 }
126
127 for (const CDCRecoHit3D& recoHit3D : track2) {
128 EForwardBackward fbInfo = VectorUtil::isForwardOrBackwardOf(VectorUtil::getXYVector(trajectory3D1.getFlightDirection3DAtSupport()),
129 recoHit3D.getRecoPos2D());
130 if (not isValid(fbInfo)) continue;
131 fbVote21 += fbInfo;
132 }
133
134 if (not trajectory3D1.isCurler() and fbVote12 < 0) return NAN;
135 if (not trajectory3D2.isCurler() and fbVote21 < 0) return NAN;
136
137 // Build common hit list by copying the wire hits into one large list
138 // We use the wire hits here as we do not want them to bring
139 // their "old" reconstructed position when fitting.
140 std::vector<const CDCWireHit*> combinedWireHits;
141 combinedWireHits.reserve(track1.size() + track2.size());
142 for (const CDCRecoHit3D& hit : track1) {
143 combinedWireHits.push_back(&(hit.getWireHit()));
144 }
145 for (const CDCRecoHit3D& hit : track2) {
146 combinedWireHits.push_back(&(hit.getWireHit()));
147 }
148
149 // Sorting is done via pointer addresses (!!).
150 // This is not very stable and also not very meaningful (in terms of ordering in the track),
151 // but it does the job for unique.
152 // (the ordering is still outwards though since the wire hits are ordered like that in continuous memory)
153 std::sort(combinedWireHits.begin(), combinedWireHits.end());
154 erase_unique(combinedWireHits);
155
156 // Calculate track parameters
157 CDCTrajectory2D commonTrajectory2D;
159
160 // Approach the best fit
161 commonTrajectory2D = fitter.fit(combinedWireHits);
162 removeStrangeHits(5, combinedWireHits, commonTrajectory2D);
163 commonTrajectory2D = fitter.fit(combinedWireHits);
164 removeStrangeHits(3, combinedWireHits, commonTrajectory2D);
165 commonTrajectory2D = fitter.fit(combinedWireHits);
166 removeStrangeHits(1, combinedWireHits, commonTrajectory2D);
167 commonTrajectory2D = fitter.fit(combinedWireHits);
168 removeStrangeHits(1, combinedWireHits, commonTrajectory2D);
169 commonTrajectory2D = fitter.fit(combinedWireHits);
170
171 // Dismiss this possibility if the hit list size after all the removing of hits is even smaller
172 // than the two lists before or if the list is too small
173 if (combinedWireHits.size() <= std::max(track1.size(), track2.size())
174 or combinedWireHits.size() < 15) {
175 return NAN;
176 }
177
178 return commonTrajectory2D.getPValue();
179}
180
182 std::vector<const CDCWireHit*>& wireHits,
183 CDCTrajectory2D& trajectory2D)
184{
185 auto farFromTrajectory = [&trajectory2D, &factor](const CDCWireHit * wireHit) {
186 ROOT::Math::XYVector pos2D = wireHit->getRefPos2D();
187 double driftLength = wireHit->getRefDriftLength();
188 double dist = std::fabs(trajectory2D.getDist2D(pos2D)) - driftLength;
189 return std::fabs(dist) > driftLength * factor;
190 };
191 erase_remove_if(wireHits, farFromTrajectory);
192}
193
195 CDCTrack& track2,
196 const std::vector<const CDCWireHit*>& allAxialWireHits)
197{
198 if (&track1 == &track2) return;
199
200 CDCTrajectory2D trajectory2D = track1.getStartTrajectory3D().getTrajectory2D();
201 for (const CDCRecoHit3D& orgRecoHit3D : track2) {
202 CDCRecoHit3D recoHit3D = CDCRecoHit3D::reconstruct(orgRecoHit3D.getRLWireHit(), trajectory2D);
203 track1.push_back(std::move(recoHit3D));
204 }
205 track2.clear();
206
208
210
212
213 for (CDCRecoHit3D& recoHit3D : track2) {
214 const auto& tmp = recoHit3D.getRefPos2D();
215 recoHit3D.setRecoPos3D({tmp.X(), tmp.Y(), 0});
216 recoHit3D.setRLInfo(ERightLeft::c_Unknown);
217 }
218
220 bool success = AxialTrackUtil::postprocessTrack(track2, allAxialWireHits);
221 if (not success) {
222 for (const CDCRecoHit3D& recoHit3D : track2) {
223 recoHit3D.getWireHit()->setTakenFlag(false);
224 }
225 track2.clear();
226 }
227}
The Module parameter list class.
void apply(std::vector< TrackingUtilities::CDCTrack > &axialTracks, const std::vector< const TrackingUtilities::CDCWireHit * > &axialWireHits) final
Merge tracks together. Allows for axial hits to be added as it may see fit.
static void removeStrangeHits(double factor, std::vector< const TrackingUtilities::CDCWireHit * > &wireHits, TrackingUtilities::CDCTrajectory2D &trajectory)
Remove all hits that are further than factor * driftlength away from the trajectory.
void doTracksMerging(std::vector< TrackingUtilities::CDCTrack > &axialTracks, const std::vector< const TrackingUtilities::CDCWireHit * > &allAxialWireHits)
The track finding often finds two curling tracks, originating from the same particle.
std::string getDescription() final
Short description of the findlet.
static void mergeTracks(TrackingUtilities::CDCTrack &track1, TrackingUtilities::CDCTrack &track2, const std::vector< const TrackingUtilities::CDCWireHit * > &allAxialWireHits)
Function to merge two track candidates.
static double doTracksFitTogether(TrackingUtilities::CDCTrack &track1, TrackingUtilities::CDCTrack &track2)
Fits the hit content of both tracks in a common fit repeated with an annealing schedule removing far ...
void exposeParameters(ModuleParamList *moduleParamList, const std::string &prefix) final
Expose the parameters to a module.
static TrackingUtilities::WithWeight< TrackingUtilities::MayBePtr< TrackingUtilities::CDCTrack > > calculateBestTrackToMerge(TrackingUtilities::CDCTrack &track, ACDCTracks &tracks)
Searches for the best candidate to merge this track to.
double m_param_minFitProb
Parameter : Minimal fit probability of the common fit of two tracks to be eligible for merging.
Class implementing the fitter using Karimakis method.
static const CDCKarimakiFitter & getNoDriftVarianceFitter()
Static getter for a general fitter that does not use the drift length variances.
Class representing a three dimensional reconstructed hit.
static CDCRecoHit3D reconstruct(const CDCRecoHit2D &recoHit2D, const CDCTrajectory2D &trajectory2D)
Reconstructs the three dimensional hit from the two dimensional and the two dimensional trajectory.
Class representing a sequence of three dimensional reconstructed hits.
Definition CDCTrack.h:37
Particle trajectory as it is seen in xy projection represented as a circle.
double getPValue() const
Getter for p-value.
double getDist2D(const ROOT::Math::XYVector &point) const
Calculates the distance from the point to the trajectory as seen from the xy projection.
Particle full three dimensional trajectory.
bool isCurler(double factor=1) const
Checks if the trajectory leaves the outer radius of the CDC times the given tolerance factor.
ROOT::Math::XYZVector getFlightDirection3DAtSupport() const
Get the unit momentum at the start point of the trajectory.
Class representing a hit wire in the central drift chamber.
Definition CDCWireHit.h:56
A mixin class to attach a weight to an object.
Definition WithWeight.h:24
Weight getWeight() const
Getter for the weight.
Definition WithWeight.h:56
void addParameter(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module list.
Abstract base class for different kinds of events.
static void normalizeTrack(TrackingUtilities::CDCTrack &track)
Refit and resort the track. Unmask all hits.
static void deleteShortTracks(std::vector< TrackingUtilities::CDCTrack > &axialTracks, double minimal_size=5)
Remove tracks that are shorter than the given number of hits.
static void deleteTracksWithLowFitProbability(std::vector< TrackingUtilities::CDCTrack > &axialTracks, double minimal_probability_for_good_fit=0.4)
Check an (improper) p-values of the tracks. If they are below the given value, delete the track from ...
static void removeHitsAfterSuperLayerBreak(TrackingUtilities::CDCTrack &track)
Searches for a break in the super layer chain and remove all hits that come after that.
static std::vector< TrackingUtilities::CDCRecoHit3D > splitBack2BackTrack(TrackingUtilities::CDCTrack &track)
Tries to split back-to-back tracks into two different tracks.
static bool postprocessTrack(TrackingUtilities::CDCTrack &track, const std::vector< const TrackingUtilities::CDCWireHit * > &allAxialWireHits)
Perform all track postprocessing - return whether the track is considered good after the postprocessi...