Project
Loading...
Searching...
No Matches
ClusterLines.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#ifndef O2_ITS_CLUSTERLINES_H
13#define O2_ITS_CLUSTERLINES_H
14
15#include <gsl/span>
16#include <vector>
17#include <array>
18#ifndef GPUCA_GPUCODE
19#include <cmath>
20#else
21#include "GPUCommonAlgorithm.h" // warp reductions of WarpFit
22#endif
23#include "ITStracking/Cluster.h"
24#include "ITStracking/Cell.h"
27#include "GPUCommonDef.h"
28#include "GPUCommonMath.h"
29
30namespace o2::its
31{
32
33struct Line final {
34 GPUhdDefault() Line() = default;
35 Line(const Tracklet&, const Cluster*, const Cluster*);
36 GPUhdi() Line(const float origin[3], const float direction[3], const TimeEstBC& time) : mTime(time)
37 {
38 float norm2 = 0.f;
39 for (int i = 0; i < 3; ++i) {
40 norm2 += direction[i] * direction[i];
41 }
42 const float norm = o2::gpu::GPUCommonMath::Sqrt(norm2);
43 for (int i = 0; i < 3; ++i) {
45 cosinesDirector[i] = norm2 > 0.f ? direction[i] / norm : 0.f;
46 }
47 }
48 Line(const std::array<float, 3>& origin, const std::array<float, 3>& direction, const TimeEstBC& time)
49 : Line(origin.data(), direction.data(), time) {}
50 bool operator==(const Line&) const = default;
51
52 GPUhdi() static float getDistance2FromPoint(const Line& line, const float point[3])
53 {
54 float delta[3], proj = 0.f;
55 for (int i = 0; i < 3; ++i) {
56 delta[i] = point[i] - line.originPoint[i];
57 proj += delta[i] * line.cosinesDirector[i];
58 }
59 float d2 = 0.f;
60 for (int i = 0; i < 3; ++i) {
61 const float residual = delta[i] - proj * line.cosinesDirector[i];
62 d2 += residual * residual;
63 }
64 return d2;
65 }
66
68 GPUhdi() static void getDCAComponents(const Line& line, const float point[3], float out[6])
69 {
70 float delta[3], proj = 0.f;
71 for (int i = 0; i < 3; ++i) {
72 delta[i] = line.originPoint[i] - point[i];
73 proj += delta[i] * line.cosinesDirector[i];
74 }
75 float r[3];
76 for (int i = 0; i < 3; ++i) {
77 r[i] = delta[i] - proj * line.cosinesDirector[i];
78 }
79 out[0] = r[0];
80 out[2] = r[1];
81 out[5] = r[2];
82#ifndef GPUCA_GPUCODE
83 out[1] = std::hypot(r[0], r[1]);
84 out[3] = std::hypot(r[0], r[2]);
85 out[4] = std::hypot(r[1], r[2]);
86#else
87 out[1] = o2::gpu::GPUCommonMath::Hypot(r[0], r[1]);
88 out[3] = o2::gpu::GPUCommonMath::Hypot(r[0], r[2]);
89 out[4] = o2::gpu::GPUCommonMath::Hypot(r[1], r[2]);
90#endif
91 }
92
93 GPUhdi() static bool getZAtBeam(const Line& line, const float beamX, const float beamY, float& z)
94 {
95 const float ux = line.cosinesDirector[0];
96 const float uy = line.cosinesDirector[1];
97 const float den = ux * ux + uy * uy;
99 return false;
100 }
101 const float dx = line.originPoint[0] - beamX;
102 const float dy = line.originPoint[1] - beamY;
103 const float s0 = -(dx * ux + dy * uy) / den;
104 z = line.originPoint[2] + s0 * line.cosinesDirector[2];
105 return true;
106 }
107
108 static float getDistance2FromPoint(const Line& line, const std::array<float, 3>& point)
109 {
110 return getDistance2FromPoint(line, point.data());
111 }
112 static float getDistanceFromPoint(const Line& line, const std::array<float, 3>& point);
113 static float getDCA2(const Line&, const Line&, const float precision = constants::Tolerance);
114 static float getDCA(const Line&, const Line&, const float precision = constants::Tolerance);
115 GPUhdi() bool isEmpty() const noexcept
116 {
117 return originPoint[0] == 0.f && originPoint[1] == 0.f && originPoint[2] == 0.f &&
118 cosinesDirector[0] == 0.f && cosinesDirector[1] == 0.f && cosinesDirector[2] == 0.f;
119 }
120 void print() const;
121
122 float originPoint[3] = {0.f, 0.f, 0.f};
123 float cosinesDirector[3] = {0.f, 0.f, 0.f};
125};
126
127GPUdi() bool getCellLineAtBeam(const CellSeed& cell, const float beamX, const float beamY, const float bz, const float curvatureScale, std::array<float, 3>& origin, std::array<float, 3>& direction)
128{
129 cell.getXYZGlo(origin);
130 if (!cell.getPxPyPzGlo(direction)) {
131 return false;
132 }
134 par.setQ2Pt(par.getQ2Pt() * curvatureScale);
135 std::array<float, 3> dcaOrigin, dcaDirection;
136 if (par.propagateParamToDCA({beamX, beamY, 0.f}, bz)) {
137 par.getXYZGlo(dcaOrigin);
138 if (par.getPxPyPzGlo(dcaDirection)) {
141 }
142 }
143 return true;
144}
145
149{
150 public:
152 GPUhdi() bool add(const Line& line)
153 {
154 const double d0 = line.cosinesDirector[0], d1 = line.cosinesDirector[1], d2 = line.cosinesDirector[2];
155 const double o0 = line.originPoint[0], o1 = line.originPoint[1], o2 = line.originPoint[2];
156 const double det = d0 * d0 + d1 * d1 + d2 * d2; // == 1 for a normalised director
157 if (det <= 0.) {
158 return false;
159 }
160 mA[0] += (det - d0 * d0) / det;
161 mA[1] += (-d0 * d1) / det;
162 mA[2] += (-d0 * d2) / det;
163 mA[3] += (det - d1 * d1) / det;
164 mA[4] += (-d1 * d2) / det;
165 mA[5] += (det - d2 * d2) / det;
166 const double dDotO = d0 * o0 + d1 * o1 + d2 * o2;
167 mB[0] += (d0 * dDotO - det * o0) / det;
168 mB[1] += (d1 * dDotO - det * o1) / det;
169 mB[2] += (d2 * dDotO - det * o2) / det;
170 return true;
171 }
172
174 GPUhdi() bool solve(float vertex[3]) const
175 {
176 const double c00 = mA[3] * mA[5] - mA[4] * mA[4];
177 const double c01 = mA[2] * mA[4] - mA[1] * mA[5];
178 const double c02 = mA[1] * mA[4] - mA[2] * mA[3];
179 const double c11 = mA[0] * mA[5] - mA[2] * mA[2];
180 const double c12 = mA[1] * mA[2] - mA[0] * mA[4];
181 const double c22 = mA[0] * mA[3] - mA[1] * mA[1];
182 const double det = mA[0] * c00 + mA[1] * c01 + mA[2] * c02;
183 if (o2::gpu::GPUCommonMath::Abs(det) < 1.e-12) {
184 return false;
185 }
186 const double invDet = 1. / det;
187 const double x0 = (c00 * mB[0] + c01 * mB[1] + c02 * mB[2]) * invDet;
188 const double x1 = (c01 * mB[0] + c11 * mB[1] + c12 * mB[2]) * invDet;
189 const double x2 = (c02 * mB[0] + c12 * mB[1] + c22 * mB[2]) * invDet;
190 vertex[0] = static_cast<float>(-x0);
191 vertex[1] = static_cast<float>(-x1);
192 vertex[2] = static_cast<float>(-x2);
193 return true;
194 }
195
197 GPUhdi() void computeClusterCentroid() { mIsValid = solve(mVertex); }
198
199 GPUhdi() bool isValid() const noexcept { return mIsValid; }
200 GPUhdi() const float* getVertex() const noexcept { return mVertex; }
201 GPUhdi() int getSize() const noexcept { return mNContributors; }
202 GPUhdi() int getNContributors() const noexcept { return mNContributors; }
203 GPUhdi() const TimeEstBC& getTimeStamp() const noexcept { return mTime; }
204 GPUhdi() float getR2() const noexcept { return (mVertex[0] * mVertex[0]) + (mVertex[1] * mVertex[1]); }
205 GPUhdi() float getR() const noexcept { return o2::gpu::GPUCommonMath::Sqrt(getR2()); }
206 GPUhdi() const float* getRMS2() const noexcept { return mRMS2; } // {XX, XY, YY, XZ, YZ, ZZ}
207 GPUhdi() float getAvgDistance2() const noexcept { return mAvgDistance2; }
208
209 protected:
210 double mA[6] = {0., 0., 0., 0., 0., 0.}; // AX=B, packed symmetric normal matrix
211 double mB[3] = {0., 0., 0.}; // AX=B, right-hand side
212 float mVertex[3] = {0.f, 0.f, 0.f}; // cluster centroid position
213 float mRMS2[6] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; // mean DCA components about the vertex
214 float mAvgDistance2 = 0.f; // mean squared distance about the vertex
215 int mNContributors = 0; // lines accumulated into the normal equations
216 bool mIsValid = false; // true if the linear system was solved successfully
217 TimeEstBC mTime; // intersection of the contributors' time intervals
218};
219
221class ClusterLines final : public LineFit
222{
223 public:
226 ClusterLines(gsl::span<const int> lineIndices, gsl::span<const Line> lines);
227
229 GPUhdi() void add(const Line& line)
230 {
231 if (!LineFit::add(line)) {
232 return;
233 }
234 if (mNContributors <= 0) {
235 mTime = line.mTime;
236 } else {
237 mTime += line.mTime;
238 }
240 }
241
243 GPUhdi() void addResidual(const Line& line) { addResidual(line, mVertex); }
244
246 GPUhdi() void addResidual(const Line& line, const float vertex[3])
247 {
248 float dca[6];
252 const float inv = 1.f / static_cast<float>(mResidualCount);
253 for (int i = 0; i < 6; ++i) {
254 mRMS2[i] += (dca[i] - mRMS2[i]) * inv;
255 }
256 mAvgDistance2 += (d2 - mAvgDistance2) / static_cast<float>(mResidualCount);
257 }
258
259 bool operator==(const ClusterLines& rhs) const noexcept;
260
261 private:
262 int mResidualCount = 0; // lines folded into the running means
263};
264
265#ifdef GPUCA_GPUCODE
268struct WarpFit : public LineFit {
269 uint32_t tLo = 0, tHi = 0xffffffffu;
270
271 GPUdi() void add(const Line& l)
272 {
273 if (LineFit::add(l)) {
274 tLo = o2::gpu::GPUCommonMath::Max(tLo, l.mTime.lower());
275 tHi = o2::gpu::GPUCommonMath::Min(tHi, l.mTime.upper());
276 ++mNContributors;
277 }
278 }
279
280 template <int Width>
281 GPUdi() void reduce()
282 {
283 for (int i = 0; i < 6; ++i) {
284 mA[i] = warp_reduce_add<Width>(mA[i]);
285 }
286 for (int i = 0; i < 3; ++i) {
287 mB[i] = warp_reduce_add<Width>(mB[i]);
288 }
289 tLo = warp_reduce_max<Width>(tLo);
290 tHi = warp_reduce_min<Width>(tHi);
291 mNContributors = warp_reduce_add<Width>(mNContributors);
292 mTime = TimeEstBC{tLo, tHi - tLo};
293 }
294
295 GPUdi() void addResidual(const Line& l, const float vertex[3])
296 {
297 float dca[6];
298 Line::getDCAComponents(l, vertex, dca);
299 for (int i = 0; i < 6; ++i) {
300 rms2Sum[i] += dca[i];
301 }
302 dist2Sum += Line::getDistance2FromPoint(l, vertex);
303 }
304
306 template <int Width>
307 GPUdi() void reduceResiduals(const int n)
308 {
309 for (int i = 0; i < 6; ++i) {
310 mRMS2[i] = warp_reduce_add<Width>(rms2Sum[i]) / n;
311 }
312 mAvgDistance2 = warp_reduce_add<Width>(dist2Sum) / n;
313 }
314
315 double rms2Sum[6] = {0., 0., 0., 0., 0., 0.};
316 double dist2Sum = 0.;
317};
318#endif
319
320} // namespace o2::its
321#endif /* O2_ITS_CLUSTERLINES_H */
uint64_t vertex
Definition RawEventData.h:9
int32_t i
#define GPUdi()
CellSeed: connections of three clusters.
Definition Cell.h:81
Least-squares vertex fit over a set of lines (the normal equations AX = -B).
GPUhdDefault() ClusterLines()=default
GPUhdi() void addResidual(const Line &line)
Running-mean update of the RMS2 and average distance about the stored vertex.
bool operator==(const ClusterLines &rhs) const noexcept
GPUhdi() void addResidual(const Line &line
Running-mean update about an externally solved vertex.
Line::getDCAComponents(line, vertex, dca)
const float vertex[3]
GPUhdi() float getR2() const noexcept
GPUhdi() int getNContributors() const noexcept
GPUhdi() const float *getRMS2() const noexcept
GPUhdi() bool solve(float vertex[3]) const
Solve the symmetric 3x3 system into vertex (= -A^-1 B); false if it is singular.
GPUhdi() const TimeEstBC &getTimeStamp() const noexcept
GPUhdi() bool add(const Line &line)
Accumulate one line.
GPUhdi() const float *getVertex() const noexcept
GPUhdi() float getAvgDistance2() const noexcept
GPUhdi() bool isValid() const noexcept
GPUhdi() float getR() const noexcept
GPUhdi() void computeClusterCentroid()
Solve into the stored vertex, setting the validity flag.
GPUhdi() int getSize() const noexcept
GLdouble n
Definition glcorearb.h:1982
GLuint GLfloat GLfloat GLfloat x1
Definition glcorearb.h:5034
GLenum array
Definition glcorearb.h:4274
GLboolean * data
Definition glcorearb.h:298
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLuint GLfloat x0
Definition glcorearb.h:5034
GLboolean r
Definition glcorearb.h:1233
GLenum GLint GLint * precision
Definition glcorearb.h:1899
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s0
Definition glcorearb.h:5034
constexpr float Tolerance
Definition Constants.h:30
const float beamX
const float const float const float const float curvatureScale
o2::track::TrackParametrization< float > par
std::array< float, 3 > dcaOrigin
const float const float beamY
const float const float const float bz
const float const float const float const float std::array< float, 3 > std::array< float, 3 > & direction
std::array< float, 3 > dcaDirection
const float const float const float const float std::array< float, 3 > & origin
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
bool isValid(std::string alias)
const float uy
GPUhdi() bool isEmpty() const noexcept
void print() const
const float direction[3]
bool operator==(const Line &) const =default
static float getDistance2FromPoint(const Line &line, const std::array< float, 3 > &point)
const float den
GPUhdi() static float getDistance2FromPoint(const Line &line
float cosinesDirector[3]
const float dx
static float getDCA2(const Line &, const Line &, const float precision=constants::Tolerance)
static float getDCA(const Line &, const Line &, const float precision=constants::Tolerance)
const float dy
GPUhdi() Line(const float origin[3]
TimeEstBC mTime
const float point[3]
const float float out[6]
GPUhdi() static void getDCAComponents(const Line &line
Packed symmetric DCA components in {XX, XY, YY, XZ, YZ, ZZ} order.
Line(const std::array< float, 3 > &origin, const std::array< float, 3 > &direction, const TimeEstBC &time)
GPUhdDefault() Line()=default
const float const TimeEstBC & time
static float getDistanceFromPoint(const Line &line, const std::array< float, 3 > &point)
const float beamX
float originPoint[3]
const float norm
const float const float beamY