CbmRoot
Loading...
Searching...
No Matches
CbmBbaAlignmentBody.cxx
Go to the documentation of this file.
1/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Sergey Gorbunov [committer] */
4
9
10#include "CbmBbaAlignmentBody.h"
11
12#include <Logger.h>
13
14#include <TGeoManager.h>
15#include <TGeoMatrix.h>
16#include <TGeoNode.h>
17#include <TGeoPhysicalNode.h>
18#include <TGeoTube.h>
19#include <TGeoVolume.h>
20#include <TObjArray.h>
21
22#include <iomanip>
23
24namespace
25{
26 constexpr bool kEulerAngles = false; // use euler angles for rotations instead of extrinsic rotations
27}
28
29namespace cbm::bba
30{
31 AlignmentBody::AlignmentBody(double shiftX, double shiftY, double shiftZ, double rotX, double rotY, double rotZ)
32 {
33
34 fGlobal.Clear();
35 fGlobalInv.Clear();
36 fAlignment.Clear();
37 fHitTransform.Clear();
38
39 if (kEulerAngles) {
40 TGeoRotation rot("", rotX, rotY, rotZ);
41 fGlobal.SetRotation(rot.GetRotationMatrix());
42 }
43 else {
44 // in order to use extrinisc rotations we have to do it step by step and before the translations
45 fGlobal.RotateX(rotX);
46 fGlobal.RotateY(rotY);
47 fGlobal.RotateZ(rotZ);
48 }
49 // the order of SetDx, SetDy, SetDz and SetRotation does not matter, but for extrinsic rotations via RotateX/Y/Z is important to do it before the translations
50 fGlobal.SetDx(shiftX);
51 fGlobal.SetDy(shiftY);
52 fGlobal.SetDz(shiftZ);
53 fGlobalNominal = fGlobal; // since there will never be pre-alignment
54 fGlobalInv = fGlobal.Inverse();
56 fIsValid = true;
57 }
58
59 AlignmentBody::AlignmentBody(std::string nodePath) { CreateFromGeoNode(nodePath); }
60
61 bool AlignmentBody::CreateFromGeoNode(const std::string nodePath)
62 {
63 fNodePath = nodePath;
64
65 // set the initial alignment to zero
66 fGlobal.Clear();
67 fGlobalInv.Clear();
68 fAlignment.Clear();
69 fHitTransform.Clear();
70
71 if (!gGeoManager) {
72 LOG(fatal) << "TGeoManager is not initialized!";
73 return false;
74 }
75
76 if (fNodePath.empty()) {
77 LOG(fatal) << "Alignment node path is empty!";
78 return false;
79 }
80
81 if (fNodePath[0] != '/') {
82 LOG(fatal) << "Alignment node path is not global. It must start with \"/\" "
83 << ": " << fNodePath;
84 return false;
85 }
86
87 if (!gGeoManager->cd(fNodePath.c_str())) {
88 LOG(fatal) << "Failed to cd to path " << fNodePath;
89 return false;
90 }
91 LOG(debug) << "Found alignment body: " << fNodePath;
92
93 // Get the current node and its global transformation
94 const TGeoNode* node = gGeoManager->GetCurrentNode();
95 if (!node) {
96 LOG(fatal) << "Failed to find TGeoNode at path " << fNodePath;
97 return false;
98 }
99
100 fGlobal = *(
101 gGeoManager
102 ->GetCurrentMatrix()); // global transformation matrix of the current node (TODO: assume that it will contain potential prealignment, to be tested)
103 fGlobalInv = fGlobal.Inverse();
104
105 // get the mother node to be able to search for the physical node
106 gGeoManager->CdUp();
107 // get the global transformation of the mother node (TODO: assume that it will contain potential prealignment, to be tested)
108 TGeoHMatrix GlobalMother =
109 *(gGeoManager
110 ->GetCurrentMatrix()); // global transformation matrix of the mother node including potential prealignment
111
112
113 // find the exsisting alignment matrix for the node
114 // when the alignment was applied, the node is presented in the list of physical nodes
115 {
116 TObjArray* pNodes = gGeoManager->GetListOfPhysicalNodes();
117 for (int i = 0; i < pNodes->GetEntriesFast(); i++) {
118 const TGeoPhysicalNode* pnode = dynamic_cast<const TGeoPhysicalNode*>(pNodes->At(i));
119 if (!pnode) {
120 LOG(fatal) << "Failed to cast TGeoPhysicalNode at index " << i;
121 return false;
122 }
123 if (pnode->GetNode() == node) {
124 // there is a physical node for this geo node -> the node already has some alignment
125 LOG(warn) << "Found pre-existing alignment for node " << fNodePath
126 << ". Pre-existing alignment will be ignored and replaced by new alignment.";
127 TGeoHMatrix localNoniminal = *(pnode->GetOriginalMatrix()); // unaligned local matrix
128 //TGeoHMatrix globalPreAligned = *(pnode->GetMatrix()); // aligned global matrix (TODO: hopefully the same as in fGlobalTransform? -> check!)
129 fGlobalNominal = GlobalMother * localNoniminal; // unaligned global matrix
130 // Calculate the pre-existing alignment matrix A0
131 TGeoHMatrix A0 = localNoniminal.Inverse() * (GlobalMother.Inverse() * fGlobal); // pre-existing alignment
132
133 // TODO: extraction of current alignment parameters from A0 into fPar0
134 //fPar = fPar0;
135 //fA = A0; // initial alignment matrix for extraction of start parameters
137
138 break;
139 }
140 }
141 }
142
143 fIsValid = true;
144 return fIsValid;
145 }
146
147
148 void AlignmentBody::ActivateParameters(const std::array<bool, NofParameters>& isParActive)
149 {
150 fIsParActive = isParActive;
151 }
152
153
154 void AlignmentBody::SetParameters(double shiftX, double shiftY, double shiftZ, double rotX, double rotY, double rotZ)
155 {
156 fPar[0] = shiftX;
157 fPar[1] = shiftY;
158 fPar[2] = shiftZ;
159 fPar[3] = rotX;
160 fPar[4] = rotY;
161 fPar[5] = rotZ;
162 if (kEulerAngles) {
163 TGeoRotation rot("", fPar[3], fPar[4], fPar[5]);
164 fAlignment.SetRotation(rot.GetRotationMatrix());
165 }
166 else {
167 // TODO!!! THIS ONLY WORKS WITHOUT PRE-EXISTING ALIGNMENT!! BECAUSE RotateX/Y/Z ALSO ROTATES PREEXISTING TRANSLATTION, OR IS IT OKAY LIKE THIS --> CHECK!!
168 fAlignment.Clear();
169 fAlignment.RotateX(rotX);
170 fAlignment.RotateY(rotY);
171 fAlignment.RotateZ(rotZ);
172 }
173 fAlignment.SetTranslation(fPar.data());
175 }
176
177 std::array<double, 3> AlignmentBody::ApplyAlignmentToHit(const std::array<double, 3> hit) const
178 {
179 std::array<double, 3> alignedHit;
180 // we use TGeoHMatrix to perform the transformation
181 // LocalToMaster calculates: master = Matrix * local
182 fHitTransform.LocalToMaster(hit.data(), alignedHit.data());
183 return alignedHit;
184 }
185
186 std::array<double, 3> AlignmentBody::ApplyInverseAlignmentToHit(const std::array<double, 3> hit) const
187 {
188 std::array<double, 3> alignedHit;
189 // we use TGeoHMatrix to perform the transformation
190 // MasterToLocal calculates: local = Matrix^{-1} * global
191 fHitTransform.MasterToLocal(hit.data(), alignedHit.data());
192 return alignedHit;
193 }
194
195 // TODO: this could be a memcpy
196 void AlignmentBody::GetParameters(double* par) const
197 {
198 for (int i = 0; i < NofParameters; i++) {
199 par[i] = fPar[i];
200 }
201 }
202
203} // namespace cbm::bba
Alignment body class for the BBA alignment.
void ActivateParameters(const std::array< bool, NofParameters > &isParActive)
TGeoHMatrix fGlobal
global transformation matrix of the alignment body
TGeoHMatrix fGlobalNominal
nominal global transformation matrix, without (pre-)alignment
std::string fNodePath
full path to the node in the root geometry
bool fIsValid
flag indicating if the alignment body is valid
std::array< double, 3 > ApplyAlignmentToHit(const std::array< double, 3 > hit) const
Apply the alignment to hit: return = fHitTransform * hit.
const std::array< double, NofParameters > & GetParameters() const
Get the alignment parameters.
AlignmentBody()=default
Default constructor.
std::array< double, NofParameters > fPar
alignment parameters: shiftX, shiftY, shiftZ, rotX, rotY, rotZ
std::array< bool, NofParameters > fIsParActive
flags for the parameters to be aligned
static constexpr int NofParameters
number of alignment parameters
TGeoHMatrix fAlignment
transformation matrix of the alignment body. Corresponds to the fPar values.
bool CreateFromGeoNode(const std::string nodePath)
void SetParameters(double shiftX=0., double shiftY=0., double shiftZ=0., double rotX=0., double rotY=0., double rotZ=0.)
TGeoHMatrix fGlobalInv
inverse of the global transformation matrix
std::array< double, 3 > ApplyInverseAlignmentToHit(const std::array< double, 3 > hit) const
Apply the inverse alignment to hit: return = fHitTransform^{-1} * hit.