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 moduleParamList->addParameter(prefixed(prefix, "removeHitsAfterSuperLayerBreak"),
45 "Remove the hits of the tracks after a super layer break "
46 "before merging the tracks",
48}
49
50void AxialTrackMerger::apply(std::vector<CDCTrack>& axialTracks,
51 const std::vector<const CDCWireHit*>& allAxialWireHits)
52{
53 // Check quality of the track basing on holes on the trajectory;
54 // if holes exist then track is split
55 for (CDCTrack& track : axialTracks) {
56 if (track.size() < 5) continue;
59 }
61 }
62
63 // Update tracks before storing to DataStore
64 for (CDCTrack& track : axialTracks) {
66 }
67
68 // Remove bad tracks
71
72 // Perform tracks merging
73 this->doTracksMerging(axialTracks, allAxialWireHits);
74
75 // Remove the consumed, now empty tracks.
77}
78
79void AxialTrackMerger::doTracksMerging(std::vector<CDCTrack>& axialTracks,
80 const std::vector<const CDCWireHit*>& allAxialWireHits)
81{
82 // Search for best matches - cannot use range for here :(.
83 for (auto itTrack = axialTracks.begin(); itTrack != axialTracks.end(); ++itTrack) {
84 CDCTrack& track = *itTrack;
85 auto followingTracks = asRange(std::next(itTrack), axialTracks.end());
86
87 WithWeight<MayBePtr<CDCTrack> > bestTrack = calculateBestTrackToMerge(track, followingTracks);
88 double fitProb = bestTrack.getWeight();
89
90 if (bestTrack != nullptr and fitProb > m_param_minFitProb) {
91 mergeTracks(track, *bestTrack, allAxialWireHits);
92 }
93 }
94
96}
97
99template <class ACDCTracks>
101{
102 std::vector<WithWeight<CDCTrack*>> weightedTracks;
103 for (CDCTrack& track2 : tracks) {
104 if (&track == &track2) continue;
105 if (track2.size() < 3) continue;
106
107 double fitProb = doTracksFitTogether(track, track2);
108 if (std::isnan(fitProb)) continue;
109
110 weightedTracks.emplace_back(&track2, fitProb);
111 }
112
113 auto bestMatch = std::max_element(weightedTracks.begin(), weightedTracks.end(), LessWeight());
114 if (bestMatch == weightedTracks.end()) return {nullptr, 0};
115 else return *bestMatch;
116}
117
119{
120 // First check whether most of the hits from the tracks lie in the backward direction
121 // even if though track is not curling -> tracks should not be merged
122 const CDCTrajectory3D& trajectory3D1 = track1.getStartTrajectory3D();
123 const CDCTrajectory3D& trajectory3D2 = track2.getStartTrajectory3D();
124
125 int fbVote12 = 0;
126 int fbVote21 = 0;
127
128 for (const CDCRecoHit3D& recoHit3D : track1) {
129 EForwardBackward fbInfo = VectorUtil::isForwardOrBackwardOf(VectorUtil::getXYVector(trajectory3D2.getFlightDirection3DAtSupport()),
130 recoHit3D.getRecoPos2D());
131 if (not isValid(fbInfo)) continue;
132 fbVote12 += fbInfo;
133 }
134
135 for (const CDCRecoHit3D& recoHit3D : track2) {
136 EForwardBackward fbInfo = VectorUtil::isForwardOrBackwardOf(VectorUtil::getXYVector(trajectory3D1.getFlightDirection3DAtSupport()),
137 recoHit3D.getRecoPos2D());
138 if (not isValid(fbInfo)) continue;
139 fbVote21 += fbInfo;
140 }
141
142 if (not trajectory3D1.isCurler() and fbVote12 < 0) return NAN;
143 if (not trajectory3D2.isCurler() and fbVote21 < 0) return NAN;
144
145 // Build common hit list by copying the wire hits into one large list
146 // We use the wire hits here as we do not want them to bring
147 // their "old" reconstructed position when fitting.
148 std::vector<const CDCWireHit*> combinedWireHits;
149 combinedWireHits.reserve(track1.size() + track2.size());
150 for (const CDCRecoHit3D& hit : track1) {
151 combinedWireHits.push_back(&(hit.getWireHit()));
152 }
153 for (const CDCRecoHit3D& hit : track2) {
154 combinedWireHits.push_back(&(hit.getWireHit()));
155 }
156
157 // Sorting is done via pointer addresses (!!).
158 // This is not very stable and also not very meaningful (in terms of ordering in the track),
159 // but it does the job for unique.
160 // (the ordering is still outwards though since the wire hits are ordered like that in continuous memory)
161 std::sort(combinedWireHits.begin(), combinedWireHits.end());
162 erase_unique(combinedWireHits);
163
164 // Calculate track parameters
165 CDCTrajectory2D commonTrajectory2D;
167
168 // Approach the best fit
169 commonTrajectory2D = fitter.fit(combinedWireHits);
170 removeStrangeHits(5, combinedWireHits, commonTrajectory2D);
171 commonTrajectory2D = fitter.fit(combinedWireHits);
172 removeStrangeHits(3, combinedWireHits, commonTrajectory2D);
173 commonTrajectory2D = fitter.fit(combinedWireHits);
174 removeStrangeHits(1, combinedWireHits, commonTrajectory2D);
175 commonTrajectory2D = fitter.fit(combinedWireHits);
176 removeStrangeHits(1, combinedWireHits, commonTrajectory2D);
177 commonTrajectory2D = fitter.fit(combinedWireHits);
178
179 // Dismiss this possibility if the hit list size after all the removing of hits is even smaller
180 // than the two lists before or if the list is too small
181 if (combinedWireHits.size() <= std::max(track1.size(), track2.size())
182 or combinedWireHits.size() < 15) {
183 return NAN;
184 }
185
186 return commonTrajectory2D.getPValue();
187}
188
190 std::vector<const CDCWireHit*>& wireHits,
191 CDCTrajectory2D& trajectory2D)
192{
193 auto farFromTrajectory = [&trajectory2D, &factor](const CDCWireHit * wireHit) {
194 ROOT::Math::XYVector pos2D = wireHit->getRefPos2D();
195 double driftLength = wireHit->getRefDriftLength();
196 double dist = std::fabs(trajectory2D.getDist2D(pos2D)) - driftLength;
197 return std::fabs(dist) > driftLength * factor;
198 };
199 erase_remove_if(wireHits, farFromTrajectory);
200}
201
203 CDCTrack& track2,
204 const std::vector<const CDCWireHit*>& allAxialWireHits)
205{
206 if (&track1 == &track2) return;
207
208 CDCTrajectory2D trajectory2D = track1.getStartTrajectory3D().getTrajectory2D();
209 for (const CDCRecoHit3D& orgRecoHit3D : track2) {
210 CDCRecoHit3D recoHit3D = CDCRecoHit3D::reconstruct(orgRecoHit3D.getRLWireHit(), trajectory2D);
211 track1.push_back(std::move(recoHit3D));
212 }
213 track2.clear();
214
216
218
220
221 for (CDCRecoHit3D& recoHit3D : track2) {
222 const auto& tmp = recoHit3D.getRefPos2D();
223 recoHit3D.setRecoPos3D({tmp.X(), tmp.Y(), 0});
224 recoHit3D.setRLInfo(ERightLeft::c_Unknown);
225 }
226
228 bool success = AxialTrackUtil::postprocessTrack(track2, allAxialWireHits);
229 if (not success) {
230 for (const CDCRecoHit3D& recoHit3D : track2) {
231 recoHit3D.getWireHit()->setTakenFlag(false);
232 }
233 track2.clear();
234 }
235}
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.
bool m_param_removeHitsAfterSuperLayerBreak
Parameter : Remove the hits of the tracks after a super layer break before merging.
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...