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