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 <cmath>
15#include <stdexcept>
16
18#include "ITS3Base/SpecsV2.h"
19
20namespace
21{
22
23void validateDerivativeOutput(const DOFSet& dofSet, Eigen::Ref<Eigen::MatrixXd> out)
24{
25 if (out.rows() != 3 || out.cols() != dofSet.nDOFs()) {
26 throw std::invalid_argument(std::format("Derivative buffer shape {}x{} does not match expected 3x{}",
27 out.rows(), out.cols(), dofSet.nDOFs()));
28 }
29 out.setZero();
30}
31
32} // namespace
33
34void RigidBodyDOFSet::fillDerivatives(const DerivativeContext& ctx, Eigen::Ref<Eigen::MatrixXd> out) const
35{
36 validateDerivativeOutput(*this, out);
37 out(0, TX) = ctx.dydx;
38 out(0, TY) = -1.;
39 out(0, RX) = ctx.trkZ;
40 out(0, RY) = ctx.trkZ * ctx.dydx;
41 out(0, RZ) = -ctx.trkY * ctx.dydx;
42
43 out(1, TX) = ctx.dzdx;
44 out(1, TZ) = -1.;
45 out(1, RX) = -ctx.trkY;
46 out(1, RY) = ctx.trkZ * ctx.dzdx;
47 out(1, RZ) = -ctx.trkY * ctx.dzdx;
48}
49
50void LegendreDOFSet::fillDerivatives(const DerivativeContext& ctx, Eigen::Ref<Eigen::MatrixXd> out) const
51{
52 validateDerivativeOutput(*this, out);
53 if (ctx.sensorID < 0 || ctx.layerID < 0) {
54 throw std::invalid_argument("LegendreDOFSet requires an ITS3 measurement context");
55 }
56
57 const double gloX = ctx.measX * std::cos(ctx.measAlpha);
58 const double gloY = ctx.measX * std::sin(ctx.measAlpha);
59 const auto [u, v] = o2::its3::align::computeUV(gloX, gloY, ctx.measZ, ctx.sensorID, o2::its3::constants::radii[ctx.layerID]);
60 const auto pu = o2::its3::align::legendrePols(mOrder, u);
61 const auto pv = o2::its3::align::legendrePols(mOrder, v);
62
63 int idx = 0;
64 for (int i = 0; i <= mOrder; ++i) {
65 for (int j = 0; j <= i; ++j) {
66 const double basis = pu[j] * pv[i - j];
67 out(0, idx) = ctx.dydx * basis;
68 out(1, idx) = ctx.dzdx * basis;
69 ++idx;
70 }
71 }
72}
73
74void InextensionalDOFSet::fillDerivatives(const DerivativeContext& ctx, Eigen::Ref<Eigen::MatrixXd> out) const
75{
76 validateDerivativeOutput(*this, out);
77 if (ctx.sensorID < 0 || ctx.layerID < 0) {
78 throw std::invalid_argument("InextensionalDOFSet requires an ITS3 measurement context");
79 }
80
81 const double r = o2::its3::constants::radii[ctx.layerID];
82 const double gloX = ctx.measX * std::cos(ctx.measAlpha);
83 const double gloY = ctx.measX * std::sin(ctx.measAlpha);
84 const auto [u, v] = o2::its3::align::computeUV(gloX, gloY, ctx.measZ, ctx.sensorID, r);
85 const double cPhi = o2::its3::align::phiScale(r);
86 const double zOverR = ctx.measZ / r;
87
88 // The residual derivative for a mode with displacement M = (M_r, M_phi, M_z)
89 // along the local (r, phi, z) directions is
90 // row0 = dydx * M_r - M_phi, row1 = dzdx * M_r - M_z
91 // (cf. the rigid-body case, where M = (1,0,0) gives (dydx, dzdx)).
92 const auto fill = [&out, &ctx](int idx, double mR, double mPhi, double mZ) {
93 out(0, idx) = (ctx.dydx * mR) - mPhi;
94 out(1, idx) = (ctx.dzdx * mR) - mZ;
95 };
96
97 const int order = std::max(mMaxOrder, hasExtensional() ? mExtOrderPhi : 0);
98 const auto pu = o2::its3::align::legendrePols(order, u);
99 const auto pu1 = o2::its3::align::legendrePolsD1(mMaxOrder, u);
100 const auto pu2 = o2::its3::align::legendrePolsD2(mMaxOrder, u);
101
102 for (int k = 0; k <= mMaxOrder; ++k) {
103 // f_k: u_z = P_k, u_phi = -(z/r) c P'_k, u_r = (z/r) c^2 P''_k
104 fill(fIdx(k),
105 zOverR * cPhi * cPhi * pu2[k],
106 -zOverR * cPhi * pu1[k],
107 pu[k]);
108 // g_k: u_phi = P_k, u_r = -c P'_k
109 fill(gIdx(k), -cPhi * pu1[k], pu[k], 0.);
110 }
111
112 if (hasExtensional()) {
113 const auto pv = o2::its3::align::legendrePols(mExtOrderZ, v);
114 for (int k = 0; k <= mExtOrderPhi; ++k) {
115 for (int l = 1; l <= mExtOrderZ; ++l) {
116 // h_{k,l}: strictly radial u_r = P_k(u) P_l(v)
117 fill(hIdx(k, l), pu[k] * pv[l], 0., 0.);
118 }
119 }
120 }
121}
int32_t i
uint32_t j
Definition RawData.h:0
int nDOFs() const
static int fIdx(int k)
bool hasExtensional() const
int hIdx(int k, int l) const
void fillDerivatives(const DerivativeContext &ctx, Eigen::Ref< Eigen::MatrixXd > out) const override
static int gIdx(int k)
void fillDerivatives(const DerivativeContext &ctx, Eigen::Ref< Eigen::MatrixXd > out) const override
void fillDerivatives(const DerivativeContext &ctx, Eigen::Ref< Eigen::MatrixXd > out) const override
const GLdouble * v
Definition glcorearb.h:832
GLboolean r
Definition glcorearb.h:1233
std::vector< double > legendrePolsD2(int order, double x)
std::vector< double > legendrePolsD1(int order, double x)
double phiScale(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