Project
Loading...
Searching...
No Matches
GeometryTGeo.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 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// TODO: clean up includes
14#include "MathUtils/Cartesian.h"
15
16#include <fairlogger/Logger.h> // for LOG
17
18#include <TGeoBBox.h> // for TGeoBBox
19#include <TGeoManager.h> // for gGeoManager, TGeoManager
20#include <TGeoPhysicalNode.h> // for TGeoPNEntry, TGeoPhysicalNode
21#include <TGeoShape.h> // for TGeoShape
22#include <TMath.h> // for Nint, ATan2, RadToDeg
23#include <TString.h> // for TString, Form
24#include "TClass.h" // for TClass
25#include "TGeoMatrix.h" // for TGeoHMatrix
26#include "TGeoNode.h" // for TGeoNode, TGeoNodeMatrix
27#include "TGeoVolume.h" // for TGeoVolume
28#include "TMathBase.h" // for Max
29#include "TObjArray.h" // for TObjArray
30#include "TObject.h" // for TObject
31
32#include <cctype> // for isdigit
33#include <cstdio> // for snprintf, NULL, printf
34#include <cstring> // for strstr, strlen
35
36using namespace TMath;
37using namespace o2::detectors;
38
39namespace o2
40{
41namespace ft3
42{
43std::unique_ptr<o2::ft3::GeometryTGeo> GeometryTGeo::sInstance;
44
45std::string GeometryTGeo::sVolumeName = "FT3V";
46std::string GeometryTGeo::sInnerVolumeName = "FT3Inner";
47std::string GeometryTGeo::sLayerName = "FT3Layer";
48std::string GeometryTGeo::sChipName = "FT3Chip";
49// TODO: this is now only used for the not-segmented version; synchronise?
50std::string GeometryTGeo::sSensorName = "FT3Sensor";
51std::string GeometryTGeo::sPassiveName = "Passive";
52
54{
55 if (!mOwner) {
56 mOwner = true;
57 sInstance.release();
58 }
59}
60//__________________________________________________________________________
61GeometryTGeo::GeometryTGeo(bool build, int loadTrans) : DetMatrixCache(detectors::DetID::FT3)
62{
63 // default c-tor, if build is true, the structures will be filled and the transform matrices
64 // will be cached
65 if (sInstance) {
66 LOG(fatal) << "Invalid use of public constructor: o2::ft3::GeometryTGeo instance exists";
67 // throw std::runtime_error("Invalid use of public constructor: o2::ft3::GeometryTGeo instance exists");
68 }
69
70 if (build) {
71 Build(loadTrans);
72 }
73}
74
75//__________________________________________________________________________
76void GeometryTGeo::Build(int loadTrans)
77{
78 if (isBuilt()) {
79 LOG(warning) << "Already built";
80 return; // already initialized
81 }
82
83 if (!gGeoManager) {
84 // RSTODO: in future there will be a method to load matrices from the CDB
85 LOG(fatal) << "Geometry is not loaded";
86 }
87
88 // Forward discs part
89 // int sensIdx = 0;
90 int totDiscs = 0;
91 int absStaveIdx = 0;
92 mSize = 0;
93 // TODO: clean up initialisation
94 if (mChipIdxStave.size() == 0) {
95 mChipIdxStave.push_back(0);
96 }
97 if (mStaveIdxDisc.size() == 0) {
98 mStaveIdxDisc.push_back(0);
99 }
100 for (int iDir = 0; iDir < 2; iDir++) {
101 mNumberOfDiscs.push_back(extractNumberOfDiscs(iDir));
102 LOG(info) << "direction " << iDir << " has " << mNumberOfDiscs[iDir] << " discs";
103 totDiscs += mNumberOfDiscs[iDir];
104
105 for (int iDisc = 0; iDisc < mNumberOfDiscs[iDir]; iDisc++) {
106 TGeoVolume* ft3V = gGeoManager->GetVolume(getFT3VolPattern());
107 if (ft3V == nullptr) {
108 LOG(fatal) << getName() << " volume " << getFT3VolPattern() << " is not in the geometry";
109 }
110 auto layerNode = ft3V->GetNode(Form("%s_1", composeSymNameLayer(iDir, iDisc)));
111 if (layerNode == nullptr) {
112 LOG(fatal) << "Could not find layer node " << Form("%s_1", composeSymNameLayer(iDir, iDisc));
113 }
114 auto layerVol = layerNode->GetVolume();
115 if (layerVol == nullptr)
116 LOG(fatal) << "Could not find layer volume " << Form("%s_1", composeSymNameLayer(iDir, iDisc));
117 TObjArray* nodes = layerVol->GetNodes();
118 int nNodes = nodes->GetEntriesFast();
119 int nStaves = 0;
120 int nSensor = 0;
121 std::vector<int> chipsPerStave;
122 for (int j = 0; j < nNodes; j++) {
123 auto nd = dynamic_cast<TGeoNode*>(nodes->At(j));
124 const char* name = nd->GetName();
125 if (strstr(name, "FT3Sensor") != nullptr && strstr(name, "Inactive") == nullptr) {
126 int direction = 0, layer = 0;
127 int stave = 0, chip = 0;
128 extractChipIds(name, direction, layer, stave, chip);
129 if (stave >= chipsPerStave.size()) {
130 chipsPerStave.resize(stave + 1, 0);
131 nStaves = stave + 1;
132 }
133 if (chip + 1 >= chipsPerStave[stave]) {
134 chipsPerStave[stave] = chip + 1;
135 }
136 nSensor++;
137 }
138 }
139 LOG(info) << "direction " << iDir << " disc " << iDisc << " has " << nNodes << " nodes of which " << nSensor << " sensors in " << chipsPerStave.size() << " staves";
140
141 if (nStaves != chipsPerStave.size()) {
142 LOG(info) << "Inconsistency in stave count " << nStaves << " " << chipsPerStave.size();
143 }
144 mChipIdxStave.resize(absStaveIdx + chipsPerStave.size() + 1);
145 mNumberOfStavesPerDisc.push_back(chipsPerStave.size()); // TODO: remove this? Or remove StaveIdxDisc
146 int totSensor = 0;
147 for (int nChips : chipsPerStave) {
148 LOG(debug) << "Absolute Stave ID " << absStaveIdx << " : " << nChips << " sensors";
149 totSensor += nChips;
150 if (absStaveIdx) {
151 mChipIdxStave[absStaveIdx + 1] = mChipIdxStave[absStaveIdx] + nChips;
152 }
153 absStaveIdx++;
154 }
155 if (totSensor != nSensor) {
156 LOG(info) << "Inconsistency in sensor count " << nSensor << " " << totSensor;
157 }
158 LOG(debug) << " adding stave Idx " << absStaveIdx << " to disc array; element " << mStaveIdxDisc.size();
159 mStaveIdxDisc.push_back(absStaveIdx);
160 mNumberOfChipsPerDisc.push_back(totSensor);
161 mSize += totSensor;
162 LOG(info) << "Total sensors so far " << mSize;
163 }
164 }
165 // mSize = mChipStaveIds.size();
166 LOG(info) << "Total sensors " << mSize;
167 LOG(info) << "Length of stave-disc array " << mStaveIdxDisc.size();
168 fillMatrixCache(loadTrans); // Check whether this causes trouble
169}
170
171//__________________________________________________________________________
172const char* GeometryTGeo::composeSymNameLayer(int direction, int layerNumber)
173{
174 return Form("%s%d_%d", GeometryTGeo::getFT3LayerPattern(), direction, layerNumber);
175}
176
177//__________________________________________________________________________
178const char* GeometryTGeo::composeSymNameChip(Int_t d, Int_t lr)
179{
180 return Form("%s/%s%d", composeSymNameLayer(d, lr), getFT3ChipPattern(), lr);
181}
182
183//__________________________________________________________________________
184const char* GeometryTGeo::composeSymNameSensor(Int_t d, Int_t lr)
185{
186 return Form("%s/%s%d", composeSymNameChip(d, lr), getFT3SensorPattern(), lr);
187}
188
189//__________________________________________________________________________
191{
192 int numDiscs = 0;
193 while (gGeoManager->GetVolume(composeSymNameLayer(dir, numDiscs))) {
194 numDiscs++;
195 } // Check maybe subvolume?
196 return numDiscs; // Assume same # layers on both sides
197}
198//__________________________________________________________________________
200{
201 int numSensors = 0;
202 TGeoVolume* ft3V = gGeoManager->GetVolume(getFT3VolPattern());
203 if (ft3V == nullptr) {
204 LOG(fatal) << getName() << " volume " << getFT3VolPattern() << " is not in the geometry";
205 }
206 auto layerVol = ft3V->GetNode(Form("%s_1", composeSymNameLayer(dir, layer)))->GetVolume();
207 TObjArray* nodes = layerVol->GetNodes();
208 int nNodes = nodes->GetEntriesFast();
209 int nSensor = 0;
210 for (int j = 0; j < nNodes; j++) {
211 auto nd = dynamic_cast<TGeoNode*>(nodes->At(j));
212 const char* name = nd->GetName();
213 if (strstr(name, "FT3Sensor") != nullptr && strstr(name, "Inactive") == nullptr) {
214 nSensor++;
215 }
216 }
217 LOG(info) << "direction " << dir << " layer " << layer << " has " << nNodes << " nodes of which " << nSensor << " sensors";
218 return nSensor;
219}
220//__________________________________________________________________________
221int GeometryTGeo::extractChipId(std::string const volName)
222{
223 if (volName.find("FT3Sensor_Active") == 0) {
224 return std::stoi(volName.substr(volName.rfind('_') + 1));
225 }
226 LOG(error) << "Not a sensor volume " << volName;
227 return -1;
228}
229void GeometryTGeo::extractStaveChipId(std::string const volName, int& stave, int& chip)
230{
231 if (volName.find("FT3Sensor_Active") == 0) {
232 int idx = volName.rfind('_');
233 chip = std::stoi(volName.substr(idx + 1));
234 idx = volName.rfind('_', idx);
235 stave = std::stoi(volName.substr(idx + 1));
236 } else {
237 LOG(error) << "Not a sensor volume " << volName;
238 stave = -1;
239 chip = -1;
240 }
241}
242void GeometryTGeo::extractChipIds(std::string const volName, int& direction, int& layer, int& stave, int& chip)
243{
244 if (volName.find("FT3Sensor_Active") == 0) {
245 int idx = volName.find('_') + 1;
246 idx = volName.find('_', idx) + 1;
247 direction = std::stoi(volName.substr(idx));
248 idx = volName.find('_', idx) + 1;
249 layer = std::stoi(volName.substr(idx));
250 idx = volName.find('_', idx) + 1;
251 stave = std::stoi(volName.substr(idx));
252 idx = volName.find('_', idx) + 1;
253 chip = std::stoi(volName.substr(idx));
254 } else {
255 LOG(error) << "Not a sensor volume " << volName;
256 direction = -1;
257 }
258}
259
260int GeometryTGeo::getChipIndex(int dir, int layer, int stave, int chip) const
261{
262 int absDisc = layer;
263 if (dir == 1) {
264 absDisc += mNumberOfDiscs[0];
265 }
266 return mChipIdxStave[mStaveIdxDisc[absDisc] + stave] + chip;
267}
268
269int GeometryTGeo::getLayer(int chipIdx) const
270{
271 int lay = mNumberOfDiscs[0] + mNumberOfDiscs[1] - 1;
272 while (chipIdx < mChipIdxStave[mStaveIdxDisc[lay]] && lay > 0) {
273 lay--;
274 }
275 return lay;
276}
277
278// retrieve local stave number from chip ID
279int GeometryTGeo::getStave(int chipIdx) const
280{
281 int lay = getLayer(chipIdx);
282 int absStave = mStaveIdxDisc[lay];
283 while (chipIdx >= mChipIdxStave[absStave] && absStave < mStaveIdxDisc[lay + 1]) {
284 absStave++;
285 }
286 return absStave - 1 - mStaveIdxDisc[lay];
287}
288
289// retrieve local chip number on stave from chip ID
290int GeometryTGeo::getChipOnStave(int chipIdx) const
291{
292 int lay = getLayer(chipIdx);
293 int stave = getStave(chipIdx);
294 return chipIdx - mChipIdxStave[mStaveIdxDisc[lay] + stave];
295}
296
297std::string GeometryTGeo::getMatrixPath(int direction, int layer, int stave, int chip) const
298{
299
300 // PrintChipID(index, subDetID, petalcase, disk, layer, stave, halfstave, mod, chip);
301
302 std::string path = Form("/cave_1/barrel_1/%s_2/", GeometryTGeo::getFT3VolPattern());
303
304 // Stave name: std::string stave_volume_name =
305 // "Stave_" + std::to_string(i_stave) + "_" + std::to_string(layerNumber) +
306 // "_" + std::to_string(direction);
307 // Sensors directly placed in layer volume?
308
309 path += Form("%s%d_%d_1/", getFT3LayerPattern(), direction, layer); // TRKLayerx_1
310 // std::string sensorName = std::string("FT3Sensor_") + std::to_string(layer) + "_" + std::to_string(direction) + "_" + std::to_string(mChipStaveIds[index]) + "_" + index;
311 path += Form("FT3Sensor_Active_%d_%d_%d_%d_%d", direction, layer, stave, chip, chip);
312 /*
313 if (mLayoutMLOT == FT3Layout::kCylindrical) {
314 // TODO: fix this caser?
315 path += Form("%s%d_1/", getTRKSensorPattern(), layer); // TRKSensorx_1
316 } else {
317 path += Form("%s%d_%d/", getFT3StavePattern(), layer, stave);
318 path += Form("%s%d_%d/", getFT3ModulePattern(), layer, mod);
319 path += Form("%s%d_%d_1", getFT3ChipPattern(), layer, chipID);
320 }
321 */
322 return path;
323}
324
325//__________________________________________________________________________
327{
328 // populate matrix cache for requested transformations
329 //
330 if (mSize < 1) {
331 LOG(warning) << "The method Build was not called yet";
332 Build(mask);
333 return;
334 }
335
336 // build matrices
337 if ((mask & o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)) && !getCacheL2G().isFilled()) {
338 // Matrices for Local (Sensor!!! rather than the full chip) to Global frame transformation
339 LOGP(info, "Loading {} L2G matrices from TGeo; there are {} matrices", getName(), mSize);
340 auto& cacheL2G = getCacheL2G();
341 cacheL2G.setSize(mSize);
342 auto& cacheT2L = getCacheT2L();
343 cacheT2L.setSize(mSize);
344 mCacheRefAlphaDiscs.resize(mSize, 0);
345
346 double locA[3] = {-100., 0., 0.}, locB[3] = {100., 0., 0.}, gloA[3], gloB[3];
347 double xp{0}, yp{0};
348
349 gGeoManager->PushPath();
350 LOG(info) << " Number of directions " << mNumberOfDiscs.size();
351 int nTotDisc = mNumberOfDiscs[0] + mNumberOfDiscs[1];
352 for (int absDisc = 0; absDisc < nTotDisc; absDisc++) {
353 int direction = 0;
354 int layer = absDisc;
355 if (absDisc >= mNumberOfDiscs[0]) {
356 direction = 1;
357 layer = absDisc - mNumberOfDiscs[0];
358 }
359 LOG(info) << "Direction " << direction << " layer " << layer;
360 if (absDisc >= mNumberOfStavesPerDisc.size()) {
361 LOG(fatal) << "Not enough entries in mNumberOfStavesPerDisc " << absDisc << " " << mNumberOfStavesPerDisc.size();
362 }
363 for (int stave = 0; stave < mNumberOfStavesPerDisc[absDisc]; stave++) {
364 int absStave = mStaveIdxDisc[absDisc] + stave;
365 if (absStave + 1 >= mChipIdxStave.size()) {
366 LOG(fatal) << "Attempting to get absStave + 1 from index array size " << mChipIdxStave.size();
367 }
368 int nChip = mChipIdxStave[absStave + 1] - mChipIdxStave[absStave]; // TODO: this is too often == 0
369 LOG(debug) << "Getting matrices for direction " << direction << " layer " << layer << " stave " << stave << " : " << nChip << " chips";
370 for (int chip = 0; chip < nChip; chip++) {
371 int chipIdx = getChipIndex(direction, layer, stave, chip);
372 if (!gGeoManager->cd(getMatrixPath(direction, layer, stave, chip).c_str())) {
373 LOG(fatal) << "Geometry path not found " << getMatrixPath(direction, layer, stave, chip);
374 }
375 const TGeoHMatrix* matL2G = gGeoManager->GetCurrentMatrix();
376 if (chipIdx >= mSize) {
377 LOG(fatal) << "ChipIdx " << chipIdx << " out of range " << mSize;
378 }
379 cacheL2G.setMatrix(Mat3D(*matL2G), chipIdx);
380
381 matL2G->LocalToMaster(locA, gloA);
382 matL2G->LocalToMaster(locB, gloB);
383 double dx = gloB[0] - gloA[0], dy = gloB[1] - gloA[1];
384 double t = (gloB[0] * dx + gloB[1] * dy) / (dx * dx + dy * dy);
385 xp = gloB[0] - dx * t;
386 yp = gloB[1] - dy * t;
387 float alp = std::atan2(yp, xp);
388 mCacheRefXDiscs.push_back(std::hypot(xp, yp));
389 o2::math_utils::bringTo02Pi(alp);
390 mCacheRefAlphaDiscs[chipIdx] = alp;
391
392 static TGeoHMatrix t2l;
393 t2l.Clear();
394 t2l.RotateZ(mCacheRefAlphaDiscs[chipIdx] * TMath::RadToDeg()); // TODO: do we need this cache?
395 const TGeoHMatrix& matL2Gi = matL2G->Inverse();
396 t2l.MultiplyLeft(&matL2Gi);
397 cacheT2L.setMatrix(Mat3D(t2l), chipIdx); // TODO: may need deref with *
398 }
399 }
400 }
401 gGeoManager->PopPath();
402 }
403}
404
405//__________________________________________________________________________
406void GeometryTGeo::Print(Option_t*) const
407{
408 if (!isBuilt()) {
409 LOGF(info, "Geometry not built yet!");
410 return;
411 }
412 std::cout << "Detector ID: " << sInstance.get()->getDetID() << std::endl;
413
414 LOGF(info, "Summary of GeometryTGeo: %s", getName());
415 LOGF(info, "Number of disks: %d + %d", mNumberOfDiscs[0], mNumberOfDiscs[1]);
416 LOGF(info, "Total number of sensors: %d", mSize);
417}
418
419} // namespace ft3
420} // namespace o2
std::ostringstream debug
uint32_t j
Definition RawData.h:0
Definition of the GeometryTGeo class.
Static class with identifiers, bitmasks and names for ALICE detectors.
Definition DetID.h:58
const MatrixCache< Mat3D > & getCacheT2L() const
const char * getName() const
int mSize
prebooked number of sensors
const MatrixCache< Mat3D > & getCacheL2G() const
int extractNumberOfDiscs(int dir)
std::vector< float > mCacheRefXDiscs
static std::string sPassiveName
Passive material name.
static std::string sChipName
Chip name.
void extractChipIds(std::string const volName, int &direction, int &layer, int &stave, int &chip)
std::vector< int > mNumberOfChipsPerDisc
Index of first chup for each global stave.
void Build(int loadTrans)
static const char * composeSymNameSensor(Int_t d, Int_t lr)
static std::string sLayerName
Layer name.
static const char * getFT3SensorPattern()
o2::math_utils::Transform3D Mat3D
void Print(Option_t *opt="") const
static std::string sVolumeName
Mother volume name.
void fillMatrixCache(int mask)
int getChipOnStave(int chipIdx) const
static const char * getFT3ChipPattern()
std::vector< int > mNumberOfStavesPerDisc
static std::string sSensorName
Sensor name.
GeometryTGeo(bool build=false, int loadTrans=0)
static const char * composeSymNameLayer(Int_t d, Int_t lr)
int getStave(int chipIdx) const
int extractNumberOfChips(int dir, int layer)
std::vector< int > mChipIdxStave
Index of first global stave Id for each disc.
static std::string sInnerVolumeName
Mother inner volume name.
std::vector< float > mCacheRefAlphaDiscs
cache for X of ML and OT
std::vector< int > mStaveIdxDisc
TODO; in principle redundant?
static const char * getFT3LayerPattern()
static const char * composeSymNameChip(Int_t d, Int_t lr)
int extractChipId(std::string const volName)
std::vector< int > mNumberOfDiscs
cache for sensor ref alpha ML and OT
void extractStaveChipId(std::string const volName, int &stave, int &chip)
int getLayer(int chipIdx) const
static const char * getFT3VolPattern()
int getChipIndex(int dir, int disc, int stave, int chip) const
std::string getMatrixPath(int direction, int layer, int stave, int chip) const
GLuint const GLchar * name
Definition glcorearb.h:781
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
GLint GLuint mask
Definition glcorearb.h:291
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
static constexpr int L2G
Definition Cartesian.h:55
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"