Skip to content

Commit 5cf005b

Browse files
authored
ITS3: add cylinder parameterisation preserving zero gaussian curvature (#15260)
* ITS3: exploit symmetric matrices for interpolation Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch> * ITS3: cleanup code Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch> * ITS3: alignment for inextionsial surfaces Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch> * ITS3: harmonize study and alignment wfx for misalignment Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch> --------- Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch>
1 parent bccbaff commit 5cf005b

File tree

16 files changed

+967
-359
lines changed

16 files changed

+967
-359
lines changed

Detectors/Upgrades/ITS3/alignment/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
o2_add_library(ITS3Align
1414
TARGETVARNAME targetName
1515
SOURCES src/AlignmentHierarchy.cxx
16+
src/AlignmentDOF.cxx
17+
src/AlignmentMath.cxx
18+
src/MisalignmentUtils.cxx
1619
src/AlignmentSensors.cxx
1720
src/AlignmentParams.cxx
1821
src/AlignmentTypes.cxx

Detectors/Upgrades/ITS3/alignment/README.md

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,38 @@ dofSet.json:
2727
"calib": { "type": "legendre", "order": 1, "fix": [0, 2] }
2828
}
2929
]
30-
}```
30+
}
31+
```
32+
33+
34+
## In-existensional modes
35+
```json
36+
{
37+
"defaults": { "rigidBody": "fixed" },
38+
"rules": [
39+
{
40+
"match": "ITS3Layer1/ITS3CarbonForm0",
41+
"calib": {
42+
"type": "inextensional",
43+
"order": 2,
44+
"free": ["a_2", "b_2", "c_2", "d_2", "alpha", "beta"]
45+
}
46+
}
47+
]
48+
}
49+
```
50+
51+
```json
52+
[
53+
{
54+
"id": 2,
55+
"inextensional": {
56+
"modes": {
57+
"2": [0.0008, -0.0005, 0.0006, -0.0007]
58+
},
59+
"alpha": 0.0004,
60+
"beta": -0.0003
61+
}
62+
}
63+
]
64+
```
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
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+
12+
#ifndef O2_ITS3_ALIGNMENT_DOF_H
13+
#define O2_ITS3_ALIGNMENT_DOF_H
14+
15+
#include <algorithm>
16+
#include <cstdint>
17+
#include <format>
18+
#include <stdexcept>
19+
#include <string>
20+
#include <vector>
21+
22+
#include <Eigen/Dense>
23+
24+
struct DerivativeContext {
25+
int sensorID{-1};
26+
int layerID{-1};
27+
double measX{0.};
28+
double measAlpha{0.};
29+
double measZ{0.};
30+
double trkY{0.};
31+
double trkZ{0.};
32+
double snp{0.};
33+
double tgl{0.};
34+
double dydx{0.};
35+
double dzdx{0.};
36+
};
37+
38+
// Generic set of DOF
39+
class DOFSet
40+
{
41+
public:
42+
enum class Type : uint8_t {
43+
RigidBody,
44+
Legendre,
45+
Inextensional
46+
};
47+
virtual ~DOFSet() = default;
48+
virtual Type type() const = 0;
49+
int nDOFs() const { return static_cast<int>(mFree.size()); }
50+
virtual std::string dofName(int idx) const = 0;
51+
virtual void fillDerivatives(const DerivativeContext& ctx, Eigen::Ref<Eigen::MatrixXd> out) const = 0;
52+
bool isFree(int idx) const { return mFree[idx]; }
53+
void setFree(int idx, bool f) { mFree[idx] = f; }
54+
void setAllFree(bool f) { std::fill(mFree.begin(), mFree.end(), f); }
55+
int nFreeDOFs() const
56+
{
57+
int n = 0;
58+
for (bool f : mFree) {
59+
n += f;
60+
}
61+
return n;
62+
}
63+
64+
protected:
65+
DOFSet(int n) : mFree(n, true) {}
66+
std::vector<bool> mFree;
67+
};
68+
69+
// Rigid body set
70+
class RigidBodyDOFSet final : public DOFSet
71+
{
72+
public:
73+
// indices for rigid body parameters in LOC frame
74+
enum RigidBodyDOF : uint8_t {
75+
TX = 0,
76+
TY,
77+
TZ,
78+
RX,
79+
RY,
80+
RZ,
81+
NDOF,
82+
};
83+
static constexpr const char* RigidBodyDOFNames[RigidBodyDOF::NDOF] = {"TX", "TY", "TZ", "RX", "RY", "RZ"};
84+
85+
RigidBodyDOFSet() : DOFSet(NDOF) {}
86+
// mask: bitmask of free DOFs (bit i = DOF i is free)
87+
explicit RigidBodyDOFSet(uint8_t mask) : DOFSet(NDOF)
88+
{
89+
for (int i = 0; i < NDOF; ++i) {
90+
mFree[i] = (mask >> i) & 1;
91+
}
92+
}
93+
Type type() const override { return Type::RigidBody; }
94+
std::string dofName(int idx) const override { return RigidBodyDOFNames[idx]; }
95+
void fillDerivatives(const DerivativeContext& ctx, Eigen::Ref<Eigen::MatrixXd> out) const override;
96+
uint8_t mask() const
97+
{
98+
uint8_t m = 0;
99+
for (int i = 0; i < NDOF; ++i) {
100+
m |= (uint8_t(mFree[i]) << i);
101+
}
102+
return m;
103+
}
104+
};
105+
106+
// Legendre DOFs
107+
// Describing radial misplacement
108+
class LegendreDOFSet final : public DOFSet
109+
{
110+
public:
111+
explicit LegendreDOFSet(int order) : DOFSet((order + 1) * (order + 2) / 2), mOrder(order) {}
112+
Type type() const override { return Type::Legendre; }
113+
int order() const { return mOrder; }
114+
std::string dofName(int idx) const override
115+
{
116+
int i = 0;
117+
while ((i + 1) * (i + 2) / 2 <= idx) {
118+
++i;
119+
}
120+
int j = idx - (i * (i + 1) / 2);
121+
return std::format("L({},{})", i, j);
122+
}
123+
void fillDerivatives(const DerivativeContext& ctx, Eigen::Ref<Eigen::MatrixXd> out) const override;
124+
125+
private:
126+
int mOrder;
127+
};
128+
129+
// In-extensional deformation DOFs for cylindrical half-shells
130+
// Fourier modes n=2..N: 4 params each (a_n, b_n, c_n, d_n)
131+
// Plus 2 non-periodic modes (alpha, beta) for the half-cylinder open edges
132+
// Total: 4*(N-1) + 2
133+
class InextensionalDOFSet final : public DOFSet
134+
{
135+
public:
136+
explicit InextensionalDOFSet(int maxOrder) : DOFSet((4 * (maxOrder - 1)) + 2), mMaxOrder(maxOrder)
137+
{
138+
if (maxOrder < 2) {
139+
// the rest is eq. to rigid body
140+
throw std::invalid_argument("InextensionalDOFSet requires maxOrder >= 2");
141+
}
142+
}
143+
Type type() const override { return Type::Inextensional; }
144+
int maxOrder() const { return mMaxOrder; }
145+
146+
// number of periodic DOFs (before alpha, beta)
147+
int nPeriodic() const { return 4 * (mMaxOrder - 1); }
148+
149+
// flat index layout: [a_2, b_2, c_2, d_2, a_3, b_3, c_3, d_3, ..., alpha, beta]
150+
// index of first DOF for mode n
151+
static int modeOffset(int n) { return 4 * (n - 2); }
152+
153+
// indices of the non-periodic modes
154+
int alphaIdx() const { return nPeriodic(); }
155+
int betaIdx() const { return nPeriodic() + 1; }
156+
157+
std::string dofName(int idx) const override
158+
{
159+
if (idx == alphaIdx()) {
160+
return "alpha";
161+
}
162+
if (idx == betaIdx()) {
163+
return "beta";
164+
}
165+
int n = (idx / 4) + 2;
166+
int sub = idx % 4;
167+
static constexpr const char* subNames[] = {"a", "b", "c", "d"};
168+
return std::format("{}_{}", subNames[sub], n);
169+
}
170+
void fillDerivatives(const DerivativeContext& ctx, Eigen::Ref<Eigen::MatrixXd> out) const override;
171+
172+
private:
173+
int mMaxOrder;
174+
};
175+
176+
#endif

0 commit comments

Comments
 (0)