Project
Loading...
Searching...
No Matches
MisalignmentUtils.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 <algorithm>
15#include <cmath>
16#include <fstream>
17#include <vector>
18
19#include <TMatrixD.h>
20#include <nlohmann/json.hpp>
21
22#include "Framework/Logger.h"
23#include "ITS3Base/SpecsV2.h"
24
25namespace o2::its3::align
26{
27
28bool MisalignmentModel::empty() const noexcept
29{
30 return std::all_of(sensors.begin(), sensors.end(), [](const auto& sensor) { return sensor.empty(); });
31}
32
33MisalignmentModel loadMisalignmentModel(const std::string& jsonPath)
34{
36 if (jsonPath.empty()) {
37 return model;
38 }
39
40 std::ifstream f(jsonPath);
41 if (!f.is_open()) {
42 LOGP(fatal, "Cannot open misalignment JSON file: {}", jsonPath);
43 }
44
45 using json = nlohmann::json;
46 const auto data = json::parse(f);
47 for (const auto& item : data) {
48 const int id = item["id"].get<int>();
49 if (id < 0 || id >= static_cast<int>(MisalignmentModel::NSensors)) {
50 LOGP(fatal, "Misalignment sensor id {} out of range [0, {}) in {}", id, MisalignmentModel::NSensors, jsonPath);
51 }
52
53 auto& sensor = model[id];
54 if (item.contains("matrix")) {
55 auto v = item["matrix"].get<std::vector<std::vector<double>>>();
56 if (v.empty()) {
57 LOGP(fatal, "Legendre matrix for sensor {} is empty in {}", id, jsonPath);
58 }
59 TMatrixD m(v.size(), v.back().size());
60 for (std::size_t r{0}; r < v.size(); ++r) {
61 for (std::size_t c{0}; c < v[r].size(); ++c) {
62 m(r, c) = v[r][c];
63 }
64 }
66 sensor.hasLegendre = true;
67 }
68 if (item.contains("inextensional")) {
69 const auto& inex = item["inextensional"];
70 sensor.hasInextensional = true;
71 if (inex.contains("modes")) {
72 for (const auto& [key, val] : inex["modes"].items()) {
73 sensor.inextensional.modes[std::stoi(key)] = val.get<std::array<double, 4>>();
74 }
75 }
76 if (inex.contains("alpha")) {
77 sensor.inextensional.alpha = inex["alpha"].get<double>();
78 }
79 if (inex.contains("beta")) {
80 sensor.inextensional.beta = inex["beta"].get<double>();
81 }
82 }
83 }
84
85 return model;
86}
87
89{
91 if (!sensor.hasLegendre) {
92 return shift;
93 }
94
95 const double gloX = frame.x * std::cos(frame.alpha);
96 const double gloY = frame.x * std::sin(frame.alpha);
97 const double gloZ = frame.z;
98 auto [u, v] = computeUV(gloX, gloY, gloZ, frame.sensorID, constants::radii[frame.layerID]);
99 const double h = sensor.legendre(u, v);
100
101 shift.dy = slopes.dydx * h;
102 shift.dz = slopes.dzdx * h;
103
104 const double newGloY = gloY + (shift.dy * std::cos(frame.alpha));
105 const double newGloX = gloX - (shift.dy * std::sin(frame.alpha));
106 const double newGloZ = gloZ + shift.dz;
107 auto [uNew, vNew] = computeUV(newGloX, newGloY, newGloZ, frame.sensorID, constants::radii[frame.layerID]);
108 shift.accepted = std::abs(uNew) <= 1. && std::abs(vNew) <= 1.;
109 return shift;
110}
111
113{
114 MisalignmentShift shift;
115 if (!sensor.hasInextensional) {
116 return shift;
117 }
118
119 const double r = constants::radii[frame.layerID];
120 const double phi = std::atan2(r * std::sin(frame.alpha), r * std::cos(frame.alpha));
121 const double z = frame.z;
122 const auto& inex = sensor.inextensional;
123
124 double uz = 0., uphi = 0., ur = 0.;
125 for (const auto& [n, coeffs] : inex.modes) {
126 const double a_n = coeffs[0], b_n = coeffs[1], c_n = coeffs[2], d_n = coeffs[3];
127 const double sn = std::sin(n * phi);
128 const double cn = std::cos(n * phi);
129 const int n2 = n * n;
130
131 const double fn = (a_n * cn) + (b_n * sn);
132 const double fpn = (-n * a_n * sn) + (n * b_n * cn);
133 const double fppn = (-n2 * a_n * cn) - (n2 * b_n * sn);
134 const double gn = (c_n * cn) + (d_n * sn);
135 const double gpn = (-n * c_n * sn) + (n * d_n * cn);
136
137 uz += fn;
138 uphi += -(z / r) * fpn + gn;
139 ur += (z / r) * fppn - gpn;
140 }
141
142 uz += inex.alpha * phi;
143 uphi += -(z / r) * inex.alpha + inex.beta * phi;
144 ur += -inex.beta;
145
146 shift.dy = -uphi + (slopes.dydx * ur);
147 shift.dz = -uz + (slopes.dzdx * ur);
148 return shift;
149}
150
151} // namespace o2::its3::align
uint32_t c
Definition RawData.h:2
nlohmann::json json
StringRef key
Class for time synchronization of RawReader instances.
GLdouble n
Definition glcorearb.h:1982
const GLfloat * m
Definition glcorearb.h:4066
const GLdouble * v
Definition glcorearb.h:832
GLdouble f
Definition glcorearb.h:310
GLboolean * data
Definition glcorearb.h:298
GLuint GLfloat * val
Definition glcorearb.h:1582
GLint GLenum GLint const GLfloat * coeffs
Definition glcorearb.h:5520
GLboolean r
Definition glcorearb.h:1233
GLuint id
Definition glcorearb.h:650
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
MisalignmentShift evaluateInextensionalShift(const SensorMisalignment &sensor, const MisalignmentFrame &frame, const TrackSlopes &slopes)
MisalignmentModel loadMisalignmentModel(const std::string &jsonPath)
MisalignmentShift evaluateLegendreShift(const SensorMisalignment &sensor, const MisalignmentFrame &frame, const TrackSlopes &slopes)
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
static constexpr std::size_t NSensors
std::array< SensorMisalignment, NSensors > sensors
o2::math_utils::Legendre2DPolynominal legendre
InextensionalMisalignment inextensional