Project
Loading...
Searching...
No Matches
Detector.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
13
14#include "DetectorsBase/Stack.h"
15
16#include "TRKBase/Specs.h"
21#include <TGeoVolume.h>
22#include <TVirtualMC.h>
23#include <TVirtualMCStack.h>
24
25#include <FairVolume.h>
26
27#include <string>
28#include <type_traits>
29
30using o2::trkft3::Hit;
31
32namespace o2
33{
34namespace trk
35{
36
37float getDetLengthFromEta(const float eta, const float radius)
38{
39 return 2. * (10. + radius * std::cos(2 * std::atan(std::exp(-eta))));
40}
41
43 : o2::base::DetImpl<Detector>("TRK", true),
44 mTrackData(),
45 mHits(o2::utils::createSimVector<o2::trkft3::Hit>())
46{
47}
48
50 : o2::base::DetImpl<Detector>("TRK", true),
51 mTrackData(),
52 mHits(o2::utils::createSimVector<o2::trkft3::Hit>())
53{
54 auto& trkPars = TRKBaseParam::Instance();
55
56 if (trkPars.configFile != "") {
57 configFromFile(trkPars.configFile);
58 } else {
59 configMLOT();
62 }
63
64 LOGP(info, "Summary of TRK configuration:");
65 for (auto& layer : mLayers) {
66 LOGP(info, "Layer: {} name: {} r: {} cm | z: {} cm | thickness: {} cm", layer->getNumber(), layer->getName(), layer->getInnerRadius(), layer->getZ(), layer->getChipThickness());
67 }
68}
69
71 : o2::base::DetImpl<Detector>(other),
72 mTrackData(),
73 mHits(o2::utils::createSimVector<o2::trkft3::Hit>())
74{
75}
76
78{
79 if (mHits) {
81 }
82}
83
89
91{
92 auto& trkPars = TRKBaseParam::Instance();
93
94 mLayers.clear();
95
96 const std::vector<float> rInn{7.f, 9.f, 12.f, 20.f, 30.f, 45.f, 60.f, 80.f};
97 const float thick = 100.e-3;
98
99 switch (trkPars.layoutMLOT) {
100 case kCylindrical: {
101 const std::vector<float> length{127.985f, 127.985f, 127.985f, 127.985f, 127.985f, 255.9f, 255.9f, 255.9f};
102 LOGP(warning, "Loading cylindrical configuration for ALICE3 TRK");
103 for (int i{0}; i < constants::ML::nLayers + constants::OT::nLayers; ++i) {
105 mLayers.push_back(std::make_unique<TRKCylindricalLayer>(i, name, rInn[i], length[i], thick, MatBudgetParamMode::Thickness));
106 }
107 break;
108 }
109 case kSegmented: {
110 const std::vector<float> tiltAngles{11.2f, 11.9f, 11.4f, 0.f, 0.f, 0.f, 0.f, 0.f};
111 // const std::vector<float> tiltAngles{10.f, 16.1f, 19.2f, 0.f, 0.f, 0.f, 0.f, 0.f};
112 const std::vector<int> nStaves{10, 14, 18, 26, 38, 32, 42, 56};
113 // const std::vector<int> nStaves{10, 16, 22, 26, 38, 32, 42, 56};
114 const std::vector<int> nMods{11, 11, 11, 11, 11, 22, 22, 22};
115
116 const std::vector<float> stagOffsets{0.f, 0.f, 0.f, 1.17f, 0.89f};
117
118 LOGP(warning, "Loading segmented configuration for ALICE3 TRK");
119 for (int i{0}; i < constants::ML::nLayers + constants::OT::nLayers; ++i) {
122 mLayers.push_back(std::make_unique<TRKMLLayer>(i, name, rInn[i], stagOffsets[i], tiltAngles[i], nStaves[i], nMods[i], thick, MatBudgetParamMode::Thickness));
123 } else {
124 mLayers.push_back(std::make_unique<TRKOTLayer>(i, name, rInn[i], tiltAngles[i], nStaves[i], nMods[i], thick, MatBudgetParamMode::Thickness));
125 }
126 }
127 break;
128 }
130 // Same ML as segmented; OT uses the detailed (realistic) barrel.
131 const std::vector<float> tiltAngles{11.2f, 11.9f, 11.4f, 0.f, 0.f, 0.f, 0.f, 0.f};
132 const std::vector<int> nMods{11, 11, 11, 11, 11, 22, 22, 22};
133 const std::vector<float> stagOffsets{0.f, 0.f, 0.f, 1.17f, 0.89f};
134
135 // OT radii chosen at the top of a stave-count band, where the paving closes with
136 // ~1.5-1.9 mm of neighbour overlap; the outermost also clears TRKServices::sOTShellRMin.
137 std::vector<float> rInnReal = rInn;
138 rInnReal[constants::ML::nLayers + 0] = 44.0f;
139 rInnReal[constants::ML::nLayers + 1] = 61.5f;
140 rInnReal[constants::ML::nLayers + 2] = 79.3f;
141 // OT counts are informational: TRKOTLayerRealistic derives its own from the radius.
142 const std::vector<int> nStaves{10, 14, 18, 26, 38, 30, 42, 54};
143
144 LOGP(warning, "Loading simplified-realistic configuration for ALICE3 TRK");
145 for (int i{0}; i < constants::ML::nLayers + constants::OT::nLayers; ++i) {
148 mLayers.push_back(std::make_unique<TRKMLLayer>(i, name, rInnReal[i], stagOffsets[i], tiltAngles[i], nStaves[i], nMods[i], thick, MatBudgetParamMode::Thickness));
149 } else {
150 mLayers.push_back(std::make_unique<TRKOTLayerRealistic>(i, name, rInnReal[i], tiltAngles[i], nStaves[i], nMods[i], thick, MatBudgetParamMode::Thickness));
151 }
152 }
153 break;
154 }
155 default:
156 LOGP(fatal, "Unknown option {} for configMLOT", static_cast<int>(trkPars.layoutMLOT));
157 break;
158 }
159}
160
161void Detector::configFromFile(std::string fileName)
162{
163 // Override the default geometry if config file provided
164 std::ifstream confFile(fileName);
165 if (!confFile.good()) {
166 LOGP(fatal, "File {} not found, aborting.", fileName);
167 }
168
169 auto& trkPars = TRKBaseParam::Instance();
170
171 mLayers.clear();
172
173 LOGP(info, "Overriding geometry of ALICE3 TRK using {} file.", fileName);
174
175 std::string line;
176 std::vector<float> tmpBuff;
177 int layerCount{0};
178 while (std::getline(confFile, line)) {
179 if (line[0] == '/') {
180 continue;
181 }
182 tmpBuff.clear();
183 std::stringstream ss(line);
184 float val;
185 std::string substr;
186 while (getline(ss, substr, '\t')) {
187 tmpBuff.push_back(std::stof(substr));
188 }
189
190 std::string name = GeometryTGeo::getTRKLayerPattern() + std::to_string(layerCount);
191
192 switch (trkPars.layoutMLOT) {
193 case kCylindrical: {
194 // Expected column mapping in the text file (separated by \t):
195 // tmpBuff[0] = rInn
196 // tmpBuff[1] = length
197 // tmpBuff[2] = thick
198 // tmpBuff[3] = matBudgetMode (optional, default = Thickness)
199
200 // Cylindrical requires at least 3 parameters
201 if (tmpBuff.size() < 3) {
202 LOGP(fatal, "Invalid configuration for cylindrical layer {}: insufficient parameters.", layerCount);
203 }
204
205 float rInn = tmpBuff[0];
206 float length = tmpBuff[1];
207 float thick = tmpBuff[2];
208
209 // Default mode is Thickness
211 if (tmpBuff.size() >= 4) {
212 matBudgetMode = static_cast<MatBudgetParamMode>(static_cast<int>(tmpBuff[3]));
213 }
214
215 mLayers.push_back(std::make_unique<TRKCylindricalLayer>(layerCount, name, rInn, length, thick, matBudgetMode));
216 break;
217 }
218 case kSegmented:
220 // Expected column mapping in the text file (separated by \t):
221 // tmpBuff[0] = rInn
222 // tmpBuff[1] = thick
223 // tmpBuff[2] = tiltAngle
224 // tmpBuff[3] = nStaves
225 // tmpBuff[4] = nMods
226 // tmpBuff[5] = stagOffset (required ONLY for ML)
227 // tmpBuff[6] = matBudgetMode (optional, default = Thickness)
228
229 // Base parameters for all segmented layers (at least 5 needed)
230 if (tmpBuff.size() < 5) {
231 LOGP(fatal, "Invalid configuration for segmented layer {}: missing base parameters.", layerCount);
232 }
233
234 float rInn = tmpBuff[0];
235 float thick = tmpBuff[1];
236 float tiltAngle = tmpBuff[2];
237 int nStaves = static_cast<int>(tmpBuff[3]);
238 int nMods = static_cast<int>(tmpBuff[4]);
239
240 // Default mode is Thickness
242
243 if (layerCount < constants::ML::nLayers) {
244 // ML layers require stagOffset (index 5)
245 if (tmpBuff.size() < 6) {
246 LOGP(fatal, "Invalid configuration for ML layer {}: stagOffset is missing.", layerCount);
247 }
248 float stagOffset = tmpBuff[5];
249
250 if (tmpBuff.size() >= 7) {
251 matBudgetMode = static_cast<MatBudgetParamMode>(static_cast<int>(tmpBuff[6]));
252 }
253
254 mLayers.push_back(std::make_unique<TRKMLLayer>(layerCount, name, rInn, stagOffset, tiltAngle, nStaves, nMods, thick, matBudgetMode));
255 } else {
256 // OT layers do NOT have stagOffset. The optional mode is at index 5.
257 if (tmpBuff.size() >= 6) {
258 matBudgetMode = static_cast<MatBudgetParamMode>(static_cast<int>(tmpBuff[5]));
259 }
260
261 if (trkPars.layoutMLOT == kSimplifiedRealistic) {
262 mLayers.push_back(std::make_unique<TRKOTLayerRealistic>(layerCount, name, rInn, tiltAngle, nStaves, nMods, thick, matBudgetMode));
263 } else {
264 mLayers.push_back(std::make_unique<TRKOTLayer>(layerCount, name, rInn, tiltAngle, nStaves, nMods, thick, matBudgetMode));
265 }
266 }
267 break;
268 }
269 default:
270 LOGP(fatal, "Unknown option {} for configMLOT", static_cast<int>(trkPars.layoutMLOT));
271 break;
272 }
273
274 ++layerCount;
275 }
276}
277
278void Detector::configToFile(std::string fileName)
279{
280 LOGP(info, "Exporting TRK Detector layout to {}", fileName);
281 std::ofstream conFile(fileName.c_str(), std::ios::out);
282 conFile << "/// TRK configuration file: inn_radius z_length lay_thickness" << std::endl;
283 for (const auto& layer : mLayers) {
284 conFile << layer->getInnerRadius() << "\t" << layer->getZ() << "\t" << layer->getChipThickness() << std::endl;
285 }
286}
287
289{
290 mServices = TRKServices();
291}
292
294{
295 int ifield = 2; // ?
296 float fieldm = 10.0; // ?
298
299 float tmaxfdSi = 0.1; // .10000E+01; // Degree
300 float stemaxSi = 0.0075; // .10000E+01; // cm
301 float deemaxSi = 0.1; // 0.30000E-02; // Fraction of particle's energy 0<deemax<=1
302 float epsilSi = 1.0E-4; // .10000E+01;
303 float stminSi = 0.0; // cm "Default value used"
304
305 float tmaxfdAir = 0.1; // .10000E+01; // Degree
306 float stemaxAir = .10000E+01; // cm
307 float deemaxAir = 0.1; // 0.30000E-02; // Fraction of particle's energy 0<deemax<=1
308 float epsilAir = 1.0E-4; // .10000E+01;
309 float stminAir = 0.0; // cm "Default value used"
310
311 float tmaxfdCer = 0.1; // .10000E+01; // Degree
312 float stemaxCer = .10000E+01; // cm
313 float deemaxCer = 0.1; // 0.30000E-02; // Fraction of particle's energy 0<deemax<=1
314 float epsilCer = 1.0E-4; // .10000E+01;
315 float stminCer = 0.0; // cm "Default value used"
316
317 // Tracking parameters shared by the passive materials below
318 float tmaxfdPas = 0.1;
319 float stemaxPas = 1.0;
320 float deemaxPas = 0.1;
321 float epsilPas = 1.0E-4;
322 float stminPas = 0.0;
323
324 // AIR
325 float aAir[4] = {12.0107, 14.0067, 15.9994, 39.948};
326 float zAir[4] = {6., 7., 8., 18.};
327 float wAir[4] = {0.000124, 0.755267, 0.231781, 0.012827};
328 float dAir = 1.20479E-3;
329
330 // Carbon fiber
331 float aCf[2] = {12.0107, 1.00794};
332 float zCf[2] = {6., 1.};
333
334 // FPC: Kapton+Cu effective mixture, X0 ~ 5 cm
335 float aFpc[2] = {63.546f, 12.0107f}; // Cu, C (Kapton proxy)
336 float zFpc[2] = {29.f, 6.f};
337 float wFpc[2] = {0.40f, 0.60f};
338 float dFpc = 3.4f;
339
340 // ZIF connector: LCP+Cu effective mixture, X0 ~ 2.9 cm
341 float aLcpCu[2] = {63.546f, 12.0107f};
342 float zLcpCu[2] = {29.f, 6.f};
343 float wLcpCu[2] = {0.60f, 0.40f};
344 float dLcpCu = 5.5f;
345
346 // SMD capacitors: BaTiO3 ceramic, X0 ~ 1.9 cm
347 float aBaTiO3[3] = {137.327f, 47.867f, 15.9994f};
348 float zBaTiO3[3] = {56.f, 22.f, 8.f};
349 float wBaTiO3[3] = {0.5879f, 0.2054f, 0.2067f};
350 float dBaTiO3 = 6.0f;
351
352 // FR4 (PCB laminate) for the end-of-stave cards: 60% glass (SiO2) + 40% epoxy by weight
353 float aFr4[4] = {28.0855f, 15.9994f, 12.0107f, 1.00794f}; // Si, O, C, H
354 float zFr4[4] = {14.f, 8.f, 6.f, 1.f};
355 float wFr4[4] = {0.2804f, 0.3836f, 0.3040f, 0.0320f};
356 float dFr4 = 1.85f;
357
358 o2::base::Detector::Mixture(1, "AIR$", aAir, zAir, dAir, 4, wAir);
359 o2::base::Detector::Medium(1, "AIR$", 1, 0, ifield, fieldm, tmaxfdAir, stemaxAir, deemaxAir, epsilAir, stminAir);
360
361 o2::base::Detector::Material(3, "SILICON$", 0.28086E+02, 0.14000E+02, 0.23300E+01, 0.93600E+01, 0.99900E+03);
362 o2::base::Detector::Medium(3, "SILICON$", 3, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
363
364 // Carbon fibre: density tuned so X0 ~ 27 cm
365 o2::base::Detector::Material(4, "CARBONFIBER$", 12.0107f, 6.f, 1.45f, 27.0f, 999.f);
366 o2::base::Detector::Medium(4, "CARBONFIBER$", 4, 0, ifield, fieldm, tmaxfdPas, stemaxPas, deemaxPas, epsilPas, stminPas);
367
368 o2::base::Detector::Mixture(5, "FPC$", aFpc, zFpc, dFpc, 2, wFpc);
369 o2::base::Detector::Medium(5, "FPC$", 5, 0, ifield, fieldm, tmaxfdPas, stemaxPas, deemaxPas, epsilPas, stminPas);
370
371 o2::base::Detector::Mixture(6, "LCPCU$", aLcpCu, zLcpCu, dLcpCu, 2, wLcpCu);
372 o2::base::Detector::Medium(6, "LCPCU$", 6, 0, ifield, fieldm, tmaxfdPas, stemaxPas, deemaxPas, epsilPas, stminPas);
373
374 o2::base::Detector::Mixture(7, "BATIO3$", aBaTiO3, zBaTiO3, dBaTiO3, 3, wBaTiO3);
375 o2::base::Detector::Medium(7, "BATIO3$", 7, 0, ifield, fieldm, tmaxfdPas, stemaxPas, deemaxPas, epsilPas, stminPas);
376
377 // PEEK polymer for mounting brackets: X0 ~ 20 cm
378 o2::base::Detector::Material(8, "PEEK$", 12.0107f, 6.f, 1.32f, 20.0f, 999.f);
379 o2::base::Detector::Medium(8, "PEEK$", 8, 0, ifield, fieldm, tmaxfdPas, stemaxPas, deemaxPas, epsilPas, stminPas);
380
381 o2::base::Detector::Mixture(9, "FR4$", aFr4, zFr4, dFr4, 4, wFr4);
382 o2::base::Detector::Medium(9, "FR4$", 9, 0, ifield, fieldm, tmaxfdPas, stemaxPas, deemaxPas, epsilPas, stminPas);
383
384 // Copper planes of the end-of-stave cards: X0 = 1.436 cm
385 o2::base::Detector::Material(10, "COPPER$", 63.546f, 29.f, 8.96f, 1.436f, 999.f);
386 o2::base::Detector::Medium(10, "COPPER$", 10, 0, ifield, fieldm, tmaxfdPas, stemaxPas, deemaxPas, epsilPas, stminPas);
387}
388
390{
391 TGeoManager* geoManager = gGeoManager;
392 TGeoVolume* vALIC = geoManager->GetVolume("barrel");
393 if (!vALIC) {
394 LOGP(fatal, "Could not find barrel volume while constructing TRK geometry");
395 }
396 new TGeoVolumeAssembly(GeometryTGeo::getTRKVolPattern());
397 TGeoVolume* vTRK = geoManager->GetVolume(GeometryTGeo::getTRKVolPattern());
398 vALIC->AddNode(vTRK, 2, new TGeoTranslation(0, 30., 0));
399
400 char vstrng[100] = "TRKVol";
401 vTRK->SetTitle(vstrng);
402
403 for (auto& layer : mLayers) {
404 layer->createLayer(vTRK);
405 }
406
407 // Add service for inner tracker
408 mServices.createServices(vTRK);
409
410 // Build the VD using the petal builder
411 // Choose the VD design based on TRKBaseParam.layoutVD
412 auto& trkPars = TRKBaseParam::Instance();
413
415
416 switch (trkPars.layoutVD) {
417 case kIRIS4:
418 LOG(info) << "Building VD with IRIS4 layout";
420 break;
421 case kIRISFullCyl:
422 LOG(info) << "Building VD with IRIS fully cylindrical layout";
424 break;
426 LOG(info) << "Building VD with IRIS fully cylindrical layout with 3 inclined walls";
428 break;
429 case kIRIS5:
430 LOG(info) << "Building VD with IRIS5 layout";
432 break;
433 case kIRIS4a:
434 LOG(info) << "Building VD with IRIS4a layout";
436 break;
437 default:
438 LOG(fatal) << "Unknown VD layout option: " << static_cast<int>(trkPars.layoutVD);
439 break;
440 }
441
442 // Fill sensor names from registry right after geometry creation
443 const auto& regs = o2::trk::vdSensorRegistry();
444 mNumberOfVolumesVD = static_cast<int>(regs.size());
445 mNumberOfVolumes = mNumberOfVolumesVD + mLayers.size();
446 mSensorName.resize(mNumberOfVolumes);
447
448 // Fill VD sensor names from registry
449 int VDvolume = 0;
450 for (const auto& sensor : regs) {
451 mSensorName[VDvolume] = sensor.name;
452 VDvolume++;
453 }
454
455 // Add MLOT sensor names
456 for (int i = 0; i < mLayers.size(); i++) {
457 mSensorName[VDvolume++].Form("%s%d", GeometryTGeo::getTRKSensorPattern(), i);
458 }
459
460 for (auto vd : mSensorName) {
461 std::cout << "Volume name: " << vd << std::endl;
462 }
463
464 mServices.excavateFromVacuum("IRIS_CUTOUTsh");
465 mServices.registerVacuum(vTRK);
466}
467
469{
470 LOG(info) << "Initialize TRK O2Detector";
471 mGeometryTGeo = GeometryTGeo::Instance();
472 defineSensitiveVolumes();
473
474 mSensorID.resize(mNumberOfVolumes); // hardcoded. TODO: change size when a different namingh scheme for VD is in place. Ideally could be 4 petals + 8 layers = 12
475 for (int i = 0; i < mNumberOfVolumes; i++) {
476 mSensorID[i] = gMC ? TVirtualMC::GetMC()->VolId(mSensorName[i]) : 0; // Volume ID from the Geant geometry
477 LOGP(info, "{}: mSensorID={}, mSensorName={}", i, mSensorID[i], mSensorName[i].Data());
478 }
479}
480
481void Detector::defineSensitiveVolumes()
482{
483 TGeoManager* geoManager = gGeoManager;
484 TGeoVolume* v;
485
486 TString volumeName;
487 LOGP(info, "Adding TRK Sensitive Volumes");
488
489 // Register VD sensors created by VDGeometryBuilder
490 for (const auto& s : o2::trk::vdSensorRegistry()) {
491 TGeoVolume* v = gGeoManager->GetVolume(s.name.c_str());
492 if (!v) {
493 LOGP(warning, "VD sensor volume '{}' not found", s.name);
494 continue;
495 }
496 LOGP(info, "Adding VD Sensitive Volume {}", v->GetName());
497 AddSensitiveVolume(v);
498 // Optionally track first/last layers for TR references:
499 if (s.region == o2::trk::VDSensorDesc::Region::Barrel && (s.idx == 0 /*innermost*/)) {
500 mFirstOrLastLayers.push_back(s.name);
501 }
502 }
503
504 // The names of the TRK sensitive volumes have the format: TRKLayer(0...mLayers.size()-1)
505 for (int j{0}; j < mLayers.size(); j++) {
506 volumeName = GeometryTGeo::getTRKSensorPattern() + TString::Itoa(j, 10);
507 if (j == mLayers.size() - 1) {
508 mFirstOrLastLayers.push_back(volumeName.Data());
509 }
510 LOGP(info, "Trying {}", volumeName.Data());
511 v = geoManager->GetVolume(volumeName.Data());
512 LOGP(info, "Adding TRK Sensitive Volume {}", v->GetName());
513 AddSensitiveVolume(v);
514 }
515}
516
518
520{
521 // This will create a branch in the output tree called Hit, setting the last
522 // parameter to kFALSE means that this collection will not be written to the file,
523 // it will exist only during the simulation
524
525 if (FairRootManager::Instance()) {
526 FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, true);
527 }
528}
529
531{
532 if (!o2::utils::ShmManager::Instance().isOperational()) {
533 mHits->clear();
534 }
535}
536
537bool Detector::InsideFirstOrLastLayer(std::string layerName)
538{
539 bool inside = false;
540 for (auto& firstOrLastLayer : mFirstOrLastLayers) {
541 if (firstOrLastLayer == layerName) {
542 inside = true;
543 break;
544 }
545 }
546 return inside;
547}
548
549bool Detector::ProcessHits(FairVolume* vol)
550{
551 // This method is called from the MC stepping
552 if (!(fMC->TrackCharge())) {
553 return false;
554 }
555
556 int subDetID = -1;
557 int layer = -1;
558 int volume = 0;
559 int volID = vol->getMCid();
560
561 bool notSens = false;
562 while ((volume < mNumberOfVolumes) && (notSens = (volID != mSensorID[volume]))) {
563 ++volume;
564 }
565
566 if (notSens) {
567 return kFALSE; // RS: can this happen? This method must be called for sensors only?
568 }
569
570 if (volume < mNumberOfVolumesVD) {
571 subDetID = 0; // VD. For the moment each "chip" is a volume./// TODO: change this logic once the naming scheme is changed
572 } else {
573 subDetID = 1; // MLOT
574 layer = volume - mNumberOfVolumesVD;
575 }
576
577 // Is it needed to keep a track reference when the outer ITS volume is encountered?
578 auto stack = (o2::data::Stack*)fMC->GetStack();
579 // if (fMC->IsTrackExiting() && (lay == 0 || lay == mLayers.size() - 1)) {
580 if (fMC->IsTrackExiting() && InsideFirstOrLastLayer(vol->GetName())) {
581 // Keep the track refs for the innermost and outermost layers only
582 o2::TrackReference tr(*fMC, GetDetId());
583 tr.setTrackID(stack->GetCurrentTrackNumber());
584 tr.setUserId(volume);
585 stack->addTrackReference(tr);
586 }
587 bool startHit = false, stopHit = false;
588 unsigned char status = 0;
589 if (fMC->IsTrackEntering()) {
590 status |= Hit::kTrackEntering;
591 }
592 if (fMC->IsTrackInside()) {
593 status |= Hit::kTrackInside;
594 }
595 if (fMC->IsTrackExiting()) {
596 status |= Hit::kTrackExiting;
597 }
598 if (fMC->IsTrackOut()) {
599 status |= Hit::kTrackOut;
600 }
601 if (fMC->IsTrackStop()) {
602 status |= Hit::kTrackStopped;
603 }
604 if (fMC->IsTrackAlive()) {
605 status |= Hit::kTrackAlive;
606 }
607
608 // track is entering or created in the volume
609 if ((status & Hit::kTrackEntering) || (status & Hit::kTrackInside && !mTrackData.mHitStarted)) {
610 startHit = true;
611 } else if ((status & (Hit::kTrackExiting | Hit::kTrackOut | Hit::kTrackStopped))) {
612 stopHit = true;
613 }
614
615 // increment energy loss at all steps except entrance
616 if (!startHit) {
617 mTrackData.mEnergyLoss += fMC->Edep();
618 }
619 if (!(startHit | stopHit)) {
620 return false; // do noting
621 }
622
623 if (startHit) {
624 mTrackData.mEnergyLoss = 0.;
625 fMC->TrackMomentum(mTrackData.mMomentumStart);
626 fMC->TrackPosition(mTrackData.mPositionStart);
627 mTrackData.mTrkStatusStart = status;
628 mTrackData.mHitStarted = true;
629 }
630 if (stopHit) {
631 TLorentzVector positionStop;
632 fMC->TrackPosition(positionStop);
633
634 // Retrieve the indices with the volume path
635 int stave(0), halfstave(0), mod(0), chip(0);
636
637 auto& trkPars = TRKBaseParam::Instance();
638
639 if (subDetID == 1) {
640 if (trkPars.layoutMLOT == o2::trk::eMLOTLayout::kSegmented) {
641 fMC->CurrentVolOffID(1, chip);
642 fMC->CurrentVolOffID(2, mod);
643 if (mGeometryTGeo->getNumberOfHalfStaves(layer) == 2) {
644 fMC->CurrentVolOffID(3, halfstave);
645 fMC->CurrentVolOffID(4, stave);
646 } else if (mGeometryTGeo->getNumberOfHalfStaves(layer) == 1) {
647 fMC->CurrentVolOffID(3, stave);
648 } else {
649 LOGP(fatal, "Wrong number of halfstaves for layer {}", layer);
650 }
651 } else if (trkPars.layoutMLOT == o2::trk::eMLOTLayout::kSimplifiedRealistic) {
652 // Stave/half-stave/module are assembly volumes here, for which CurrentVolOffID copy
653 // numbers all read 0; resolve the indices from the TGeo path at the hit mid-point.
654 const TVector3 mid = (mTrackData.mPositionStart.Vect() + positionStop.Vect()) * 0.5;
655 gGeoManager->PushPath();
656 if (gGeoManager->FindNode(mid.X(), mid.Y(), mid.Z())) {
657 auto copyUp = [](int up) { TGeoNode* n = gGeoManager->GetMother(up); return n ? n->GetNumber() : 0; };
658 chip = copyUp(1);
659 mod = copyUp(2);
660 if (mGeometryTGeo->getNumberOfHalfStaves(layer) == 2) {
661 halfstave = copyUp(3);
662 stave = copyUp(4);
663 } else if (mGeometryTGeo->getNumberOfHalfStaves(layer) == 1) {
664 stave = copyUp(3);
665 } else {
666 LOGP(fatal, "Wrong number of halfstaves for layer {}", layer);
667 }
668 }
669 gGeoManager->PopPath();
670 }
671 }
672
673 unsigned short chipID = mGeometryTGeo->getChipIndex(subDetID, volume, layer, stave, halfstave, mod, chip);
674
675 // Print(vol, volume, subDetID, layer, stave, halfstave, mod, chip, chipID);
676
677 // mGeometryTGeo->Print();
678
679 Hit* p = addHit(stack->GetCurrentTrackNumber(), chipID, mTrackData.mPositionStart.Vect(), positionStop.Vect(),
680 mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(),
681 mTrackData.mEnergyLoss, mTrackData.mTrkStatusStart, status);
682 // p->SetTotalEnergy(vmc->Etot());
683
684 // RS: not sure this is needed
685 // Increment number of Detector det points in TParticle
686 stack->addHit(GetDetId());
687 }
688
689 return true;
690}
691
692o2::trkft3::Hit* Detector::addHit(int trackID, unsigned short detID, const TVector3& startPos, const TVector3& endPos,
693 const TVector3& startMom, double startE, double endTime, double eLoss, unsigned char startStatus,
694 unsigned char endStatus)
695{
696 mHits->emplace_back(trackID, detID, startPos, endPos, startMom, startE, endTime, eLoss, startStatus, endStatus);
697 return &(mHits->back());
698}
699
700void Detector::Print(FairVolume* vol, int volume, int subDetID, int layer, int stave, int halfstave, int mod, int chip, int chipID) const
701{
702 int currentVol(0);
703 LOG(info) << "Current volume name: " << fMC->CurrentVolName() << " and ID " << fMC->CurrentVolID(currentVol);
704 LOG(info) << "volume: " << volume << "/" << mNumberOfVolumes - 1;
705
706 auto& trkPars = TRKBaseParam::Instance();
707
708 if (subDetID == 1) { // MLOT
709 if (trkPars.layoutMLOT == o2::trk::eMLOTLayout::kCylindrical) {
710 LOG(info) << "off volume name 1 " << fMC->CurrentVolOffName(1) << " chip: " << chip;
711 LOG(info) << "SubDetector ID: " << subDetID << " Layer: " << layer << " Chip ID: " << chipID;
712 } else {
713 LOG(info) << "off volume name 1 " << fMC->CurrentVolOffName(1) << " chip: " << chip;
714 LOG(info) << "off volume name 2 " << fMC->CurrentVolOffName(2) << " module: " << mod;
715 if (mGeometryTGeo->getNumberOfHalfStaves(layer) == 2) { // staggered geometry
716 LOG(info) << "off volume name 3 " << fMC->CurrentVolOffName(3) << " halfstave: " << halfstave;
717 LOG(info) << "off volume name 4 " << fMC->CurrentVolOffName(4) << " stave: " << stave;
718 LOG(info) << "SubDetector ID: " << subDetID << " Layer: " << layer << " staveinLayer: " << stave << " Chip ID: " << chipID;
719 } else if (mGeometryTGeo->getNumberOfHalfStaves(layer) == 1) { // turbo geometry
720 LOG(info) << "off volume name 3 " << fMC->CurrentVolOffName(3) << " stave: " << stave;
721 LOG(info) << "SubDetector ID: " << subDetID << " Layer: " << layer << " staveinLayer: " << stave << " Chip ID: " << chipID;
722 }
723 }
724 } else {
725 // VD
726 LOG(info) << "SubDetector ID: " << subDetID << " Chip ID: " << chipID;
727 }
728
729 LOG(info);
730}
731
732} // namespace trk
733} // namespace o2
734
736
737// Define Factory method for calling from the outside
738extern "C" {
743}
Definition of the Stack class.
int32_t i
uint32_t j
Definition RawData.h:0
uint32_t stack
Definition RawData.h:1
specs of the ALICE3 TRK
ClassImp(o2::trk::Detector)
o2::base::Detector * create_detector_trk(bool active)
Definition Detector.cxx:739
void setUserId(Int_t userId)
void setTrackID(Int_t track)
void Mixture(Int_t imat, const char *name, Float_t *a, Float_t *z, Float_t dens, Int_t nlmat, Float_t *wmat)
Definition Detector.cxx:66
void Medium(Int_t numed, const char *name, Int_t nmat, Int_t isvol, Int_t ifield, Float_t fieldm, Float_t tmaxfd, Float_t stemax, Float_t deemax, Float_t epsil, Float_t stmin, Float_t *ubuf=nullptr, Int_t nbuf=0)
Definition Detector.cxx:72
static void initFieldTrackingParams(int &mode, float &maxfield)
Definition Detector.cxx:143
void Material(Int_t imat, const char *name, Float_t a, Float_t z, Float_t dens, Float_t radl, Float_t absl, Float_t *buf=nullptr, Int_t nwbuf=0)
Definition Detector.cxx:59
std::string addNameTo(const char *ext) const
Definition Detector.h:150
void Reset() override
Definition Detector.cxx:530
void Register() override
Definition Detector.cxx:519
void ConstructGeometry() override
Definition Detector.cxx:84
void InitializeO2Detector() override
Definition Detector.cxx:468
o2::trkft3::Hit * addHit(int trackID, unsigned short detID, const TVector3 &startPos, const TVector3 &endPos, const TVector3 &startMom, double startE, double endTime, double eLoss, unsigned char startStatus, unsigned char endStatus)
Definition Detector.cxx:692
void configFromFile(std::string fileName="alice3_TRK_layout.txt")
Definition Detector.cxx:161
void EndOfEvent() override
Definition Detector.cxx:517
void Print(FairVolume *vol, int volume, int subDetID, int layer, int stave, int halfstave, int mod, int chip, int chipID) const
Number of TRK layers.
Definition Detector.cxx:700
static o2::base::Detector * create(bool active)
Definition Detector.h:39
void configToFile(std::string fileName="alice3_TRK_layout.txt")
Definition Detector.cxx:278
bool ProcessHits(FairVolume *v=nullptr) override
Definition Detector.cxx:549
std::vector< int > mSensorID
Definition Detector.h:101
std::vector< TString > mSensorName
layer identifiers
Definition Detector.h:102
static const char * getTRKSensorPattern()
static const char * getTRKLayerPattern()
unsigned short getChipIndex(int subDetID, int petalcase, int disk, int lay, int stave, int halfstave, int mod, int chip) const
int getNumberOfHalfStaves(int lay) const
static const char * getTRKVolPattern()
static GeometryTGeo * Instance()
void registerVacuum(TGeoVolume *motherVolume)
void createServices(TGeoVolume *motherVolume)
void excavateFromVacuum(TString shapeToExcavate)
static ShmManager & Instance()
Definition ShmManager.h:61
GLdouble n
Definition glcorearb.h:1982
const GLdouble * v
Definition glcorearb.h:832
GLuint const GLchar * name
Definition glcorearb.h:781
GLboolean * data
Definition glcorearb.h:298
GLuint GLsizei GLsizei * length
Definition glcorearb.h:790
GLuint GLfloat * val
Definition glcorearb.h:1582
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
constexpr int nLayers
Definition Specs.h:105
constexpr int nLayers
Definition Specs.h:123
std::vector< VDSensorDesc > & vdSensorRegistry()
float getDetLengthFromEta(const float eta, const float radius)
Definition Detector.cxx:37
void createIRISGeometry3InclinedWalls(TGeoVolume *motherVolume)
void createIRISGeometryFullCyl(TGeoVolume *motherVolume)
void createIRIS4aGeometry(TGeoVolume *motherVolume)
MatBudgetParamMode
Definition TRKLayer.h:27
void createIRIS4Geometry(TGeoVolume *motherVolume)
void createIRIS5Geometry(TGeoVolume *motherVolume)
@ kIRISFullCyl3InclinedWalls
void clearVDSensorRegistry()
@ kSimplifiedRealistic
void freeSimVector(std::vector< T > *ptr)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
Common utility functions.
VectorOfTObjectPtrs other
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"