|
| 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 | +/// \file ClusterLinesGPU.h |
| 13 | +/// \brief device-side line + N-line vertex fit for the GPU seeding vertexer. |
| 14 | + |
| 15 | +#ifndef O2_ITS_CLUSTERLINES_GPU_H |
| 16 | +#define O2_ITS_CLUSTERLINES_GPU_H |
| 17 | + |
| 18 | +#include "DataFormatsITS/TimeEstBC.h" |
| 19 | +#include "GPUCommonDef.h" |
| 20 | +#include "GPUCommonMath.h" |
| 21 | +#include "ITStracking/LineProjection.h" |
| 22 | + |
| 23 | +namespace o2::its::gpu |
| 24 | +{ |
| 25 | + |
| 26 | +using LineWindow = o2::its::LineWindow; |
| 27 | + |
| 28 | +struct LineProjSoA { |
| 29 | + float* z{nullptr}; // projected z at the beamline; sort key and binary-search key, kept dense |
| 30 | + o2::its::TimeEstBC* t{nullptr}; // time interval of the line |
| 31 | + int* idx{nullptr}; // sorted slot -> original line index |
| 32 | + int* rof{nullptr}; // ROF of the line |
| 33 | +}; |
| 34 | + |
| 35 | +struct VertexCand { |
| 36 | + float x, y, z; |
| 37 | + float rms2[6]; |
| 38 | + float avgDist2; |
| 39 | + int nGood; |
| 40 | + float seed[3]; |
| 41 | + o2::its::TimeEstBC time; |
| 42 | + int size; |
| 43 | + uint8_t ok; // 1 if the candidate passed the fit cuts |
| 44 | + uint8_t keep; // 1 if it survived duplicate suppression (subset of ok) |
| 45 | + uint8_t fine; |
| 46 | +}; |
| 47 | + |
| 48 | +// Device-side line: origin point + unit direction, with a time stamp |
| 49 | +struct GPULine { |
| 50 | + GPUhdDefault() GPULine() = default; |
| 51 | + |
| 52 | + GPUhdi() GPULine(const float origin[3], const float direction[3], const o2::its::TimeEstBC& t) : mTime(t) |
| 53 | + { |
| 54 | + const float norm = o2::gpu::GPUCommonMath::Sqrt(direction[0] * direction[0] + |
| 55 | + direction[1] * direction[1] + |
| 56 | + direction[2] * direction[2]); |
| 57 | + const float inv = norm > 0.f ? 1.f / norm : 0.f; |
| 58 | + for (int i = 0; i < 3; ++i) { |
| 59 | + originPoint[i] = origin[i]; |
| 60 | + cosinesDirector[i] = direction[i] * inv; |
| 61 | + } |
| 62 | + } |
| 63 | + |
| 64 | + // Squared distance from a point to the (infinite) line: |delta - (delta.u) u|^2 |
| 65 | + GPUhdi() static float getDistance2FromPoint(const GPULine& line, const float point[3]) |
| 66 | + { |
| 67 | + float delta[3]; |
| 68 | + float proj = 0.f; |
| 69 | + for (int i = 0; i < 3; ++i) { |
| 70 | + delta[i] = point[i] - line.originPoint[i]; |
| 71 | + proj += delta[i] * line.cosinesDirector[i]; |
| 72 | + } |
| 73 | + float d2 = 0.f; |
| 74 | + for (int i = 0; i < 3; ++i) { |
| 75 | + const float residual = delta[i] - proj * line.cosinesDirector[i]; |
| 76 | + d2 += residual * residual; |
| 77 | + } |
| 78 | + return d2; |
| 79 | + } |
| 80 | + |
| 81 | + GPUhdi() static void getDCAComponents(const GPULine& line, const float point[3], float out[6]) |
| 82 | + { |
| 83 | + float delta[3]; |
| 84 | + float proj = 0.f; |
| 85 | + for (int i = 0; i < 3; ++i) { |
| 86 | + delta[i] = line.originPoint[i] - point[i]; |
| 87 | + proj += delta[i] * line.cosinesDirector[i]; |
| 88 | + } |
| 89 | + float r[3]; |
| 90 | + for (int i = 0; i < 3; ++i) { |
| 91 | + r[i] = delta[i] - proj * line.cosinesDirector[i]; |
| 92 | + } |
| 93 | + out[0] = r[0]; // (0,0) XX |
| 94 | + out[1] = o2::gpu::GPUCommonMath::Hypot(r[0], r[1]); // (0,1) XY |
| 95 | + out[2] = r[1]; // (1,1) YY |
| 96 | + out[3] = o2::gpu::GPUCommonMath::Hypot(r[0], r[2]); // (0,2) XZ |
| 97 | + out[4] = o2::gpu::GPUCommonMath::Hypot(r[1], r[2]); // (1,2) YZ |
| 98 | + out[5] = r[2]; // (2,2) ZZ |
| 99 | + } |
| 100 | + |
| 101 | + float originPoint[3] = {0.f, 0.f, 0.f}; |
| 102 | + float cosinesDirector[3] = {0.f, 0.f, 0.f}; |
| 103 | + o2::its::TimeEstBC mTime; |
| 104 | +}; |
| 105 | + |
| 106 | +class GPUClusterLinesFit |
| 107 | +{ |
| 108 | + public: |
| 109 | + GPUhdDefault() GPUClusterLinesFit() = default; |
| 110 | + |
| 111 | + // Add one line's contribution: A_ij += (delta_ij*|d|^2 - d_i*d_j)/|d|^2, |
| 112 | + // b_i += (d_i*(d.o) - |d|^2*o_i)/|d|^2. For a unit director |d|^2 == 1. |
| 113 | + GPUhdi() void add(const GPULine& line) |
| 114 | + { |
| 115 | + const double d0 = line.cosinesDirector[0], d1 = line.cosinesDirector[1], d2 = line.cosinesDirector[2]; |
| 116 | + const double o0 = line.originPoint[0], o1 = line.originPoint[1], o2 = line.originPoint[2]; |
| 117 | + const double det = d0 * d0 + d1 * d1 + d2 * d2; // == 1 for a normalised director |
| 118 | + if (det <= 0.) { |
| 119 | + return; |
| 120 | + } |
| 121 | + if (mNContributors <= 0) { |
| 122 | + mTime = line.mTime; |
| 123 | + } else { |
| 124 | + mTime += line.mTime; |
| 125 | + } |
| 126 | + mA[0] += (det - d0 * d0) / det; |
| 127 | + mA[1] += (-d0 * d1) / det; |
| 128 | + mA[2] += (-d0 * d2) / det; |
| 129 | + mA[3] += (det - d1 * d1) / det; |
| 130 | + mA[4] += (-d1 * d2) / det; |
| 131 | + mA[5] += (det - d2 * d2) / det; |
| 132 | + const double dDotO = d0 * o0 + d1 * o1 + d2 * o2; |
| 133 | + mB[0] += (d0 * dDotO - det * o0) / det; |
| 134 | + mB[1] += (d1 * dDotO - det * o1) / det; |
| 135 | + mB[2] += (d2 * dDotO - det * o2) / det; |
| 136 | + ++mNContributors; |
| 137 | + } |
| 138 | + |
| 139 | + // Solve the symmetric system and write the vertex (= -A^-1 B) |
| 140 | + GPUhdi() bool solve(float vertex[3]) const |
| 141 | + { |
| 142 | + const double a = mA[0], b = mA[1], c = mA[2], d = mA[3], e = mA[4], f = mA[5]; |
| 143 | + const double c00 = d * f - e * e; |
| 144 | + const double c01 = c * e - b * f; |
| 145 | + const double c02 = b * e - c * d; |
| 146 | + const double c11 = a * f - c * c; |
| 147 | + const double c12 = b * c - a * e; |
| 148 | + const double c22 = a * d - b * b; |
| 149 | + const double det = a * c00 + b * c01 + c * c02; |
| 150 | + if (o2::gpu::GPUCommonMath::Abs(det) < 1.e-12) { |
| 151 | + return false; |
| 152 | + } |
| 153 | + const double invDet = 1. / det; |
| 154 | + const double x0 = (c00 * mB[0] + c01 * mB[1] + c02 * mB[2]) * invDet; |
| 155 | + const double x1 = (c01 * mB[0] + c11 * mB[1] + c12 * mB[2]) * invDet; |
| 156 | + const double x2 = (c02 * mB[0] + c12 * mB[1] + c22 * mB[2]) * invDet; |
| 157 | + vertex[0] = static_cast<float>(-x0); |
| 158 | + vertex[1] = static_cast<float>(-x1); |
| 159 | + vertex[2] = static_cast<float>(-x2); |
| 160 | + return true; |
| 161 | + } |
| 162 | + |
| 163 | + GPUhdi() void addResidual(const GPULine& line, const float vertex[3]) |
| 164 | + { |
| 165 | + float dca[6]; |
| 166 | + GPULine::getDCAComponents(line, vertex, dca); |
| 167 | + const float d2 = GPULine::getDistance2FromPoint(line, vertex); |
| 168 | + ++mResidualCount; |
| 169 | + const float inv = 1.f / static_cast<float>(mResidualCount); |
| 170 | + for (int i = 0; i < 6; ++i) { |
| 171 | + mRMS2[i] += (dca[i] - mRMS2[i]) * inv; |
| 172 | + } |
| 173 | + mAvgDistance2 += (d2 - mAvgDistance2) * inv; |
| 174 | + } |
| 175 | + |
| 176 | + GPUhdi() int getNContributors() const { return mNContributors; } |
| 177 | + GPUhdi() const float* getRMS2() const { return mRMS2; } // Packed symmetric covariance in {XX, XY, YY, XZ, YZ, ZZ} order |
| 178 | + GPUhdi() float getAvgDistance2() const { return mAvgDistance2; } |
| 179 | + GPUhdi() const o2::its::TimeEstBC& getTimeStamp() const { return mTime; } |
| 180 | + |
| 181 | + private: |
| 182 | + double mA[6] = {0., 0., 0., 0., 0., 0.}; |
| 183 | + double mB[3] = {0., 0., 0.}; |
| 184 | + int mNContributors = 0; |
| 185 | + float mRMS2[6] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; |
| 186 | + float mAvgDistance2 = 0.f; |
| 187 | + int mResidualCount = 0; |
| 188 | + o2::its::TimeEstBC mTime; |
| 189 | +}; |
| 190 | + |
| 191 | +} // namespace o2::its::gpu |
| 192 | + |
| 193 | +#endif /* O2_ITS_CLUSTERLINES_GPU_H */ |
0 commit comments