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 auto layerVol = layerNode->GetVolume();
114 if (layerVol == nullptr)
115 LOG(fatal) << "Could not find layer volume " << Form("%s_1", composeSymNameLayer(iDir, iDisc));
116 TObjArray* nodes = layerVol->GetNodes();
117 int nNodes = nodes->GetEntriesFast();
118 int nStaves = 0;
119 int nSensor = 0;
120 std::vector<int> chipsPerStave;
121 for (int j = 0; j < nNodes; j++) {
122 auto nd = dynamic_cast<TGeoNode*>(nodes->At(j));
123 const char* name = nd->GetName();
124 if (strstr(name, "FT3Sensor") != nullptr && strstr(name, "Inactive") == nullptr) {
125 int direction = 0, layer = 0;
126 int stave = 0, chip = 0;
127 extractChipIds(name, direction, layer, stave, chip);
128 if (stave >= chipsPerStave.size()) {
129 chipsPerStave.resize(stave + 1, 0);
130 nStaves = stave + 1;
131 }
132 if (chip + 1 >= chipsPerStave[stave]) {
133 chipsPerStave[stave] = chip + 1;
134 }
135 nSensor++;
136 }
137 }
138 LOG(info) << "direction " << iDir << " disc " << iDisc << " has " << nNodes << " nodes of which " << nSensor << " sensors in " << chipsPerStave.size() << " staves";
139
140 if (nStaves != chipsPerStave.size())
141 LOG(info) << "Inconsistency in stave count " << nStaves << " " << chipsPerStave.size();
142 mChipIdxStave.resize(absStaveIdx + chipsPerStave.size() + 1);
143 mNumberOfStavesPerDisc.push_back(chipsPerStave.size()); // TODO: remove this? Or remove StaveIdxDisc
144 int totSensor = 0;
145 for (int nChips : chipsPerStave) {
146 LOG(debug) << "Absolute Stave ID " << absStaveIdx << " : " << nChips << " sensors";
147 totSensor += nChips;
148 if (absStaveIdx)
149 mChipIdxStave[absStaveIdx + 1] = mChipIdxStave[absStaveIdx] + nChips;
150 absStaveIdx++;
151 }
152 if (totSensor != nSensor)
153 LOG(info) << "Inconsistency in sensor count " << nSensor << " " << totSensor;
154 LOG(debug) << " adding stave Idx " << absStaveIdx << " to disc array; element " << mStaveIdxDisc.size();
155 mStaveIdxDisc.push_back(absStaveIdx);
156 mNumberOfChipsPerDisc.push_back(totSensor);
157 mSize += totSensor;
158 LOG(info) << "Total sensors so far " << mSize;
159 }
160 }
161 // mSize = mChipStaveIds.size();
162 LOG(info) << "Total sensors " << mSize;
163 LOG(info) << "Length of stave-disc array " << mStaveIdxDisc.size();
164 fillMatrixCache(loadTrans); // Check whether this causes trouble
165}
166
167//__________________________________________________________________________
168const char* GeometryTGeo::composeSymNameLayer(int direction, int layerNumber)
169{
170 return Form("%s%d_%d", GeometryTGeo::getFT3LayerPattern(), direction, layerNumber);
171}
172
173//__________________________________________________________________________
174const char* GeometryTGeo::composeSymNameChip(Int_t d, Int_t lr)
175{
176 return Form("%s/%s%d", composeSymNameLayer(d, lr), getFT3ChipPattern(), lr);
177}
178
179//__________________________________________________________________________
180const char* GeometryTGeo::composeSymNameSensor(Int_t d, Int_t lr)
181{
182 return Form("%s/%s%d", composeSymNameChip(d, lr), getFT3SensorPattern(), lr);
183}
184
185//__________________________________________________________________________
187{
188 int numDiscs = 0;
189 while (gGeoManager->GetVolume(composeSymNameLayer(dir, numDiscs))) {
190 numDiscs++;
191 } // Check maybe subvolume?
192 return numDiscs; // Assume same # layers on both sides
193}
194//__________________________________________________________________________
196{
197 int numSensors = 0;
198 TGeoVolume* ft3V = gGeoManager->GetVolume(getFT3VolPattern());
199 if (ft3V == nullptr) {
200 LOG(fatal) << getName() << " volume " << getFT3VolPattern() << " is not in the geometry";
201 }
202 auto layerVol = ft3V->GetNode(Form("%s_1", composeSymNameLayer(dir, layer)))->GetVolume();
203 TObjArray* nodes = layerVol->GetNodes();
204 int nNodes = nodes->GetEntriesFast();
205 int nSensor = 0;
206 for (int j = 0; j < nNodes; j++) {
207 auto nd = dynamic_cast<TGeoNode*>(nodes->At(j));
208 const char* name = nd->GetName();
209 if (strstr(name, "FT3Sensor") != nullptr && strstr(name, "Inactive") == nullptr) {
210 nSensor++;
211 }
212 }
213 LOG(info) << "direction " << dir << " layer " << layer << " has " << nNodes << " nodes of which " << nSensor << " sensors";
214 return nSensor;
215}
216//__________________________________________________________________________
217int GeometryTGeo::extractChipId(std::string const volName)
218{
219 if (volName.find("FT3Sensor_Active") == 0) {
220 return std::stoi(volName.substr(volName.rfind('_') + 1));
221 }
222 LOG(error) << "Not a sensor volume " << volName;
223 return -1;
224}
225void GeometryTGeo::extractStaveChipId(std::string const volName, int& stave, int& chip)
226{
227 if (volName.find("FT3Sensor_Active") == 0) {
228 int idx = volName.rfind('_');
229 chip = std::stoi(volName.substr(idx + 1));
230 idx = volName.rfind('_', idx);
231 stave = std::stoi(volName.substr(idx + 1));
232 } else {
233 LOG(error) << "Not a sensor volume " << volName;
234 stave = -1;
235 chip = -1;
236 }
237}
238void GeometryTGeo::extractChipIds(std::string const volName, int& direction, int& layer, int& stave, int& chip)
239{
240 if (volName.find("FT3Sensor_Active") == 0) {
241 int idx = volName.find('_') + 1;
242 idx = volName.find('_', idx) + 1;
243 direction = std::stoi(volName.substr(idx));
244 idx = volName.find('_', idx) + 1;
245 layer = std::stoi(volName.substr(idx));
246 idx = volName.find('_', idx) + 1;
247 stave = std::stoi(volName.substr(idx));
248 idx = volName.find('_', idx) + 1;
249 chip = std::stoi(volName.substr(idx));
250 } else {
251 LOG(error) << "Not a sensor volume " << volName;
252 direction = -1;
253 }
254}
255
256int GeometryTGeo::getChipIndex(int dir, int layer, int stave, int chip) const
257{
258 int absDisc = layer;
259 if (dir == 1)
260 absDisc += mNumberOfDiscs[0];
261 return mChipIdxStave[mStaveIdxDisc[absDisc] + stave] + chip;
262}
263
264int GeometryTGeo::getLayer(int chipIdx) const
265{
266 int lay = mNumberOfDiscs[0] + mNumberOfDiscs[1] - 1;
267 while (chipIdx < mChipIdxStave[mStaveIdxDisc[lay]] && lay > 0) {
268 lay--;
269 }
270 return lay;
271}
272
273// retrieve local stave number from chip ID
274int GeometryTGeo::getStave(int chipIdx) const
275{
276 int lay = getLayer(chipIdx);
277 int absStave = mStaveIdxDisc[lay];
278 while (chipIdx >= mChipIdxStave[absStave] && absStave < mStaveIdxDisc[lay + 1]) {
279 absStave++;
280 }
281 return absStave - 1 - mStaveIdxDisc[lay];
282}
283
284// retrieve local chip number on stave from chip ID
285int GeometryTGeo::getChipOnStave(int chipIdx) const
286{
287 int lay = getLayer(chipIdx);
288 int stave = getStave(chipIdx);
289 return chipIdx - mChipIdxStave[mStaveIdxDisc[lay] + stave];
290}
291
292std::string GeometryTGeo::getMatrixPath(int direction, int layer, int stave, int chip) const
293{
294
295 // PrintChipID(index, subDetID, petalcase, disk, layer, stave, halfstave, mod, chip);
296
297 std::string path = Form("/cave_1/barrel_1/%s_2/", GeometryTGeo::getFT3VolPattern());
298
299 // Stave name: std::string stave_volume_name =
300 // "Stave_" + std::to_string(i_stave) + "_" + std::to_string(layerNumber) +
301 // "_" + std::to_string(direction);
302 // Sensors directly placed in layer volume?
303
304 path += Form("%s%d_%d_1/", getFT3LayerPattern(), direction, layer); // TRKLayerx_1
305 // std::string sensorName = std::string("FT3Sensor_") + std::to_string(layer) + "_" + std::to_string(direction) + "_" + std::to_string(mChipStaveIds[index]) + "_" + index;
306 path += Form("FT3Sensor_Active_%d_%d_%d_%d_%d", direction, layer, stave, chip, chip);
307 /*
308 if (mLayoutMLOT == FT3Layout::kCylindrical) {
309 // TODO: fix this caser?
310 path += Form("%s%d_1/", getTRKSensorPattern(), layer); // TRKSensorx_1
311 } else {
312 path += Form("%s%d_%d/", getFT3StavePattern(), layer, stave);
313 path += Form("%s%d_%d/", getFT3ModulePattern(), layer, mod);
314 path += Form("%s%d_%d_1", getFT3ChipPattern(), layer, chipID);
315 }
316 */
317 return path;
318}
319
320//__________________________________________________________________________
322{
323 // populate matrix cache for requested transformations
324 //
325 if (mSize < 1) {
326 LOG(warning) << "The method Build was not called yet";
327 Build(mask);
328 return;
329 }
330
331 // build matrices
332 if ((mask & o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)) && !getCacheL2G().isFilled()) {
333 // Matrices for Local (Sensor!!! rather than the full chip) to Global frame transformation
334 LOGP(info, "Loading {} L2G matrices from TGeo; there are {} matrices", getName(), mSize);
335 auto& cacheL2G = getCacheL2G();
336 cacheL2G.setSize(mSize);
337 auto& cacheT2L = getCacheT2L();
338 cacheT2L.setSize(mSize);
339 mCacheRefAlphaDiscs.resize(mSize, 0);
340
341 double locA[3] = {-100., 0., 0.}, locB[3] = {100., 0., 0.}, gloA[3], gloB[3];
342 double xp{0}, yp{0};
343
344 gGeoManager->PushPath();
345 LOG(info) << " Number of directions " << mNumberOfDiscs.size();
346 int nTotDisc = mNumberOfDiscs[0] + mNumberOfDiscs[1];
347 for (int absDisc = 0; absDisc < nTotDisc; absDisc++) {
348 int direction = 0;
349 int layer = absDisc;
350 if (absDisc >= mNumberOfDiscs[0]) {
351 direction = 1;
352 layer = absDisc - mNumberOfDiscs[0];
353 }
354 LOG(info) << "Direction " << direction << " layer " << layer;
355 if (absDisc >= mNumberOfStavesPerDisc.size())
356 LOG(fatal) << "Not enough entries in mNumberOfStavesPerDisc " << absDisc << " " << mNumberOfStavesPerDisc.size();
357 for (int stave = 0; stave < mNumberOfStavesPerDisc[absDisc]; stave++) {
358 int absStave = mStaveIdxDisc[absDisc] + stave;
359 if (absStave + 1 >= mChipIdxStave.size())
360 LOG(fatal) << "Attempting to get absStave + 1 from index array size " << mChipIdxStave.size();
361 int nChip = mChipIdxStave[absStave + 1] - mChipIdxStave[absStave]; // TODO: this is too often == 0
362 LOG(debug) << "Getting matrices for direction " << direction << " layer " << layer << " stave " << stave << " : " << nChip << " chips";
363 for (int chip = 0; chip < nChip; chip++) {
364 int chipIdx = getChipIndex(direction, layer, stave, chip);
365 if (!gGeoManager->cd(getMatrixPath(direction, layer, stave, chip).c_str()))
366 LOG(fatal) << "Geometry path not found " << getMatrixPath(direction, layer, stave, chip);
367 const TGeoHMatrix* matL2G = gGeoManager->GetCurrentMatrix();
368 if (chipIdx >= mSize)
369 LOG(fatal) << "ChipIdx " << chipIdx << " out of range " << mSize;
370 cacheL2G.setMatrix(Mat3D(*matL2G), chipIdx);
371
372 matL2G->LocalToMaster(locA, gloA);
373 matL2G->LocalToMaster(locB, gloB);
374 double dx = gloB[0] - gloA[0], dy = gloB[1] - gloA[1];
375 double t = (gloB[0] * dx + gloB[1] * dy) / (dx * dx + dy * dy);
376 xp = gloB[0] - dx * t;
377 yp = gloB[1] - dy * t;
378 float alp = std::atan2(yp, xp);
379 mCacheRefXDiscs.push_back(std::hypot(xp, yp));
380 o2::math_utils::bringTo02Pi(alp);
381 mCacheRefAlphaDiscs[chipIdx] = alp;
382
383 static TGeoHMatrix t2l;
384 t2l.Clear();
385 t2l.RotateZ(mCacheRefAlphaDiscs[chipIdx] * TMath::RadToDeg()); // TODO: do we need this cache?
386 const TGeoHMatrix& matL2Gi = matL2G->Inverse();
387 t2l.MultiplyLeft(&matL2Gi);
388 cacheT2L.setMatrix(Mat3D(t2l), chipIdx); // TODO: may need deref with *
389 }
390 }
391 }
392 gGeoManager->PopPath();
393 }
394}
395
396//__________________________________________________________________________
397void GeometryTGeo::Print(Option_t*) const
398{
399 if (!isBuilt()) {
400 LOGF(info, "Geometry not built yet!");
401 return;
402 }
403 std::cout << "Detector ID: " << sInstance.get()->getDetID() << std::endl;
404
405 LOGF(info, "Summary of GeometryTGeo: %s", getName());
406 LOGF(info, "Number of disks: %d + %d", mNumberOfDiscs[0], mNumberOfDiscs[1]);
407 LOGF(info, "Total number of sensors: %d", mSize);
408}
409
410} // namespace ft3
411} // 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:54
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"