Belle II Software development
TrackQualityTools.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/processing/TrackQualityTools.h>
9#include <tracking/trackingUtilities/eventdata/tracks/CDCTrack.h>
10#include <tracking/trackingUtilities/eventdata/hits/CDCWireHit.h>
11#include <tracking/trackingUtilities/eventdata/trajectories/CDCTrajectory3D.h>
12#include <tracking/trackingUtilities/eventdata/trajectories/CDCTrajectory2D.h>
13
14#include <cdc/topology/CDCWire.h>
15#include <tracking/trackingUtilities/utilities/ReversedRange.h>
16
17#include <Math/VectorUtil.h>
18
19using namespace Belle2;
20using namespace CDC;
21using namespace TrackFindingCDC;
22using namespace TrackingUtilities;
23
24
26{
27 for (const CDCRecoHit3D& recoHit : track) {
28 if (recoHit.getStereoKind() == EStereoKind::c_Axial) {
29 break;
30 } else {
31 recoHit.getWireHit().getAutomatonCell().setAssignedFlag();
32 }
33 }
34}
35
36void TrackQualityTools::splitSecondHalfOfTrack(CDCTrack& track, std::vector<CDCTrack>& tracks)
37{
38 const CDCTrajectory3D& trajectory3D = track.getStartTrajectory3D();
39 const CDCTrajectory2D& trajectory2D = trajectory3D.getTrajectory2D();
40 const double radius = trajectory2D.getLocalCircle()->absRadius();
41 const Vector2D& apogee = trajectory2D.getGlobalCircle().apogee();
42 double arcLength2DOfApogee = trajectory2D.calcArcLength2D(apogee);
43 if (arcLength2DOfApogee < 0) {
44 arcLength2DOfApogee += 2 * TMath::Pi() * radius;
45 }
46
47 CDCTrack splittedCDCTrack;
48 splittedCDCTrack.setStartTrajectory3D(trajectory3D);
49
50 for (CDCRecoHit3D& recoHit : track) {
51 double currentArcLength2D = recoHit.getArcLength2D();
52 if (currentArcLength2D < 0) B2INFO("Below 0");
53 if (currentArcLength2D > arcLength2DOfApogee) {
54 splittedCDCTrack.push_back(recoHit);
55 recoHit.getWireHit().getAutomatonCell().setAssignedFlag();
56 }
57 }
58
59 if (splittedCDCTrack.size() > 0) {
60 tracks.push_back(splittedCDCTrack);
61 }
62}
63
65{
66 if (track.empty()) return;
67
68 CDCTrajectory3D trajectory3D = track.getStartTrajectory3D();
69
70 // We reset the trajectory here to start (later) at the newStartPosition of the first hit
71 const Vector3D startPosition(0, 0, 0);
72 trajectory3D.setLocalOrigin(startPosition);
73 trajectory3D.setFlightTime(0);
74
75 CDCTrajectory2D trajectory2D = trajectory3D.getTrajectory2D();
76
77 // Check if we have to reverse the trajectory. This is done by counting the number of hits
78 // with positive and with negative arc length
79 unsigned int numberOfPositiveHits = 0;
80 for (const CDCRecoHit3D& recoHit : track) {
81 const double currentArcLength = trajectory2D.calcArcLength2D(recoHit.getRecoPos2D());
82 if (currentArcLength > 0) {
83 numberOfPositiveHits++;
84 }
85 }
86 const bool reverseTrajectory = 2 * numberOfPositiveHits < track.size();
87
88 if (reverseTrajectory) {
89 trajectory3D.reverse();
90 trajectory2D.reverse();
91 }
92
93 double arcLength2DPeriod = trajectory2D.getArcLength2DPeriod();
94 for (CDCRecoHit3D& recoHit : track) {
95 Vector2D recoPos2D = recoHit.getRLWireHit().reconstruct3D(trajectory2D).xy();
96 double arcLength2D = trajectory2D.calcArcLength2D(recoPos2D);
97
98 if (arcLength2D < 0) {
99 arcLength2D += arcLength2DPeriod;
100 }
101 recoHit.setArcLength2D(arcLength2D);
102 recoHit.getWireHit().getAutomatonCell().unsetAssignedFlag();
103 recoHit.getWireHit().getAutomatonCell().setTakenFlag();
104 }
105
106 // We can now sort by arc length
107 track.sortByArcLength2D();
108
109 // Set the position to the first hit and let the hits start at arc length of 0
110 Vector3D frontPosition = track.front().getRLWireHit().reconstruct3D(trajectory2D);
111 double arcLengthOffset = trajectory3D.setLocalOrigin(frontPosition);
112 track.setStartTrajectory3D(trajectory3D);
113 for (CDCRecoHit3D& recoHit : track) {
114 recoHit.shiftArcLength2D(-arcLengthOffset);
115 }
116
117 // Set the back trajectory to start at the last hit position (and shift if necessary)
118 Vector3D backPosition = track.back().getRLWireHit().reconstruct3D(trajectory2D);
119 double backArcLength2D = trajectory3D.setLocalOrigin(backPosition);
120 if (backArcLength2D < 0) {
121 trajectory3D.shiftPeriod(1);
122 }
123 track.setEndTrajectory3D(trajectory3D);
124
125}
126
127void TrackQualityTools::removeHitsAfterCDCWall(CDCTrack& track, double outerCylindricalRFactor)
128{
129 const CDCTrajectory2D& trajectory2D = track.getStartTrajectory3D().getTrajectory2D();
130 const double radius = trajectory2D.getLocalCircle()->absRadius();
131
132 // Curler are allowed to have hits on both arms
133 if (trajectory2D.isCurler(outerCylindricalRFactor)) {
134 return;
135 }
136
137 const Vector2D& outerExitWithFactor = trajectory2D.getOuterExit(outerCylindricalRFactor);
138
139 double arcLength2DOfExitWithFactor = trajectory2D.calcArcLength2D(outerExitWithFactor);
140 if (arcLength2DOfExitWithFactor < 0) {
141 arcLength2DOfExitWithFactor += 2 * TMath::Pi() * radius;
142 }
143 bool removeAfterThis = false;
144
145 for (const CDCRecoHit3D& recoHit : track) {
146 if (removeAfterThis) {
147 recoHit.getWireHit().getAutomatonCell().setAssignedFlag();
148 continue;
149 }
150
151 double currentArcLength2D = recoHit.getArcLength2D();
152 if (currentArcLength2D < 0) {
153 currentArcLength2D += 2 * TMath::Pi() * radius;
154 }
155
156 if (currentArcLength2D > arcLength2DOfExitWithFactor) {
157 recoHit.getWireHit().getAutomatonCell().setAssignedFlag();
158 removeAfterThis = true;
159 }
160 }
161}
162
164{
165 ILayer lastLayer = -1;
166 Vector2D lastWirePosition;
167
168 std::vector<std::vector<const CDCRecoHit3D*>> trackletList;
169 trackletList.reserve(3);
170
171 std::vector<const CDCRecoHit3D*>* currentTracklet = nullptr;
172
173 for (const CDCRecoHit3D& recoHit : track) {
174 if (currentTracklet == nullptr) {
175 trackletList.emplace_back();
176 currentTracklet = &(trackletList.back());
177 }
178
179 const ILayer currentLayer = recoHit.getWire().getICLayer();
180 const Vector2D& currentPosition = recoHit.getRecoPos2D();
181 if (lastLayer != -1) {
182 const ILayer delta = currentLayer - lastLayer;
183 const double distance = (currentPosition - lastWirePosition).norm();
184 if (abs(delta) > 4 or distance > 50) {
185 trackletList.emplace_back();
186 currentTracklet = &(trackletList.back());
187 }
188 }
189
190 lastWirePosition = currentPosition;
191 lastLayer = currentLayer;
192
193 currentTracklet->push_back(&recoHit);
194 }
195
196 if (trackletList.size() > 1) {
197 for (const std::vector<const CDCRecoHit3D*>& tracklet : trackletList) {
198 if (tracklet.size() < 5) {
199 for (const CDCRecoHit3D* recoHit : tracklet) {
200 recoHit->getWireHit().getAutomatonCell().setAssignedFlag();
201 }
202 }
203 }
204 }
205}
206
207void TrackQualityTools::removeHitsAfterLayerBreak(CDCTrack& track, double m_maximumArcLength2DDistance)
208{
209 const CDCTrajectory3D& trajectory3D = track.getStartTrajectory3D();
210 const CDCTrajectory2D& trajectory2D = trajectory3D.getTrajectory2D();
211 const double radius = trajectory2D.getLocalCircle()->absRadius();
212
213 if (std::isnan(radius)) {
214 return;
215 }
216
217 std::vector<std::vector<const CDCRecoHit3D*>> trackletList;
218
219 double lastArcLength2D = NAN;
220
221 std::vector<const CDCRecoHit3D*>* currentTracklet = nullptr;
222
223 for (const CDCRecoHit3D& recoHit : track) {
224 if (currentTracklet == nullptr) {
225 trackletList.emplace_back();
226 currentTracklet = &(trackletList.back());
227 }
228
229 const double currentArcLength2D = recoHit.getArcLength2D();
230 if (not std::isnan(lastArcLength2D)) {
231 const double delta = (currentArcLength2D - lastArcLength2D);
232 if (std::fabs(delta) > m_maximumArcLength2DDistance) {
233 trackletList.emplace_back();
234 currentTracklet = &(trackletList.back());
235 }
236 }
237
238 lastArcLength2D = currentArcLength2D;
239
240 currentTracklet->push_back(&recoHit);
241 }
242
243 if (trackletList.size() > 1) {
244 // Throw away the ends if they are too small
245 while (trackletList.size() > 0) {
246 if (trackletList.back().size() > 4) {
247 break;
248 }
249
250 for (const CDCRecoHit3D* recoHit : trackletList.back()) {
251 recoHit->getWireHit().getAutomatonCell().setAssignedFlag();
252 }
253
254 trackletList.pop_back();
255 }
256
257 std::reverse(trackletList.begin(), trackletList.end());
258
259 while (trackletList.size() > 0) {
260 if (trackletList.back().size() > 4) {
261 break;
262 }
263
264 for (const CDCRecoHit3D* recoHit : trackletList.back()) {
265 recoHit->getWireHit().getAutomatonCell().setAssignedFlag();
266 }
267
268 trackletList.pop_back();
269 }
270 }
271}
272
273void TrackQualityTools::removeHitsIfSmall(CDCTrack& track, unsigned int minimalHits)
274{
275 const bool deleteTrack = track.size() < minimalHits;
276
277 if (deleteTrack) {
278 for (const CDCRecoHit3D& recoHit : track) {
279 recoHit.getWireHit().getAutomatonCell().setAssignedFlag();
280 }
281 }
282}
283
285{
286 double lastAngle = NAN;
287 bool removeAfterThis = false;
288
289 for (const CDCRecoHit3D& recoHit : reversedRange(track)) {
290 if (removeAfterThis) {
291 recoHit.getWireHit().getAutomatonCell().setAssignedFlag();
292 continue;
293 }
294
295 const double currentAngle = recoHit.getRecoPos2D().phi();
296 if (not std::isnan(lastAngle)) {
297 const double delta = currentAngle - lastAngle;
298 const double normalizedDelta =
299 std::min(
300 ROOT::Math::VectorUtil::Phi_0_2pi(delta),
301 ROOT::Math::VectorUtil::Phi_0_2pi(-delta));
302 if (fabs(normalizedDelta) > maximalAngle) {
303 removeAfterThis = true;
304 recoHit.getWireHit().getAutomatonCell().setAssignedFlag();
305 }
306 }
307
308 lastAngle = currentAngle;
309 }
310}
311
312
314{
315 ISuperLayer lastLayer = -1;
316 bool deleteTrack = true;
317
318 for (const CDCRecoHit3D& recoHit : track) {
319 const ISuperLayer currentLayer = recoHit.getISuperLayer();
320 if (lastLayer != -1 and lastLayer != currentLayer) {
321 deleteTrack = false;
322 break;
323 }
324
325 lastLayer = currentLayer;
326 }
327
328 if (deleteTrack) {
329 for (const CDCRecoHit3D& recoHit : track) {
330 recoHit.getWireHit().getAutomatonCell().setAssignedFlag();
331 }
332 }
333}
334
336{
337 const CDCTrajectory3D& trajectory3D = track.getStartTrajectory3D();
338 const CDCTrajectory2D& trajectory2D = trajectory3D.getTrajectory2D();
339
340 // Curler are allowed to have negative arc lengths
341 if (trajectory2D.isCurler()) {
342 return;
343 }
344 for (const CDCRecoHit3D& recoHit : track) {
345 if (trajectory2D.calcArcLength2D(recoHit.getRecoPos2D()) < 0) {
346 recoHit.getWireHit().getAutomatonCell().setAssignedFlag();
347 }
348 }
349}
350
351void TrackQualityTools::removeArcLength2DHoles(CDCTrack& track, double m_maximumArcLength2DDistance)
352{
353 const CDCTrajectory3D& trajectory3D = track.getStartTrajectory3D();
354 const CDCTrajectory2D& trajectory2D = trajectory3D.getTrajectory2D();
355 const double radius = trajectory2D.getLocalCircle()->absRadius();
356
357 if (std::isnan(radius)) {
358 return;
359 }
360
361 double lastArcLength2D = NAN;
362 bool removeAfterThis = false;
363
364 for (const CDCRecoHit3D& recoHit : track) {
365 if (removeAfterThis) {
366 recoHit.getWireHit().getAutomatonCell().setAssignedFlag();
367 continue;
368 }
369
370 const double currentArcLength2D = recoHit.getArcLength2D();
371 if (not std::isnan(lastArcLength2D)) {
372 const double delta = (currentArcLength2D - lastArcLength2D) / radius;
373 if (fabs(delta) > m_maximumArcLength2DDistance) {
374 removeAfterThis = true;
375 recoHit.getWireHit().getAutomatonCell().setAssignedFlag();
376 continue;
377 }
378 }
379
380 lastArcLength2D = currentArcLength2D;
381 }
382}
static void splitSecondHalfOfTrack(TrackingUtilities::CDCTrack &track, std::vector< TrackingUtilities::CDCTrack > &tracks)
Trasan did output curlers in split two halves - this method can be used to mimic this.
static void removeHitsIfSmall(TrackingUtilities::CDCTrack &track, unsigned int minimalHits=7)
Delete a track fully of the number of hits is below minimalHits.
static void removeHitsIfOnlyOneSuperLayer(TrackingUtilities::CDCTrack &track)
Remove the whole track if it only consists of one superlayer.
static void removeHitsAfterLayerBreak(TrackingUtilities::CDCTrack &track, double m_maximumArcLength2DDistance=10)
Delete all hits after a large layer break.
static void removeHitsInTheBeginningIfAngleLarge(TrackingUtilities::CDCTrack &track, double maximalAngle=0.7)
If the angle between two following hits is larger than maximalAngle, delete all hits before (!...
static void removeHitsOnTheWrongSide(TrackingUtilities::CDCTrack &track)
Remove all hits that are on the wrong side of the detector (so to say: "beyond the IP").
static void moveToNextAxialLayer(TrackingUtilities::CDCTrack &track)
Delete hits of the first superlayer if it is a stereo one (fitting does not work very well when start...
static void removeArcLength2DHoles(TrackingUtilities::CDCTrack &track, double m_maximumArcLength2DDistance=10)
Remove all hits that come after a large hole in the two dimensional arc length.
static void normalizeHitsAndResetTrajectory(TrackingUtilities::CDCTrack &track)
Update all hits to have a positive perpS, a taken flag and no background flag Also set the trajectory...
static void removeHitsAfterCDCWall(TrackingUtilities::CDCTrack &track, double outerCylindricalRFactor=1.1)
Remove all hits which can not belong to the track, as the particle can not exit and enter the CDC aga...
static void removeHitsAfterLayerBreak2(TrackingUtilities::CDCTrack &track)
Delete all hits after a large layer break.
void setAssignedFlag(bool setTo=true)
Sets the already assigned marker flag to the given value. Default value true.
Class representing a three dimensional reconstructed hit.
Class representing a sequence of three dimensional reconstructed hits.
Definition CDCTrack.h:39
void setStartTrajectory3D(const CDCTrajectory3D &startTrajectory3D)
Setter for the two dimensional trajectory.
Definition CDCTrack.h:96
AutomatonCell & getAutomatonCell() const
Mutable getter for the automaton cell.
Definition CDCTrack.h:123
Particle trajectory as it is seen in xy projection represented as a circle.
PerigeeCircle getGlobalCircle() const
Getter for the circle in global coordinates.
Vector2D getOuterExit(double factor=1) const
Calculates the point where the trajectory meets the outer wall of the CDC.
void reverse()
Reverses the trajectory in place.
double calcArcLength2D(const Vector2D &point) const
Calculate the travel distance from the start position of the trajectory.
bool isCurler(double factor=1) const
Checks if the trajectory leaves the outer radius of the CDC times the given tolerance factor.
double getArcLength2DPeriod() const
Getter for the arc length for one round trip around the trajectory.
const UncertainPerigeeCircle & getLocalCircle() const
Getter for the circle in local coordinates.
Particle full three dimensional trajectory.
void reverse()
Reverses the trajectory in place.
CDCTrajectory2D getTrajectory2D() const
Getter for the two dimensional trajectory.
double shiftPeriod(int nPeriods)
Adjusts the z0 to the one that lies n periods forward.
double setLocalOrigin(const Vector3D &localOrigin)
Setter for the origin of the local coordinate system.
void setFlightTime(double flightTime)
Setter for the time when the particle reached the support point position.
Vector2D apogee() const
Getter for the apogee of the circle. If it was a line both components will be infinity.
double absRadius() const
Gives the signed radius of the circle. If it was a line this will be infinity.
A two dimensional vector which is equipped with functions for correct handling of orientation relate...
Definition Vector2D.h:36
HepGeom::Vector3D< double > Vector3D
3D Vector
Definition Cell.h:34
signed short ILayer
The type of the layer ids enumerating layers within a superlayer.
Definition ILayer.h:18
signed short ISuperLayer
The type of the layer and superlayer ids.
Definition ISuperLayer.h:24
Abstract base class for different kinds of events.