25constexpr std::size_t NMeasurementCoordinates = 9;
26constexpr std::size_t NCoordinates = NMeasurementCoordinates;
27constexpr std::size_t NAdjacentKinks = 4;
29using KinkVector = std::array<float, NAdjacentKinks>;
30using KinkCovariance = std::array<std::array<float, NAdjacentKinks>, NAdjacentKinks>;
36 static DualNumber variable(
float val, std::size_t
index)
noexcept
44DualNumber
operator+(
const DualNumber& lhs,
const DualNumber& rhs)
noexcept
47 for (std::size_t
i = 0;
i < NCoordinates; ++
i) {
53DualNumber
operator-(
const DualNumber& lhs,
const DualNumber& rhs)
noexcept
56 for (std::size_t
i = 0;
i < NCoordinates; ++
i) {
65 for (std::size_t
i = 0;
i < NCoordinates; ++
i) {
71DualNumber
operator*(
const DualNumber& lhs,
const DualNumber& rhs)
noexcept
74 for (std::size_t
i = 0;
i < NCoordinates; ++
i) {
80DualNumber operator/(
const DualNumber& lhs,
const DualNumber& rhs)
noexcept
82 const float inverse = 1. /
rhs.value;
84 for (std::size_t
i = 0;
i < NCoordinates; ++
i) {
90DualNumber squareRoot(
const DualNumber& argument)
noexcept
92 const float root = std::sqrt(argument.value);
94 const float scale = 0.5 / root;
95 for (std::size_t
i = 0;
i < NCoordinates; ++
i) {
96 result.derivative[
i] = scale * argument.derivative[
i];
101DualNumber arcSine(
const DualNumber& argument)
noexcept
103 DualNumber
result{std::asin(argument.value)};
104 const float scale = 1. / std::sqrt(1. - argument.value * argument.value);
105 for (std::size_t
i = 0;
i < NCoordinates; ++
i) {
106 result.derivative[
i] = scale * argument.derivative[
i];
111DualNumber arcTangent2(
const DualNumber&
y,
const DualNumber&
x)
noexcept
113 DualNumber
result{std::atan2(
y.value,
x.value)};
114 const float denominator =
x.value *
x.value +
y.value *
y.value;
115 for (std::size_t
i = 0;
i < NCoordinates; ++
i) {
116 result.derivative[
i] = (
x.value *
y.derivative[
i] -
y.value *
x.derivative[
i]) / denominator;
121struct SegmentGeometry {
130bool makeSegmentGeometry(
const DualNumber& transverseCurvature,
const DualNumber& chordLength,
131 const DualNumber& deltaZ, SegmentGeometry&
result)
noexcept
133 const DualNumber halfSine = DualNumber{0.5} * transverseCurvature * chordLength;
134 if (std::abs(halfSine.value) >= 1.) {
138 const DualNumber halfSine2 = halfSine * halfSine;
139 const DualNumber halfSine4 = halfSine2 * halfSine2;
140 DualNumber asinOverArgument;
141 DualNumber angleCotangent;
142 const DualNumber halfAngle = arcSine(halfSine);
143 if (std::abs(halfSine.value) < 1.e-4) {
144 asinOverArgument = DualNumber{1.} + halfSine2 * DualNumber{1. / 6.} + halfSine4 * DualNumber{3. / 40.};
145 angleCotangent = DualNumber{1.} - halfSine2 * DualNumber{1. / 3.} - halfSine4 * DualNumber{2. / 15.};
147 asinOverArgument = halfAngle / halfSine;
148 angleCotangent = halfAngle * squareRoot(DualNumber{1.} - halfSine2) / halfSine;
151 const DualNumber
bendingAngle = DualNumber{2.} * halfAngle;
156 const DualNumber
index = DualNumber{1.} /
165struct TripletGeometry {
172bool makeTripletGeometry(
const std::array<GlobalMeasurement, 3>& measurements,
173 TripletGeometry&
result)
noexcept
175 std::array<std::array<DualNumber, 3>, 3> point{};
176 for (std::size_t hit = 0; hit < measurements.size(); ++hit) {
177 const std::array<float, 3> position{
178 measurements[hit].x, measurements[hit].y, measurements[hit].z};
179 for (std::size_t coordinate = 0; coordinate < 3; ++coordinate) {
180 const std::size_t
index = 3 * hit + coordinate;
181 point[hit][coordinate] = DualNumber::variable(position[coordinate],
index);
185 const DualNumber dx01 = point[1][0] - point[0][0];
186 const DualNumber dy01 = point[1][1] - point[0][1];
187 const DualNumber dz01 = point[1][2] - point[0][2];
188 const DualNumber dx12 = point[2][0] - point[1][0];
189 const DualNumber dy12 = point[2][1] - point[1][1];
190 const DualNumber dz12 = point[2][2] - point[1][2];
191 const DualNumber dx02 = point[2][0] - point[0][0];
192 const DualNumber dy02 = point[2][1] - point[0][1];
193 const DualNumber length01 = squareRoot(dx01 * dx01 + dy01 * dy01);
194 const DualNumber length12 = squareRoot(dx12 * dx12 + dy12 * dy12);
195 const DualNumber length02 = squareRoot(dx02 * dx02 + dy02 * dy02);
196 if (length01.value <= 0. ||
197 length12.value <= 0. || length02.value <= 0.) {
201 const DualNumber
cross = dx01 * dy12 - dy01 * dx12;
202 const DualNumber transverseCurvature = DualNumber{2.} *
cross / (length01 * length12 * length02);
203 SegmentGeometry firstSegment;
204 SegmentGeometry secondSegment;
205 if (!makeSegmentGeometry(transverseCurvature, length01, dz01, firstSegment) ||
206 !makeSegmentGeometry(transverseCurvature, length12, dz12, secondSegment)) {
210 const DualNumber theta01 = arcTangent2(firstSegment.transverseArcLength, dz01);
211 const DualNumber theta12 = arcTangent2(secondSegment.transverseArcLength, dz12);
212 const DualNumber
phiTilde = DualNumber{0.5} *
213 (firstSegment.bendingAngle * firstSegment.index +
214 secondSegment.bendingAngle * secondSegment.index);
215 const DualNumber
thetaTilde = theta12 - theta01 +
216 (DualNumber{1.} - secondSegment.index) * secondSegment.cotangentTheta -
217 (DualNumber{1.} - firstSegment.index) * firstSegment.cotangentTheta;
218 const DualNumber
rhoPhi = DualNumber{-0.5} *
219 (firstSegment.transverseArcLength * firstSegment.index / firstSegment.sineTheta +
220 secondSegment.transverseArcLength * secondSegment.index / secondSegment.sineTheta);
223 const float maximumHalfSine = 0.5 * std::abs(transverseCurvature.value) *
224 std::max(length01.value, length12.value);
225 if (maximumHalfSine < 1.e-4) {
227 (length12 * length12 * secondSegment.cosineTheta -
228 length01 * length01 * firstSegment.cosineTheta) /
231 rhoTheta = ((DualNumber{1.} - firstSegment.index) * firstSegment.cotangentTheta / firstSegment.sineTheta -
232 (DualNumber{1.} - secondSegment.index) * secondSegment.cotangentTheta / secondSegment.sineTheta) /
243float covarianceContraction(
const std::array<float, 3>&
left,
244 const GlobalCovariance3F& covariance,
245 const std::array<float, 3>&
right)
noexcept
247 return left[0] * (covariance.xx *
right[0] + covariance.xy *
right[1] + covariance.xz *
right[2]) +
248 left[1] * (covariance.xy *
right[0] + covariance.yy *
right[1] + covariance.yz *
right[2]) +
249 left[2] * (covariance.xz *
right[0] + covariance.yz *
right[1] + covariance.zz *
right[2]);
252bool choleskyDecompose(
const KinkCovariance& covariance,
253 KinkCovariance&
lower)
noexcept
255 for (std::size_t
row = 0;
row < NAdjacentKinks; ++
row) {
256 for (std::size_t column = 0; column <=
row; ++column) {
257 float value = covariance[
row][column];
258 for (std::size_t k = 0; k < column; ++k) {
274bool choleskySolve(
const KinkCovariance&
lower,
const KinkVector&
right,
275 KinkVector& solution)
noexcept
277 KinkVector intermediate{};
278 for (std::size_t
row = 0;
row < NAdjacentKinks; ++
row) {
280 for (std::size_t column = 0; column <
row; ++column) {
285 for (
int row =
static_cast<int>(NAdjacentKinks) - 1;
row >= 0; --
row) {
287 for (std::size_t column =
static_cast<std::size_t
>(
row) + 1;
288 column < NAdjacentKinks; ++column) {
296float dotProduct(
const KinkVector&
left,
const KinkVector&
right)
noexcept
299 for (std::size_t
i = 0;
i < NAdjacentKinks; ++
i) {
305bool referenceSinTheta(
const GlobalMeasurement&
first,
306 const GlobalMeasurement& third,
309 const float dx = third.x -
first.x;
310 const float dy = third.y -
first.y;
311 const float dz = third.z -
first.z;
312 const float transverse = std::hypot(dx, dy);
313 const float length = std::hypot(transverse, dz);
321 const std::array<GlobalMeasurement, 3>& measurements,
324 TripletGeometry geometry;
325 if (!makeTripletGeometry(measurements, geometry)) {
328 const float kappaReference = -geometry.phiTilde.value / geometry.rhoPhi.value;
330 {geometry.thetaTilde.value, geometry.phiTilde.value},
331 {geometry.rhoTheta.value, geometry.rhoPhi.value},
334 for (std::size_t hit = 0; hit < measurements.size(); ++hit) {
335 for (std::size_t coordinate = 0; coordinate < 3; ++coordinate) {
336 const std::size_t
index = 3 * hit + coordinate;
337 const float gradientTheta = geometry.thetaTilde.derivative[
index] +
338 kappaReference * geometry.rhoTheta.derivative[
index];
339 const float gradientPhi = geometry.phiTilde.derivative[
index] +
340 kappaReference * geometry.rhoPhi.derivative[
index];
341 scratch.h[hit].theta[coordinate] = gradientTheta;
342 scratch.h[hit].phi[coordinate] = gradientPhi;
345 if (!scratch.isValid()) {
355 const std::array<GlobalMeasurement, 4>& measurements,
356 const std::array<float, 2>& angularVariance,
360 if (!referenceSinTheta(measurements[0], measurements[2],
sineTheta[0]) ||
361 !referenceSinTheta(measurements[1], measurements[3],
sineTheta[1])) {
365 const KinkVector psi{
366 firstFactor.psi.theta, firstFactor.psi.phi,
367 secondFactor.psi.theta, secondFactor.psi.phi};
368 const KinkVector rho{
369 firstFactor.rho.theta, firstFactor.rho.phi,
370 secondFactor.rho.theta, secondFactor.rho.phi};
371 KinkCovariance covariance{};
372 covariance[0][0] = angularVariance[0];
374 covariance[2][2] = angularVariance[1];
379 std::array<std::array<std::array<float, 3>, NAdjacentKinks>, 4> gradients{};
380 for (std::size_t coordinate = 0; coordinate < 3; ++coordinate) {
381 for (std::size_t hit = 0; hit < 3; ++hit) {
382 gradients[hit][0][coordinate] = firstFactor.h[hit].theta[coordinate];
383 gradients[hit][1][coordinate] = firstFactor.h[hit].phi[coordinate];
384 gradients[hit + 1][2][coordinate] = secondFactor.h[hit].theta[coordinate];
385 gradients[hit + 1][3][coordinate] = secondFactor.h[hit].phi[coordinate];
388 for (std::size_t hit = 0; hit < measurements.size(); ++hit) {
389 for (std::size_t
row = 0;
row < NAdjacentKinks; ++
row) {
390 for (std::size_t column = 0; column <=
row; ++column) {
391 const float contribution = covarianceContraction(
392 gradients[hit][
row], measurements[hit].covariance, gradients[hit][column]);
393 covariance[
row][column] += contribution;
395 covariance[column][
row] += contribution;
401 KinkCovariance
lower{};
402 KinkVector precisionPsi{};
403 KinkVector precisionRho{};
404 if (!choleskyDecompose(covariance,
lower) ||
405 !choleskySolve(
lower, psi, precisionPsi) ||
406 !choleskySolve(
lower, rho, precisionRho)) {
409 const float rhoPrecisionPsi = dotProduct(rho, precisionPsi);
410 const float rhoPrecisionRho = dotProduct(rho, precisionRho);
411 const float psiPrecisionPsi = dotProduct(psi, precisionPsi);
412 if (rhoPrecisionRho <= 0.) {
416 const float curvature = -rhoPrecisionPsi / rhoPrecisionRho;
417 const float curvatureVariance = 1. / rhoPrecisionRho;
418 const float removedCurvatureTerm = rhoPrecisionPsi * rhoPrecisionPsi / rhoPrecisionRho;
419 float chi2 = psiPrecisionPsi - removedCurvatureTerm;
420 const float chi2Tolerance = 128. * std::numeric_limits<float>::epsilon() *
421 std::max(std::abs(psiPrecisionPsi), std::abs(removedCurvatureTerm));
422 if (chi2 < 0. && chi2 >= -chi2Tolerance) {
425 if (curvatureVariance <= 0. ||
chi2 < 0.) {
429 result = {curvature, curvatureVariance,
chi2};
DualNumber cotangentTheta
std::array< float, NCoordinates > derivative
DualNumber transverseArcLength
GLsizei const GLfloat * value
GLuint GLsizei GLsizei * length
Vec3 operator-(const Vec3 &firstVector, const Vec3 &secondVector)
Vec3 cross(const Vec3 &firstVector, const Vec3 &secondVector)
bool fitAdjacentTripletFactors(const TripletFitFactor &firstFactor, const TripletFitFactor &secondFactor, const std::array< GlobalMeasurement, 4 > &measurements, const std::array< float, 2 > &angularVariance, AdjacentTripletFitResult &result) noexcept
bool makeTripletFitFactor(const std::array< GlobalMeasurement, 3 > &measurements, TripletFitFactor &factor) noexcept
D const SVectorGPU< T, D > & rhs
MultPolicyGPU< T, R1, R2 >::RepType operator*(const SMatrixGPU< T, D1, D, R1 > &lhs, const SMatrixGPU< T, D, D2, R2 > &rhs)