Skip to content

Commit 2ef458e

Browse files
committed
ITS: fix degenerate LSE for matrix solving
Comparing the output of dev and this PR, I saw plently of cases where the system of equation was fully degenerate and produced to different floating instructions and compiler optimizations slightly different results. The solution is to discard the vertex cand. if the LSE becomes degenerate as not to produce non-sense solutions. Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch>
1 parent 19d94af commit 2ef458e

File tree

8 files changed

+129
-419
lines changed

8 files changed

+129
-419
lines changed

Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h

Lines changed: 0 additions & 73 deletions
This file was deleted.

Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h

Lines changed: 33 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -14,150 +14,56 @@
1414

1515
#include <array>
1616
#include <vector>
17+
#include <Math/SMatrix.h>
18+
#include <Math/SVector.h>
19+
#include "Framework/Logger.h"
1720
#include "ITStracking/Cluster.h"
1821
#include "ITStracking/Constants.h"
19-
#include "ITStracking/Definitions.h"
2022
#include "ITStracking/Tracklet.h"
21-
#include "GPUCommonRtypes.h"
22-
#include "GPUCommonMath.h"
23-
#include "GPUCommonDef.h"
24-
#include "GPUCommonLogger.h"
2523

2624
namespace o2::its
2725
{
26+
2827
struct Line final {
29-
GPUhdDefault() Line() = default;
30-
GPUhdDefault() Line(const Line&) = default;
31-
Line(std::array<float, 3> firstPoint, std::array<float, 3> secondPoint);
32-
GPUhd() Line(const Tracklet&, const Cluster*, const Cluster*);
28+
using SVector3f = ROOT::Math::SVector<float, 3>;
29+
using SMatrix3f = ROOT::Math::SMatrix<float, 3, 3, ROOT::Math::MatRepSym<float, 3>>;
30+
31+
Line() = default;
32+
Line(const Tracklet&, const Cluster*, const Cluster*);
3333

3434
static float getDistanceFromPoint(const Line& line, const std::array<float, 3>& point);
35-
GPUhd() static float getDistanceFromPoint(const Line& line, const float point[3]);
36-
static std::array<float, 6> getDCAComponents(const Line& line, const std::array<float, 3> point);
37-
GPUhd() static void getDCAComponents(const Line& line, const float point[3], float destArray[6]);
38-
GPUhd() static float getDCA(const Line&, const Line&, const float precision = constants::Tolerance);
39-
static bool areParallel(const Line&, const Line&, const float precision = constants::Tolerance);
40-
GPUhd() unsigned char isEmpty() const { return (originPoint[0] == 0.f && originPoint[1] == 0.f && originPoint[2] == 0.f) &&
41-
(cosinesDirector[0] == 0.f && cosinesDirector[1] == 0.f && cosinesDirector[2] == 0.f); }
42-
bool operator==(const Line&) const;
43-
bool operator!=(const Line&) const;
44-
GPUh() void print() const
35+
static SMatrix3f getDCAComponents(const Line& line, const std::array<float, 3>& point);
36+
static float getDCA(const Line&, const Line&, const float precision = constants::Tolerance);
37+
bool isEmpty() const { return ROOT::Math::Dot(originPoint, originPoint) == 0.f &&
38+
ROOT::Math::Dot(cosinesDirector, cosinesDirector) == 0.f; }
39+
bool operator==(const Line&) const = default;
40+
void print() const
4541
{
46-
LOGP(info, "TRKLT: x={} y={} z={} dx={} dy={} dz={} ts:{}+/-{}", originPoint[0], originPoint[1], originPoint[2], cosinesDirector[0], cosinesDirector[1], cosinesDirector[2], mTime.getTimeStamp(), mTime.getTimeStampError());
42+
LOGP(info, "TRKLT: x={} y={} z={} dx={} dy={} dz={} ts:{}+/-{}", originPoint(0), originPoint(1), originPoint(2), cosinesDirector(0), cosinesDirector(1), cosinesDirector(2), mTime.getTimeStamp(), mTime.getTimeStampError());
4743
}
4844

49-
float originPoint[3] = {0, 0, 0};
50-
float cosinesDirector[3] = {0, 0, 0};
45+
SVector3f originPoint;
46+
SVector3f cosinesDirector;
5147
TimeEstBC mTime;
5248

5349
ClassDefNV(Line, 1);
5450
};
5551

56-
GPUhdi() Line::Line(const Tracklet& tracklet, const Cluster* innerClusters, const Cluster* outerClusters) : mTime(tracklet.mTime)
57-
{
58-
originPoint[0] = innerClusters[tracklet.firstClusterIndex].xCoordinate;
59-
originPoint[1] = innerClusters[tracklet.firstClusterIndex].yCoordinate;
60-
originPoint[2] = innerClusters[tracklet.firstClusterIndex].zCoordinate;
61-
62-
cosinesDirector[0] = outerClusters[tracklet.secondClusterIndex].xCoordinate - innerClusters[tracklet.firstClusterIndex].xCoordinate;
63-
cosinesDirector[1] = outerClusters[tracklet.secondClusterIndex].yCoordinate - innerClusters[tracklet.firstClusterIndex].yCoordinate;
64-
cosinesDirector[2] = outerClusters[tracklet.secondClusterIndex].zCoordinate - innerClusters[tracklet.firstClusterIndex].zCoordinate;
65-
66-
float inverseNorm{1.f / o2::gpu::CAMath::Hypot(cosinesDirector[0], cosinesDirector[1], cosinesDirector[2])};
67-
cosinesDirector[0] *= inverseNorm;
68-
cosinesDirector[1] *= inverseNorm;
69-
cosinesDirector[2] *= inverseNorm;
70-
}
71-
72-
// static functions:
73-
inline float Line::getDistanceFromPoint(const Line& line, const std::array<float, 3>& point)
74-
{
75-
float DCASquared{0};
76-
float cdelta{0};
77-
for (int i{0}; i < 3; ++i) {
78-
cdelta -= line.cosinesDirector[i] * (line.originPoint[i] - point[i]);
79-
}
80-
for (int i{0}; i < 3; ++i) {
81-
DCASquared += (line.originPoint[i] - point[i] + line.cosinesDirector[i] * cdelta) *
82-
(line.originPoint[i] - point[i] + line.cosinesDirector[i] * cdelta);
83-
}
84-
return o2::gpu::CAMath::Sqrt(DCASquared);
85-
}
86-
87-
GPUhdi() float Line::getDistanceFromPoint(const Line& line, const float point[3])
88-
{
89-
const float dx = point[0] - line.originPoint[0];
90-
const float dy = point[1] - line.originPoint[1];
91-
const float dz = point[2] - line.originPoint[2];
92-
const float d = (dx * line.cosinesDirector[0]) + (dy * line.cosinesDirector[1]) + (dz * line.cosinesDirector[2]);
93-
94-
const float vx = dx - (d * line.cosinesDirector[0]);
95-
const float vy = dy - (d * line.cosinesDirector[1]);
96-
const float vz = dz - (d * line.cosinesDirector[2]);
97-
98-
return o2::gpu::CAMath::Hypot(vx, vy, vz);
99-
}
100-
101-
GPUhdi() float Line::getDCA(const Line& firstLine, const Line& secondLine, const float precision)
102-
{
103-
const float nx = (firstLine.cosinesDirector[1] * secondLine.cosinesDirector[2]) -
104-
(firstLine.cosinesDirector[2] * secondLine.cosinesDirector[1]);
105-
const float ny = -(firstLine.cosinesDirector[0] * secondLine.cosinesDirector[2]) +
106-
(firstLine.cosinesDirector[2] * secondLine.cosinesDirector[0]);
107-
const float nz = (firstLine.cosinesDirector[0] * secondLine.cosinesDirector[1]) -
108-
(firstLine.cosinesDirector[1] * secondLine.cosinesDirector[0]);
109-
const float norm2 = (nx * nx) + (ny * ny) + (nz * nz);
110-
111-
if (norm2 <= precision * precision) {
112-
return getDistanceFromPoint(firstLine, secondLine.originPoint);
113-
}
114-
115-
const float dx = secondLine.originPoint[0] - firstLine.originPoint[0];
116-
const float dy = secondLine.originPoint[1] - firstLine.originPoint[1];
117-
const float dz = secondLine.originPoint[2] - firstLine.originPoint[2];
118-
const float triple = (dx * nx) + (dy * ny) + (dz * nz);
119-
120-
return o2::gpu::CAMath::Abs(triple) / o2::gpu::CAMath::Sqrt(norm2);
121-
}
122-
123-
GPUhdi() void Line::getDCAComponents(const Line& line, const float point[3], float destArray[6])
124-
{
125-
float cdelta{0.};
126-
for (int i{0}; i < 3; ++i) {
127-
cdelta -= line.cosinesDirector[i] * (line.originPoint[i] - point[i]);
128-
}
129-
130-
destArray[0] = line.originPoint[0] - point[0] + line.cosinesDirector[0] * cdelta;
131-
destArray[3] = line.originPoint[1] - point[1] + line.cosinesDirector[1] * cdelta;
132-
destArray[5] = line.originPoint[2] - point[2] + line.cosinesDirector[2] * cdelta;
133-
destArray[1] = o2::gpu::CAMath::Hypot(destArray[0], destArray[3]);
134-
destArray[2] = o2::gpu::CAMath::Hypot(destArray[0], destArray[5]);
135-
destArray[4] = o2::gpu::CAMath::Hypot(destArray[3], destArray[5]);
136-
}
137-
138-
inline bool Line::operator==(const Line& rhs) const
139-
{
140-
bool val{false};
141-
for (int i{0}; i < 3; ++i) {
142-
val &= this->originPoint[i] == rhs.originPoint[i];
143-
}
144-
return val;
145-
}
146-
147-
inline bool Line::operator!=(const Line& rhs) const
148-
{
149-
return !(*this == rhs);
150-
}
151-
15252
class ClusterLines final
15353
{
54+
using SMatrix3 = ROOT::Math::SMatrix<double, 3, 3, ROOT::Math::MatRepSym<double, 3>>;
55+
using SMatrix3f = ROOT::Math::SMatrix<float, 3, 3, ROOT::Math::MatRepSym<float, 3>>;
56+
using SVector3 = ROOT::Math::SVector<double, 3>;
57+
15458
public:
15559
ClusterLines() = default;
15660
ClusterLines(const int firstLabel, const Line& firstLine, const int secondLabel, const Line& secondLine);
15761
void add(const int lineLabel, const Line& line);
15862
void computeClusterCentroid();
63+
void accumulate(const Line& line);
64+
bool isValid() const noexcept { return mIsValid; }
15965
auto const& getVertex() const { return mVertex; }
160-
std::array<float, 6> getRMS2() const { return mRMS2; }
66+
const float* getRMS2() const { return mRMS2.Array(); }
16167
float getAvgDistance2() const { return mAvgDistance2; }
16268
auto getSize() const noexcept { return mLabels.size(); }
16369
auto& getLabels() noexcept { return mLabels; }
@@ -167,13 +73,14 @@ class ClusterLines final
16773
float getR() const noexcept { return std::sqrt(getR2()); }
16874

16975
protected:
170-
std::array<float, 6> mAMatrix = {}; // AX=B
171-
std::array<float, 3> mBMatrix = {}; // AX=B
172-
std::array<float, 3> mVertex = {}; // cluster centroid position
173-
std::array<float, 6> mRMS2 = {}; // symmetric matrix: diagonal is RMS2
174-
float mAvgDistance2 = 0.f; // substitute for chi2
175-
TimeEstBC mTime; // time stamp
176-
std::vector<int> mLabels; // contributing labels
76+
SMatrix3 mAMatrix; // AX=B, symmetric normal matrix
77+
SVector3 mBMatrix; // AX=B, right-hand side
78+
std::array<float, 3> mVertex = {}; // cluster centroid position
79+
SMatrix3f mRMS2; // symmetric matrix: diagonal is RMS2
80+
float mAvgDistance2 = 0.f; // substitute for chi2
81+
bool mIsValid = false; // true if linear system was solved successfully
82+
TimeEstBC mTime; // time stamp
83+
std::vector<int> mLabels; // contributing labels
17784
};
17885

17986
} // namespace o2::its

Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ struct VertexingParameters {
8787
std::string asString() const;
8888

8989
int nIterations = 1; // Number of vertexing passes to perform
90-
bool allowSingleContribClusters = false;
9190
std::vector<float> LayerZ = {16.333f + 1, 16.333f + 1, 16.333f + 1, 42.140f + 1, 42.140f + 1, 73.745f + 1, 73.745f + 1};
9291
std::vector<float> LayerRadii = {2.33959f, 3.14076f, 3.91924f, 19.6213f, 24.5597f, 34.388f, 39.3329f};
9392
int ZBins{1};

Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,9 @@ namespace o2::its
2222
struct VertexerParamConfig : public o2::conf::ConfigurableParamHelper<VertexerParamConfig> {
2323
bool saveTimeBenchmarks = false; // dump metrics on file
2424

25-
int nIterations = 1; // Number of vertexing passes to perform.
26-
int vertPerRofThreshold = 0; // Maximum number of vertices per ROF to trigger second a iteration.
27-
bool allowSingleContribClusters = false; // attempt to find vertices in case of a single tracklet found.
28-
int deltaRof = 0; // Number of ROFs to be considered for the vertexing.
25+
int nIterations = 1; // Number of vertexing passes to perform.
26+
int vertPerRofThreshold = 0; // Maximum number of vertices per ROF to trigger second a iteration.
27+
int deltaRof = 0; // Number of ROFs to be considered for the vertexing.
2928

3029
// geometrical cuts for tracklet selection
3130
float zCut = 0.002f;

0 commit comments

Comments
 (0)