Project
Loading...
Searching...
No Matches
AlignmentDOF.cxx
Go to the documentation of this file.
1// Copyright 2019-2026 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
13
14#include <array>
15#include <cmath>
16#include <stdexcept>
17
19#include "ITS3Base/SpecsV2.h"
21
22namespace
23{
24
25void validateDerivativeOutput(const DOFSet& dofSet, Eigen::Ref<Eigen::MatrixXd> out)
26{
27 if (out.rows() != 3 || out.cols() != dofSet.nDOFs()) {
28 throw std::invalid_argument(std::format("Derivative buffer shape {}x{} does not match expected 3x{}",
29 out.rows(), out.cols(), dofSet.nDOFs()));
30 }
31 out.setZero();
32}
33
34} // namespace
35
36void RigidBodyDOFSet::fillDerivatives(const DerivativeContext& ctx, Eigen::Ref<Eigen::MatrixXd> out) const
37{
38 validateDerivativeOutput(*this, out);
39
40 const double csp = 1. / std::sqrt(1. + (ctx.tgl * ctx.tgl));
41 const double uP = ctx.snp * csp;
42 const double vP = ctx.tgl * csp;
43
44 out(0, TX) = uP;
45 out(0, TY) = -1.;
46 out(0, RX) = ctx.trkZ;
47 out(0, RY) = ctx.trkZ * uP;
48 out(0, RZ) = -ctx.trkY * uP;
49
50 out(1, TX) = vP;
51 out(1, TZ) = -1.;
52 out(1, RX) = -ctx.trkY;
53 out(1, RY) = ctx.trkZ * vP;
54 out(1, RZ) = -ctx.trkY * vP;
55}
56
57void LegendreDOFSet::fillDerivatives(const DerivativeContext& ctx, Eigen::Ref<Eigen::MatrixXd> out) const
58{
59 validateDerivativeOutput(*this, out);
60 if (ctx.sensorID < 0 || ctx.layerID < 0) {
61 throw std::invalid_argument("LegendreDOFSet requires an ITS3 measurement context");
62 }
63
64 const double gloX = ctx.measX * std::cos(ctx.measAlpha);
65 const double gloY = ctx.measX * std::sin(ctx.measAlpha);
66 const auto [u, v] = o2::its3::align::computeUV(gloX, gloY, ctx.measZ, ctx.sensorID, o2::its3::constants::radii[ctx.layerID]);
67 const auto pu = o2::its3::align::legendrePols(mOrder, u);
68 const auto pv = o2::its3::align::legendrePols(mOrder, v);
69 const double phiWidth = o2::its3::align::getSensorPhiWidth(ctx.sensorID, o2::its3::constants::radii[ctx.layerID]);
70
71 // same intergration as `evaluateLegendreShift' but now for each order separateley
72 Eigen::VectorXd arcMismatch = Eigen::VectorXd::Zero(nDOFs());
73 if (std::abs(u) > o2::constants::math::Almost0) {
74 constexpr std::array<double, 8> x = {-0.9602898564975363, -0.7966664774136267, -0.5255324099163290, -0.1834346424956498, 0.1834346424956498, 0.5255324099163290, 0.7966664774136267, 0.9602898564975363};
75 constexpr std::array<double, 8> w = {0.1012285362903763, 0.2223810344533745, 0.3137066458778873, 0.3626837833783620, 0.3626837833783620, 0.3137066458778873, 0.2223810344533745, 0.1012285362903763};
76 const double mid = 0.5 * u;
77 const double half = 0.5 * u;
78 for (int iq = 0; iq < 8; ++iq) {
79 const double up = mid + (half * x[iq]);
80 const auto puQ = o2::its3::align::legendrePols(mOrder, up);
81 int idx = 0;
82 for (int i = 0; i <= mOrder; ++i) {
83 for (int j = 0; j <= i; ++j) {
84 arcMismatch[idx] += w[iq] * puQ[j] * pv[i - j];
85 ++idx;
86 }
87 }
88 }
89 arcMismatch *= 0.5 * phiWidth * half;
90 }
91
92 int idx = 0;
93 for (int i = 0; i <= mOrder; ++i) {
94 for (int j = 0; j <= i; ++j) {
95 const double basis = pu[j] * pv[i - j];
96 out(0, idx) = (ctx.dydx * basis) + arcMismatch[idx];
97 out(1, idx) = ctx.dzdx * basis;
98 ++idx;
99 }
100 }
101}
102
103void InextensionalDOFSet::fillDerivatives(const DerivativeContext& ctx, Eigen::Ref<Eigen::MatrixXd> out) const
104{
105 validateDerivativeOutput(*this, out);
106 if (ctx.layerID < 0) {
107 throw std::invalid_argument("InextensionalDOFSet requires an ITS3 measurement context");
108 }
109
110 const double r = o2::its3::constants::radii[ctx.layerID];
111 const double phi = std::atan2(r * std::sin(ctx.measAlpha), r * std::cos(ctx.measAlpha));
112 const double z = ctx.measZ;
113
114 for (int n = 2; n <= mMaxOrder; ++n) {
115 const double sn = std::sin(n * phi);
116 const double cn = std::cos(n * phi);
117 const double n2 = static_cast<double>(n * n);
118 const int off = modeOffset(n);
119
120 out(0, off + 0) = -(z / r) * (n * sn + ctx.dydx * n2 * cn);
121 out(1, off + 0) = -cn - ctx.dzdx * (z / r) * n2 * cn;
122
123 out(0, off + 1) = (z / r) * (n * cn - ctx.dydx * n2 * sn);
124 out(1, off + 1) = -sn * (1. + ctx.dzdx * (z / r) * n2);
125
126 out(0, off + 2) = -cn + ctx.dydx * n * sn;
127 out(1, off + 2) = ctx.dzdx * n * sn;
128
129 out(0, off + 3) = -sn - ctx.dydx * n * cn;
130 out(1, off + 3) = -ctx.dzdx * n * cn;
131 }
132
133 out(0, alphaIdx()) = z / r;
134 out(1, alphaIdx()) = -phi;
135
136 out(0, betaIdx()) = -phi - ctx.dydx;
137 out(1, betaIdx()) = -ctx.dzdx;
138}
int32_t i
useful math constants
uint32_t j
Definition RawData.h:0
int nDOFs() const
static int modeOffset(int n)
void fillDerivatives(const DerivativeContext &ctx, Eigen::Ref< Eigen::MatrixXd > out) const override
void fillDerivatives(const DerivativeContext &ctx, Eigen::Ref< Eigen::MatrixXd > out) const override
void fillDerivatives(const DerivativeContext &ctx, Eigen::Ref< Eigen::MatrixXd > out) const override
GLdouble n
Definition glcorearb.h:1982
GLint GLenum GLint x
Definition glcorearb.h:403
const GLdouble * v
Definition glcorearb.h:832
GLboolean r
Definition glcorearb.h:1233
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
constexpr float Almost0
double getSensorPhiWidth(int sensorID, double radius)
std::vector< double > legendrePols(int order, double x)
std::pair< double, double > computeUV(double gloX, double gloY, double gloZ, int sensorID, double radius)
constexpr std::array< double, nLayers > radii
Definition SpecsV2.h:134