Project
Loading...
Searching...
No Matches
ClusterLines.cxx
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#include <cmath>
13#include "Framework/Logger.h"
15
16namespace o2::its
17{
18
19Line::Line(const Tracklet& tracklet, const Cluster* innerClusters, const Cluster* outerClusters) : mTime(tracklet.mTime)
20{
21 const auto& inner = innerClusters[tracklet.firstClusterIndex];
22 const auto& outer = outerClusters[tracklet.secondClusterIndex];
23
24 originPoint = SVector3f(inner.xCoordinate, inner.yCoordinate, inner.zCoordinate);
25 cosinesDirector = SVector3f(outer.xCoordinate - inner.xCoordinate,
26 outer.yCoordinate - inner.yCoordinate,
27 outer.zCoordinate - inner.zCoordinate);
28 cosinesDirector /= std::sqrt(ROOT::Math::Dot(cosinesDirector, cosinesDirector));
29}
30
31float Line::getDistance2FromPoint(const Line& line, const std::array<float, 3>& point)
32{
33 const SVector3f p(point.data(), 3);
34 const SVector3f delta = p - line.originPoint;
35 const float proj = ROOT::Math::Dot(delta, line.cosinesDirector);
36 const SVector3f residual = delta - proj * line.cosinesDirector;
37 return ROOT::Math::Dot(residual, residual);
38}
39
40float Line::getDistanceFromPoint(const Line& line, const std::array<float, 3>& point)
41{
42 return std::sqrt(getDistance2FromPoint(line, point));
43}
44
45float Line::getDCA2(const Line& firstLine, const Line& secondLine, const float precision)
46{
47 const SVector3f n = ROOT::Math::Cross(firstLine.cosinesDirector, secondLine.cosinesDirector);
48 const float norm2 = ROOT::Math::Dot(n, n);
49
50 if (norm2 <= precision * precision) {
51 // lines are parallel, fall back to point-to-line distance
52 const SVector3f d = secondLine.originPoint - firstLine.originPoint;
53 const float proj = ROOT::Math::Dot(d, firstLine.cosinesDirector);
54 const SVector3f residual = d - proj * firstLine.cosinesDirector;
55 return ROOT::Math::Dot(residual, residual);
56 }
57
58 const SVector3f delta = secondLine.originPoint - firstLine.originPoint;
59 const float numerator = ROOT::Math::Dot(delta, n);
60 return (numerator * numerator) / norm2;
61}
62
63float Line::getDCA(const Line& firstLine, const Line& secondLine, const float precision)
64{
65 return std::sqrt(getDCA2(firstLine, secondLine, precision));
66}
67
68Line::SMatrix3f Line::getDCAComponents(const Line& line, const std::array<float, 3>& point)
69{
70 const SVector3f p(point.data(), 3);
71 const SVector3f delta = line.originPoint - p;
72 const float proj = ROOT::Math::Dot(line.cosinesDirector, delta);
73 const SVector3f residual = delta - proj * line.cosinesDirector;
74
75 // symmetric 3x3: diagonal = residual components, off-diagonal = 2D projected distances
77 m(0, 0) = residual(0);
78 m(1, 1) = residual(1);
79 m(2, 2) = residual(2);
80 m(0, 1) = std::hypot(m(0, 0), m(1, 1));
81 m(0, 2) = std::hypot(m(0, 0), m(2, 2));
82 m(1, 2) = std::hypot(m(1, 1), m(2, 2));
83 return m;
84}
85
86bool Line::isEmpty() const noexcept
87{
88 return ROOT::Math::Dot(originPoint, originPoint) == 0.f &&
89 ROOT::Math::Dot(cosinesDirector, cosinesDirector) == 0.f;
90}
91
92void Line::print() const
93{
94 LOGP(info, "\tLine: originPoint = ({}, {}, {}), cosinesDirector = ({}, {}, {}) ts={}+-{}",
97 mTime.getTimeStamp(), mTime.getTimeStampError());
98}
99
100// Accumulate the weighted normal equation contributions (A matrix and B vector)
101// from a single line into the running sums. The covariance is assumed to be
102// diagonal and uniform ({1,1,1}) so the weights simplify accordingly.
103// The A matrix entry (i,j) = (delta_ij - d_i*d_j) / det, and the B vector
104// entry b_i = sum_j d_j*(d_j*o_i - d_i*o_j) / det, where d = cosinesDirector
105// and o = originPoint.
107{
108 const ROOT::Math::SVector<double, 3> d(line.cosinesDirector(0), line.cosinesDirector(1), line.cosinesDirector(2));
109 const ROOT::Math::SVector<double, 3> o(line.originPoint(0), line.originPoint(1), line.originPoint(2));
110
111 // == 1 for normalised directors, kept for generality
112 const double det = ROOT::Math::Dot(d, d);
113
114 // A matrix (symmetric): A_ij = (delta_ij * |d|^2 - d_i * d_j) / det
115 for (int i = 0; i < 3; ++i) {
116 for (int j = i; j < 3; ++j) {
117 mAMatrix(i, j) += ((i == j ? det : 0.) - d(i) * d(j)) / det;
118 }
119 }
120
121 // B vector: b_i = (d_i * dot(d,o) - |d|^2 * o_i) / det
122 const double dDotO = ROOT::Math::Dot(d, o);
123 for (int i = 0; i < 3; ++i) {
124 mBMatrix(i) += (d(i) * dDotO - det * o(i)) / det;
125 }
126}
127
128ClusterLines::ClusterLines(const int firstLabel, const Line& firstLine, const int secondLabel, const Line& secondLine) : mTime(firstLine.mTime)
129{
130 mTime += secondLine.mTime;
131
132 mLabels.push_back(firstLabel);
133 if (secondLabel > 0) {
134 mLabels.push_back(secondLabel); // don't add info in case of beamline used
135 }
136
137 accumulate(firstLine);
138 accumulate(secondLine);
140
141 // RMS2: running mean update
143 const auto tmpRMS2 = Line::getDCAComponents(secondLine, mVertex);
144 mRMS2 += (tmpRMS2 - mRMS2) * (1.f / static_cast<float>(getSize()));
145
146 // AvgDistance2
149}
150
151ClusterLines::ClusterLines(gsl::span<const int> lineLabels, gsl::span<const Line> lines)
152{
153 if (lineLabels.size() < 2) {
154 return;
155 }
156
157 mLabels.reserve(lineLabels.size());
158 mTime = lines[lineLabels[0]].mTime;
159 for (size_t index = 0; index < lineLabels.size(); ++index) {
160 const auto lineLabel = lineLabels[index];
161 if (index > 0) {
162 mTime += lines[lineLabel].mTime;
163 }
164 mLabels.push_back(lineLabel);
165 accumulate(lines[lineLabel]);
166 }
167
169 if (!mIsValid) {
170 return;
171 }
172
173 mRMS2 = Line::getDCAComponents(lines[lineLabels[0]], mVertex);
174 mAvgDistance2 = Line::getDistance2FromPoint(lines[lineLabels[0]], mVertex);
175 for (size_t index = 1; index < lineLabels.size(); ++index) {
176 const auto lineLabel = lineLabels[index];
177 const auto tmpRMS2 = Line::getDCAComponents(lines[lineLabel], mVertex);
178 mRMS2 += (tmpRMS2 - mRMS2) * (1.f / static_cast<float>(index + 1));
179 mAvgDistance2 += (Line::getDistance2FromPoint(lines[lineLabel], mVertex) - mAvgDistance2) / static_cast<float>(index + 1);
180 }
181}
182
183void ClusterLines::add(const int lineLabel, const Line& line)
184{
185 mTime += line.mTime;
186 mLabels.push_back(lineLabel);
187
188 accumulate(line);
191}
192
194{
195 // Solve the 3x3 symmetric linear system AX = -B using SMatrix inversion.
196 // Invert() returns false if the matrix is singular or ill-conditioned.
197 SMatrix3 invA{mAMatrix};
198 mIsValid = invA.Invert();
199 if (!mIsValid) {
200 return;
201 }
202
203 SVector3 result = invA * mBMatrix;
204 mVertex[0] = static_cast<float>(-result(0));
205 mVertex[1] = static_cast<float>(-result(1));
206 mVertex[2] = static_cast<float>(-result(2));
207}
208
209bool ClusterLines::operator==(const ClusterLines& rhs) const noexcept
210{
211 return mRMS2 == rhs.mRMS2 &&
212 mVertex == rhs.mVertex &&
213 mLabels == rhs.mLabels &&
214 mAvgDistance2 == rhs.mAvgDistance2;
215}
216
217} // namespace o2::its
int32_t i
uint32_t j
Definition RawData.h:0
void accumulate(const Line &line)
bool operator==(const ClusterLines &rhs) const noexcept
auto getSize() const noexcept
void add(const int lineLabel, const Line &line)
std::vector< int > mLabels
std::array< float, 3 > mVertex
GLdouble n
Definition glcorearb.h:1982
const GLfloat * m
Definition glcorearb.h:4066
GLuint64EXT * result
Definition glcorearb.h:5662
GLuint index
Definition glcorearb.h:781
GLenum GLint GLint * precision
Definition glcorearb.h:1899
SVector3f cosinesDirector
void print() const
static float getDistance2FromPoint(const Line &line, const std::array< float, 3 > &point)
bool isEmpty() const noexcept
static float getDCA2(const Line &, const Line &, const float precision=constants::Tolerance)
static float getDCA(const Line &, const Line &, const float precision=constants::Tolerance)
TimeEstBC mTime
ROOT::Math::SVector< float, 3 > SVector3f
static float getDistanceFromPoint(const Line &line, const std::array< float, 3 > &point)
SVector3f originPoint
static SMatrix3f getDCAComponents(const Line &line, const std::array< float, 3 > &point)
Line()=default