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
14
24
25#include "DetectorsBase/Stack.h"
27#include "fairlogger/Logger.h" // for LOG, LOG_IF
28
29// FairRoot includes
30#include "FairDetector.h" // for FairDetector
31#include "FairRootManager.h" // for FairRootManager
32#include "FairRun.h" // for FairRun
33#include "FairRuntimeDb.h" // for FairRuntimeDb
34#include "FairVolume.h" // for FairVolume
35#include "FairRootManager.h"
36
37#include "TGeoManager.h" // for TGeoManager, gGeoManager
38#include "TGeoTube.h" // for TGeoTube
39#include "TGeoPcon.h" // for TGeoPcon
40#include "TGeoVolume.h" // for TGeoVolume, TGeoVolumeAssembly
41#include "TString.h" // for TString, operator+
42#include "TVirtualMC.h" // for gMC, TVirtualMC
43#include "TVirtualMCStack.h" // for TVirtualMCStack
44#include "TFile.h" // for TVirtualMCStack
45#include "TGeoParallelWorld.h"
46
47#include <cstdio> // for NULL, snprintf
48#include <cmath>
49
50class FairModule;
51
52class TGeoMedium;
53
54class TParticle;
55
56using std::cout;
57using std::endl;
58
59using o2::itsmft::Hit;
61using namespace o2::its;
62
63#ifdef ENABLE_UPGRADES
64using namespace o2::its3;
65#endif
66
68 : o2::base::DetImpl<Detector>("ITS", kTRUE),
69 mTrackData(),
70 /*
71 mHitStarted(false),
72 mTrkStatusStart(),
73 mPositionStart(),
74 mMomentumStart(),
75 mEnergyLoss(),
76 */
77 mNumberOfDetectors(-1),
78 mModifyGeometry(kFALSE),
79 mNumberInnerLayers(3),
80 mHits(o2::utils::createSimVector<o2::itsmft::Hit>())
81{
82 mDescriptorIB = nullptr;
84}
85
86void Detector::configOuterBarrelITS(int nInnerBarrelLayers, int buildLevel)
87{
88 // build ITS outer barrel detector
89 const int kNLr = 4;
90 const int kSensTypeID = 0; // dummy id for Alpide sensor
91
92 const double ChipThicknessOB = 100.e-4;
93
94 const int kRmd = 1;
95 const int kNModPerStave = 3;
96 const int kPhi0 = 4;
97 const int kNStave = 5;
98 const int kNPar = 6;
99
100 // Radii are from last TDR (ALICE-TDR-017.pdf Tab. 1.1, rMid is mean value)
101
102 const double tdr5dat[kNLr][kNPar] = {
103 {-1, 19.45, -1, 4., 7.5, 24}, // for others: -, rMid, -, NMod/HStave, phi0, nStaves // 24 was 49
104 {-1, 24.40, -1, 4., 6., 30}, // 30 was 61
105 {-1, 34.24, -1, 7., 4.29, 42}, // 42 was 88
106 {-1, 39.20, -1, 7., 3.75, 48} // 48 was 100
107 };
108
109 double rLr, phi0, turbo;
110 int nStaveLr, nModPerStaveLr;
111
112 const int kNWrapVol = 2;
113 const double wrpRMin[kNWrapVol] = {19.2, 33.32};
114 const double wrpRMax[kNWrapVol] = {29.14, 44.9};
115 const double wrpZSpan[kNWrapVol] = {93., 163.0};
116
117 for (int iw = 0; iw < kNWrapVol; iw++) {
118 defineWrapperVolume(iw + 1, wrpRMin[iw], wrpRMax[iw], wrpZSpan[iw]); // first wrapper volume managed by DescriptorInnerBarrel
119 }
120
121 for (int idLr = 0; idLr < kNLr; idLr++) {
122 rLr = tdr5dat[idLr][kRmd];
123 phi0 = tdr5dat[idLr][kPhi0];
124
125 nStaveLr = TMath::Nint(tdr5dat[idLr][kNStave]);
126 nModPerStaveLr = TMath::Nint(tdr5dat[idLr][kNModPerStave]);
127 defineLayer(idLr + nInnerBarrelLayers, phi0, rLr, nStaveLr, nModPerStaveLr, ChipThicknessOB, Segmentation::SensorLayerThickness,
128 kSensTypeID, buildLevel);
129 }
130}
131
133 : o2::base::DetImpl<Detector>(name, active),
134 mTrackData(),
135 /*
136 mHitStarted(false),
137 mTrkStatusStart(),
138 mPositionStart(),
139 mMomentumStart(),
140 mEnergyLoss(),
141 */
142 mNumberOfDetectors(-1),
143 mModifyGeometry(kFALSE),
144 mNumberLayers(sNumberOuterLayers),
145 mHits(o2::utils::createSimVector<o2::itsmft::Hit>())
146{
147 if (name == "ITS") {
148 mDescriptorIB = std::make_shared<DescriptorInnerBarrelITS2>(3);
149 } else if (name == "IT3") {
150#ifdef ENABLE_UPGRADES
151 mDescriptorIB = std::make_shared<DescriptorInnerBarrelITS3>();
152#endif
153 } else {
154 LOG(fatal) << "Detector name not supported (options ITS and ITS3)";
155 }
156
158 int buildLevelITS = param.buildLevel;
159
160 TString detName = GetName();
161 if (detName == "ITS") {
162 dynamic_cast<DescriptorInnerBarrelITS2*>(mDescriptorIB.get())->configure(buildLevelITS);
163 } else if (detName == "IT3") {
164#ifdef ENABLE_UPGRADES
165 dynamic_cast<DescriptorInnerBarrelITS3*>(mDescriptorIB.get())->configure();
166#endif
167 }
168
169 mNumberInnerLayers = mDescriptorIB->getNumberOfLayers();
171
184 mGeometry.resize(mNumberLayers);
186
187 for (int j{0}; j < mNumberLayers; j++) {
188 if (detName == "IT3" && j < mNumberInnerLayers) {
190 } else {
191 mLayerName[j].Form("%s%d", GeometryTGeo::getITSSensorPattern(), j); // See V3Layer
192 }
193 LOGP(info, "{}: mLayerName={}", j, mLayerName[j].Data());
194 }
195
196 if (mNumberLayers > 0) { // if not, we'll Fatal-ize in CreateGeometry
197 for (Int_t j = 0; j < mNumberLayers; j++) {
198 mLayerPhi0[j] = 0;
199 mLayerRadii[j] = 0.;
200 mStavePerLayer[j] = 0;
201 mUnitPerStave[j] = 0;
202 mChipThickness[j] = 0.;
203 mStaveWidth[j] = 0.;
204 mStaveTilt[j] = 0.;
205 mDetectorThickness[j] = 0.;
206 mChipTypeID[j] = 0;
207 mBuildLevel[j] = 0;
208 mGeometry[j] = nullptr;
209 }
210 }
211 mServicesGeometry = nullptr;
212
213 for (int i = sNumberOfWrapperVolumes; i--;) {
215 }
216
218}
219
221 : o2::base::DetImpl<Detector>(rhs),
222 mTrackData(),
223 /*
224 mHitStarted(false),
225 mTrkStatusStart(),
226 mPositionStart(),
227 mMomentumStart(),
228 mEnergyLoss(),
229 */
230 mNumberOfDetectors(rhs.mNumberOfDetectors),
231 mModifyGeometry(rhs.mModifyGeometry),
232
234 mHits(o2::utils::createSimVector<o2::itsmft::Hit>())
235{
236 mDescriptorIB = rhs.mDescriptorIB;
237 mNumberInnerLayers = rhs.mNumberInnerLayers;
238 mNumberLayers = rhs.mNumberLayers;
240
241 TString detName = rhs.GetName();
242 for (int j{0}; j < mNumberLayers; j++) {
243 if (detName == "IT3" && j < mNumberInnerLayers) {
244 mLayerName[j].Form("%s%d", GeometryTGeo::getITS3SensorPattern(), j); // See V3Layer
245 } else {
246 mLayerName[j].Form("%s%d", GeometryTGeo::getITSSensorPattern(), j); // See V3Layer
247 }
248 }
249}
250
252{
253
254 if (mHits) {
255 // delete mHits;
257 }
258}
259
261{
262 // The standard = operator
263 // Inputs:
264 // Detector &h the sourse of this copy
265 // Outputs:
266 // none.
267 // Return:
268 // A copy of the sourse hit h
269
270 if (this == &rhs) {
271 return *this;
272 }
273
274 // base class assignment
276
277 mNumberOfDetectors = rhs.mNumberOfDetectors;
278
279 mModifyGeometry = rhs.mModifyGeometry;
280
282 mHits = nullptr;
283
284 mDescriptorIB = rhs.mDescriptorIB;
285
286 mNumberInnerLayers = rhs.mNumberInnerLayers;
287 mNumberLayers = rhs.mNumberLayers;
289
290 TString detName = rhs.GetName();
291 for (Int_t j = 0; j < mNumberLayers; j++) {
292 if (detName == "IT3" && j < mNumberInnerLayers) {
293 mLayerName[j].Form("%s%d", GeometryTGeo::getITS3SensorPattern(), j); // See V3Layer
294 } else {
295 mLayerName[j].Form("%s%d", GeometryTGeo::getITSSensorPattern(), j); // See V3Layer
296 }
297 }
298
299 return *this;
300}
301
303{
304 // Define the list of sensitive volumes
306
307 mLayerID.resize(mNumberLayers);
308 for (int i = 0; i < mNumberLayers; i++) {
309 mLayerID[i] = gMC ? TVirtualMC::GetMC()->VolId(mLayerName[i]) : 0;
310 }
311
313 // FairRuntimeDb* rtdb= FairRun::Instance()->GetRuntimeDb();
314 // O2itsGeoPar* par=(O2itsGeoPar*)(rtdb->getContainer("O2itsGeoPar"));
315}
316
317Bool_t Detector::ProcessHits(FairVolume* vol)
318{
319 // This method is called from the MC stepping
320 if (!(fMC->TrackCharge())) {
321 return kFALSE;
322 }
323
324 Int_t lay = 0, volID = vol->getMCid();
325
326 // FIXME: Determine the layer number. Is this information available directly from the FairVolume?
327 bool notSens = false;
328 while ((lay < mNumberLayers) && (notSens = (volID != mLayerID[lay]))) {
329 ++lay;
330 }
331 if (notSens) {
332 return kFALSE; // RS: can this happen? This method must be called for sensors only?
333 }
334
335 // Is it needed to keep a track reference when the outer ITS volume is encountered?
336 auto stack = (o2::data::Stack*)fMC->GetStack();
337 if (fMC->IsTrackExiting()) {
338 // Keep the track refs for the innermost and outermost layers only
339 o2::TrackReference tr(*fMC, GetDetId());
340 tr.setTrackID(stack->GetCurrentTrackNumber());
341 tr.setUserId(lay);
342 stack->addTrackReference(tr);
343 }
344 bool startHit = false, stopHit = false;
345 unsigned char status = 0;
346 if (fMC->IsTrackEntering()) {
347 status |= Hit::kTrackEntering;
348 }
349 if (fMC->IsTrackInside()) {
350 status |= Hit::kTrackInside;
351 }
352 if (fMC->IsTrackExiting()) {
353 status |= Hit::kTrackExiting;
354 }
355 if (fMC->IsTrackOut()) {
356 status |= Hit::kTrackOut;
357 }
358 if (fMC->IsTrackStop()) {
359 status |= Hit::kTrackStopped;
360 }
361 if (fMC->IsTrackAlive()) {
362 status |= Hit::kTrackAlive;
363 }
364
365 // track is entering or created in the volume
366 if ((status & Hit::kTrackEntering) || (status & Hit::kTrackInside && !mTrackData.mHitStarted)) {
367 startHit = true;
368 } else if ((status & (Hit::kTrackExiting | Hit::kTrackOut | Hit::kTrackStopped))) {
369 stopHit = true;
370 }
371
372 // increment energy loss at all steps except entrance
373 if (!startHit) {
374 mTrackData.mEnergyLoss += fMC->Edep();
375 }
376 if (!(startHit | stopHit)) {
377 return kFALSE; // do noting
378 }
379
380 if (startHit) {
382 fMC->TrackMomentum(mTrackData.mMomentumStart);
383 fMC->TrackPosition(mTrackData.mPositionStart);
385 mTrackData.mHitStarted = true;
386 }
387 if (stopHit) {
388 TLorentzVector positionStop;
389 fMC->TrackPosition(positionStop);
390 // Retrieve the indices with the volume path
391 int halfbarrel(0), stave(0), halfstave(0), chipinmodule(0), module(0);
392 fMC->CurrentVolOffID(1, chipinmodule);
393 fMC->CurrentVolOffID(2, module);
394 fMC->CurrentVolOffID(3, halfstave);
395 fMC->CurrentVolOffID(4, stave);
396 fMC->CurrentVolOffID(5, halfbarrel);
397 int chipindex = mGeometryTGeo->getChipIndex(lay, halfbarrel, stave, halfstave, module, chipinmodule);
398
399 Hit* p = addHit(stack->GetCurrentTrackNumber(), chipindex, mTrackData.mPositionStart.Vect(), positionStop.Vect(),
400 mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(),
402 // p->SetTotalEnergy(vmc->Etot());
403
404 // RS: not sure this is needed
405 // Increment number of Detector det points in TParticle
406 stack->addHit(GetDetId());
407 }
408
409 return kTRUE;
410}
411
413{
414 Int_t ifield = 2;
415 Float_t fieldm = 10.0;
418
419 Float_t tmaxfd = 0.1; // 1.0; // Degree
420 Float_t stemax = 1.0; // cm
421 Float_t deemax = 0.1; // 30.0; // Fraction of particle's energy 0<deemax<=1
422 Float_t epsil = 1.0E-4; // 1.0; // cm
423 Float_t stmin = 0.0; // cm "Default value used"
424
425 Float_t tmaxfdSi = 0.1; // .10000E+01; // Degree
426 Float_t stemaxSi = 0.0075; // .10000E+01; // cm
427 Float_t deemaxSi = 0.1; // 0.30000E-02; // Fraction of particle's energy 0<deemax<=1
428 Float_t epsilSi = 1.0E-4; // .10000E+01;
429 Float_t stminSi = 0.0; // cm "Default value used"
430
431 Float_t tmaxfdAir = 0.1; // .10000E+01; // Degree
432 Float_t stemaxAir = .10000E+01; // cm
433 Float_t deemaxAir = 0.1; // 0.30000E-02; // Fraction of particle's energy 0<deemax<=1
434 Float_t epsilAir = 1.0E-4; // .10000E+01;
435 Float_t stminAir = 0.0; // cm "Default value used"
436
437 // AIR
438 Float_t aAir[4] = {12.0107, 14.0067, 15.9994, 39.948};
439 Float_t zAir[4] = {6., 7., 8., 18.};
440 Float_t wAir[4] = {0.000124, 0.755267, 0.231781, 0.012827};
441 Float_t dAir = 1.20479E-3;
442
443 // Water
444 Float_t aWater[2] = {1.00794, 15.9994};
445 Float_t zWater[2] = {1., 8.};
446 Float_t wWater[2] = {0.111894, 0.888106};
447 Float_t dWater = 1.0;
448
449 // PEEK CF30
450 Float_t aPEEK[3] = {12.0107, 1.00794, 15.9994};
451 Float_t zPEEK[3] = {6., 1., 8.};
452 Float_t wPEEK[3] = {19., 12., 3};
453 Float_t dPEEK = 1.32;
454
455 // Kapton
456 Float_t aKapton[4] = {1.00794, 12.0107, 14.010, 15.9994};
457 Float_t zKapton[4] = {1., 6., 7., 8.};
458 Float_t wKapton[4] = {0.026362, 0.69113, 0.07327, 0.209235};
459 Float_t dKapton = 1.42;
460
461 // Tungsten Carbide
462 Float_t aWC[2] = {183.84, 12.0107};
463 Float_t zWC[2] = {74, 6};
464 Float_t wWC[2] = {0.5, 0.5};
465 Float_t dWC = 15.63;
466
467 // BEOL (Metal interconnection stack in Si sensors)
468 Float_t aBEOL[3] = {26.982, 28.086, 15.999};
469 Float_t zBEOL[3] = {13, 14, 8}; // Al, Si, O
470 Float_t wBEOL[3] = {0.170, 0.388, 0.442};
471 Float_t dBEOL = 2.28;
472
473 // Inox 304
474 Float_t aInox304[4] = {12.0107, 51.9961, 58.6928, 55.845};
475 Float_t zInox304[4] = {6., 24., 28, 26}; // C, Cr, Ni, Fe
476 Float_t wInox304[4] = {0.0003, 0.18, 0.10, 0}; // [3] will be computed
477 Float_t dInox304 = 7.85;
478
479 // Ceramic (for IB capacitors) (BaTiO3)
480 Float_t aCeramic[3] = {137.327, 47.867, 15.999};
481 Float_t zCeramic[3] = {56, 22, 8}; // Ba, Ti, O
482 Float_t wCeramic[3] = {1, 1, 3}; // Molecular composition
483 Float_t dCeramic = 6.02;
484
485 // Rohacell (C9 H13 N1 O2)
486 Float_t aRohac[4] = {12.01, 1.01, 14.010, 16.};
487 Float_t zRohac[4] = {6., 1., 7., 8.};
488 Float_t wRohac[4] = {9., 13., 1., 2.};
489 Float_t dRohac = 0.05;
490
491 // Rohacell RIST 110
492 Float_t dRist = 0.11;
493
494 // EN AW 7075 (Al alloy with Cu Mg Zn)
495 Float_t aENAW7075[4] = {26.98, 63.55, 24.31, 65.41};
496 Float_t zENAW7075[4] = {13., 29., 12., 30.};
497 Float_t wENAW7075[4] = {0., 0.015, 0.025, 0.055}; // [0] will be computed
498 Float_t dENAW7075 = 2.85;
499
500 // Brass CuZn39Pb3 (Cu Zn Pb)
501 Float_t aBrass[3] = {63.55, 65.41, 207.2};
502 Float_t zBrass[3] = {29., 30., 82.};
503 Float_t wBrass[3] = {0.58, 0.39, 0.03};
504 Float_t dBrass = 8.46;
505
506 // Polymer for ITS services
507 Float_t aPoly[2] = {12.01, 1.};
508 Float_t zPoly[2] = {6., 1.};
509 Float_t wPoly[2] = {0.857, .143};
510 Float_t dPoly = 0.9;
511
512 // Vespel for Beam Pipe Support (same definition of Polyimide in Pipe.cxx)
513 Float_t aVesp[4] = {16., 14., 12., 1.};
514 Float_t zVesp[4] = {8., 7., 6., 1.};
515 Float_t wVesp[4] = {5., 2., 22., 10.};
516 Float_t dVesp = 1.42;
517
518 o2::base::Detector::Mixture(1, "AIR$", aAir, zAir, dAir, 4, wAir);
519 o2::base::Detector::Medium(1, "AIR$", 1, 0, ifield, fieldm, tmaxfdAir, stemaxAir, deemaxAir, epsilAir, stminAir);
520
521 o2::base::Detector::Mixture(2, "WATER$", aWater, zWater, dWater, 2, wWater);
522 o2::base::Detector::Medium(2, "WATER$", 2, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
523
524 o2::base::Detector::Material(3, "SI$", 0.28086E+02, 0.14000E+02, 0.23300E+01, 0.93600E+01, 0.99900E+03);
525 o2::base::Detector::Medium(3, "SI$", 3, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
526
527 o2::base::Detector::Material(4, "BERILLIUM$", 9.01, 4., 1.848, 35.3, 36.7); // From AliPIPEv3
528 o2::base::Detector::Medium(4, "BERILLIUM$", 4, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
529
530 o2::base::Detector::Material(5, "COPPER$", 0.63546E+02, 0.29000E+02, 0.89600E+01, 0.14300E+01, 0.99900E+03);
531 o2::base::Detector::Medium(5, "COPPER$", 5, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
532
533 // needed for STAVE , Carbon, kapton, Epoxy, flexcable
534
535 // AliceO2::Base::Detector::Material(6,"CARBON$",12.0107,6,2.210,999,999);
536 o2::base::Detector::Material(6, "CARBON$", 12.0107, 6, 2.210 / 1.3, 999, 999);
537 o2::base::Detector::Medium(6, "CARBON$", 6, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
538
539 o2::base::Detector::Mixture(7, "KAPTON(POLYCH2)$", aKapton, zKapton, dKapton, 4, wKapton);
540 o2::base::Detector::Medium(7, "KAPTON(POLYCH2)$", 7, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
541
542 // values below modified as compared to source AliITSv11 !
543
544 // BEOL (Metal interconnection stack in Si sensors)
545 o2::base::Detector::Mixture(29, "METALSTACK$", aBEOL, zBEOL, dBEOL, 3, wBEOL);
546 o2::base::Detector::Medium(29, "METALSTACK$", 29, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
547
548 // Glue between IB chip and FPC: density reduced to take into account
549 // empty spaces (160 glue spots/chip , diam. 1 spot = 1 mm)
550 o2::base::Detector::Material(30, "GLUE_IBFPC$", 12.011, 6, 1.05 * 0.3, 999, 999);
551 o2::base::Detector::Medium(30, "GLUE_IBFPC$", 30, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
552
553 // Ceramic for IB capacitors (nmat < 0 => wmat contains number of atoms)
554 o2::base::Detector::Mixture(31, "CERAMIC$", aCeramic, zCeramic, dCeramic, -3, wCeramic);
555 o2::base::Detector::Medium(31, "CERAMIC$", 31, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
556
557 // All types of carbon
558 // Unidirectional prepreg
559 o2::base::Detector::Material(8, "K13D2U2k$", 12.0107, 6, 1.643, 999, 999);
560 o2::base::Detector::Medium(8, "K13D2U2k$", 8, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
561 o2::base::Detector::Material(17, "K13D2U120$", 12.0107, 6, 1.583, 999, 999);
562 o2::base::Detector::Medium(17, "K13D2U120$", 17, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
563 // Carbon prepreg woven
564 o2::base::Detector::Material(18, "F6151B05M$", 12.0107, 6, 2.133, 999, 999);
565 o2::base::Detector::Medium(18, "F6151B05M$", 18, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
566 // Impregnated thread
567 o2::base::Detector::Material(9, "M60J3K$", 12.0107, 6, 2.21, 999, 999);
568 o2::base::Detector::Medium(9, "M60J3K$", 9, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
569 // Impregnated thread
570 o2::base::Detector::Material(10, "M55J6K$", 12.0107, 6, 1.63, 999, 999);
571 o2::base::Detector::Medium(10, "M55J6K$", 10, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
572 // Fabric(0/90)
573 o2::base::Detector::Material(11, "T300$", 12.0107, 6, 1.725, 999, 999);
574 o2::base::Detector::Medium(11, "T300$", 11, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
575 // AMEC Thermasol
576 o2::base::Detector::Material(12, "FGS003$", 12.0107, 6, 1.6, 999, 999);
577 o2::base::Detector::Medium(12, "FGS003$", 12, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
578 // Carbon fleece
579 o2::base::Detector::Material(13, "CarbonFleece$", 12.0107, 6, 0.4, 999, 999);
580 o2::base::Detector::Medium(13, "CarbonFleece$", 13, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
581 // AS4C 200 gsm EX1515
582 o2::base::Detector::Material(37, "AS4C200$", 12.0107, 6, 1.48, 999, 999);
583 o2::base::Detector::Medium(37, "AS4C200$", 37, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
584
585 // Rohacell (various types)
586 o2::base::Detector::Mixture(32, "ROHACELL$", aRohac, zRohac, dRohac, -4, wRohac);
587 o2::base::Detector::Medium(32, "ROHACELL$", 32, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
588
589 o2::base::Detector::Mixture(38, "RIST110$", aRohac, zRohac, dRist, -4, wRohac);
590 o2::base::Detector::Medium(38, "RIST110$", 38, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
591
592 // Carbon prepreg (Cage)
593 o2::base::Detector::Material(33, "M46J6K$", 12.0107, 6, 1.48, 999, 999);
594 o2::base::Detector::Medium(33, "M46J6K$", 33, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
595
596 // PEEK CF30
597 o2::base::Detector::Mixture(19, "PEEKCF30$", aPEEK, zPEEK, dPEEK, -3, wPEEK);
598 o2::base::Detector::Medium(19, "PEEKCF30$", 19, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
599
600 // Flex cable
601 Float_t aFCm[5] = {12.0107, 1.00794, 14.0067, 15.9994, 26.981538};
602 Float_t zFCm[5] = {6., 1., 7., 8., 13.};
603 Float_t wFCm[5] = {0.520088819984, 0.01983871336, 0.0551367996, 0.157399667056, 0.247536};
604 // Float_t dFCm = 1.6087; // original
605 // Float_t dFCm = 2.55; // conform with STAR
606 Float_t dFCm = 2.595; // conform with Corrado
607
608 o2::base::Detector::Mixture(14, "FLEXCABLE$", aFCm, zFCm, dFCm, 5, wFCm);
609 o2::base::Detector::Medium(14, "FLEXCABLE$", 14, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
610
611 // AliceO2::Base::Detector::Material(7,"GLUE$",0.12011E+02,0.60000E+01,0.1930E+01/2.015,999,999);
612 // // original
613 o2::base::Detector::Material(15, "GLUE$", 12.011, 6, 1.93 / 2.015, 999, 999); // conform with ATLAS, Corrado, Stefan
614 o2::base::Detector::Medium(15, "GLUE$", 15, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
615
616 o2::base::Detector::Material(16, "ALUMINUM$", 0.26982E+02, 0.13000E+02, 0.26989E+01, 0.89000E+01, 0.99900E+03);
617 o2::base::Detector::Medium(16, "ALUMINUM$", 16, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
618
619 o2::base::Detector::Mixture(20, "TUNGCARB$", aWC, zWC, dWC, 2, wWC);
620 o2::base::Detector::Medium(20, "TUNGCARB$", 20, 0, ifield, fieldm, tmaxfd, stemax, deemaxSi, epsilSi, stminSi);
621
622 wInox304[3] = 1. - wInox304[0] - wInox304[1] - wInox304[2];
623 o2::base::Detector::Mixture(21, "INOX304$", aInox304, zInox304, dInox304, 4, wInox304);
624 o2::base::Detector::Medium(21, "INOX304$", 21, 0, ifield, fieldm, tmaxfd, stemax, deemaxSi, epsilSi, stminSi);
625
626 // Tungsten (for gamma converter rods)
627 o2::base::Detector::Material(28, "TUNGSTEN$", 183.84, 74, 19.25, 999, 999);
628 o2::base::Detector::Medium(28, "TUNGSTEN$", 28, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
629
630 // EN AW 7075 (Al alloy with Cu Mg Zn) (for Cage rails)
631 wENAW7075[0] = 1. - wENAW7075[1] - wENAW7075[2] - wENAW7075[3];
632 o2::base::Detector::Mixture(36, "ENAW7075$", aENAW7075, zENAW7075, dENAW7075, 4, wENAW7075);
633 o2::base::Detector::Medium(36, "ENAW7075$", 36, 0, ifield, fieldm, tmaxfd, stemax, deemaxSi, epsilSi, stminSi);
634
635 // Brass CuZn39Pb3
636 o2::base::Detector::Mixture(34, "BRASS$", aBrass, zBrass, dBrass, 3, wBrass);
637 o2::base::Detector::Medium(34, "BRASS$", 34, 0, ifield, fieldm, tmaxfd, stemax, deemaxSi, epsilSi, stminSi);
638
639 // Titanium
640 o2::base::Detector::Material(35, "TITANIUM$", 47.867, 22, 4.506, 999, 999);
641 o2::base::Detector::Medium(35, "TITANIUM$", 35, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
642
643 // Carbon-Fiber-Reinforced Polymer
644 o2::base::Detector::Material(43, "CFRP$", 12.01, 6, 1.55, 999, 999);
645 o2::base::Detector::Medium(43, "CFRP$", 43, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
646
647 // Vespel for Beam Pipe Support
648 o2::base::Detector::Mixture(44, "VESPEL$", aVesp, zVesp, dVesp, -4, wVesp);
649 o2::base::Detector::Medium(44, "VESPEL$", 44, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
650
651 // Carbon for ITS services
652 o2::base::Detector::Material(41, "C4SERVICES$", 12.01, 6, 1.75, 999, 999);
653 o2::base::Detector::Medium(41, "C4SERVICES$", 41, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
654
655 // Polymer for ITS services
656 o2::base::Detector::Mixture(42, "POLY4SERVICES$", aPoly, zPoly, dPoly, 2, wPoly);
657 o2::base::Detector::Medium(42, "POLY4SERVICES$", 42, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
658
659 // For ITS3
660
661 // Araldite 2011
662 Float_t dAraldite = 1.05;
663
664 // ERG Duocel
665 o2::base::Detector::Material(39, "ERGDUOCEL$", 12.0107, 6, 0.06, 999, 999);
666 o2::base::Detector::Medium(39, "ERGDUOCEL$", 39, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
667
668 // Impregnated carbon fleece
669 // (as educated guess we assume 50% carbon fleece 50% Araldite glue)
670 o2::base::Detector::Material(40, "IMPREG_FLEECE$", 12.0107, 6, 0.5 * (dAraldite + 0.4), 999, 999);
671 o2::base::Detector::Medium(40, "IMPREG_FLEECE$", 40, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
672}
673
675
677{
678 // This will create a branch in the output tree called Hit, setting the last
679 // parameter to kFALSE means that this collection will not be written to the file,
680 // it will exist only during the simulation
681
682 if (FairRootManager::Instance()) {
683 FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, kTRUE);
684 }
685}
686
688{
689 if (!o2::utils::ShmManager::Instance().isOperational()) {
690 mHits->clear();
691 }
692}
693
694void Detector::defineWrapperVolume(Int_t id, Double_t rmin, Double_t rmax, Double_t zspan)
695{
696 // set parameters of id-th wrapper volume
697 if (id >= sNumberOfWrapperVolumes || id < 0) {
698 LOG(fatal) << "id " << id << " of wrapper volume is not in 0-" << sNumberOfWrapperVolumes - 1 << " range";
699 }
700
701 mWrapperMinRadius[id] = rmin;
702 mWrapperMaxRadius[id] = rmax;
703 mWrapperZSpan[id] = zspan;
704}
705
706void Detector::defineLayer(Int_t nlay, Double_t phi0, Double_t r, Int_t nstav, Int_t nunit, Double_t lthick,
707 Double_t dthick, UInt_t dettypeID, Int_t buildLevel)
708{
709 // Sets the layer parameters
710 // Inputs:
711 // nlay layer number
712 // phi0 layer phi0
713 // r layer radius
714 // nstav number of staves
715 // nunit IB: number of chips per stave
716 // OB: number of modules per half stave
717 // lthick stave thickness (if omitted, defaults to 0)
718 // dthick detector thickness (if omitted, defaults to 0)
719 // dettypeID ??
720 // buildLevel (if 0, all geometry is build, used for material budget studies)
721 // Outputs:
722 // none.
723 // Return:
724 // none.
725
726 LOG(info) << "L# " << nlay << " Phi:" << phi0 << " R:" << r << " Nst:" << nstav << " Nunit:" << nunit
727 << " Lthick:" << lthick << " Dthick:" << dthick << " DetID:" << dettypeID << " B:" << buildLevel;
728
729 if (nlay >= mNumberLayers || nlay < 0) {
730 LOG(error) << "Wrong layer number " << nlay;
731 return;
732 }
733
734 mTurboLayer[nlay] = kFALSE;
735 mLayerPhi0[nlay] = phi0;
736 mLayerRadii[nlay] = r;
737 mStavePerLayer[nlay] = nstav;
738 mUnitPerStave[nlay] = nunit;
739 mChipThickness[nlay] = lthick;
740 mDetectorThickness[nlay] = dthick;
741 mChipTypeID[nlay] = dettypeID;
742 mBuildLevel[nlay] = buildLevel;
743}
744
745void Detector::getLayerParameters(Int_t nlay, Double_t& phi0, Double_t& r, Int_t& nstav, Int_t& nmod, Double_t& width,
746 Double_t& tilt, Double_t& lthick, Double_t& dthick, UInt_t& dettype) const
747{
748 // Gets the layer parameters
749 // Inputs:
750 // nlay layer number
751 // Outputs:
752 // phi0 phi of 1st stave
753 // r layer radius
754 // nstav number of staves
755 // nmod IB: number of chips per stave
756 // OB: number of modules per half stave
757 // width stave width
758 // tilt stave tilt angle
759 // lthick stave thickness
760 // dthick detector thickness
761 // dettype detector type
762 // Return:
763 // none.
764
765 if (nlay >= mNumberLayers || nlay < 0) {
766 LOG(error) << "Wrong layer number " << nlay;
767 return;
768 }
769
770 phi0 = mLayerPhi0[nlay];
771 r = mLayerRadii[nlay];
772 nstav = mStavePerLayer[nlay];
773 nmod = mUnitPerStave[nlay];
774 width = mStaveWidth[nlay];
775 tilt = mStaveTilt[nlay];
776 lthick = mChipThickness[nlay];
777 dthick = mDetectorThickness[nlay];
778 dettype = mChipTypeID[nlay];
779}
780
781TGeoVolume* Detector::createWrapperVolume(Int_t id)
782{
783 // Creates an air-filled wrapper cylindrical volume
784 // For OB a Pcon is needed to host the support rings
785 // while avoiding overlaps with MFT structures and OB cones
786
787 const Double_t suppRingAZlen = 4.;
788 const Double_t coneRingARmax = 33.96;
789 const Double_t coneRingAZlen[2] = {5.6, 0.3};
790 const Double_t suppRingCZlen[3] = {4.8, 4.0, 2.1};
791 const Double_t suppRingsRmin[3] = {23.35, 20.05, 35.4};
792
793 if (id > 0 && (mWrapperMinRadius[id] < 0 || mWrapperMaxRadius[id] < 0 || mWrapperZSpan[id] < 0)) { // check only for OB, IB managed in DescriptorInnerBarrel
794 LOG(fatal) << "Wrapper volume " << id << " was requested but not defined";
795 }
796
797 // Now create the actual shape and volume
798 TGeoShape* tube = nullptr;
799 Double_t zlen;
800 switch (id) {
801 case 0: // IB Layer 0,1,2: simple cylinder
802 {
803 tube = (TGeoShape*)mDescriptorIB->defineWrapperVolume();
804 } break;
805 case 1: // MB Layer 3,4: complex Pcon to avoid MFT overlaps
806 {
807 TGeoPcon* wrap = new TGeoPcon(0, 360, 6);
808 zlen = mWrapperZSpan[id] / 2 + suppRingCZlen[0];
809 wrap->DefineSection(0, -zlen, suppRingsRmin[0], mWrapperMaxRadius[id]);
810 zlen = mWrapperZSpan[id] / 2 + suppRingCZlen[1];
811 wrap->DefineSection(1, -zlen, suppRingsRmin[0], mWrapperMaxRadius[id]);
812 wrap->DefineSection(2, -zlen, suppRingsRmin[1], mWrapperMaxRadius[id]);
813 wrap->DefineSection(3, -mWrapperZSpan[id] / 2., suppRingsRmin[1], mWrapperMaxRadius[id]);
814 wrap->DefineSection(4, -mWrapperZSpan[id] / 2., mWrapperMinRadius[id], mWrapperMaxRadius[id]);
815 zlen = mWrapperZSpan[id] / 2 + suppRingAZlen;
816 wrap->DefineSection(5, zlen, mWrapperMinRadius[id], mWrapperMaxRadius[id]);
817 tube = (TGeoShape*)wrap;
818 } break;
819 case 2: // OB Layer 5,6: simpler Pcon to avoid OB cones overlaps
820 {
821 TGeoPcon* wrap = new TGeoPcon(0, 360, 6);
822 zlen = mWrapperZSpan[id] / 2;
823 wrap->DefineSection(0, -zlen, suppRingsRmin[2], mWrapperMaxRadius[id]);
824 zlen -= suppRingCZlen[2];
825 wrap->DefineSection(1, -zlen, suppRingsRmin[2], mWrapperMaxRadius[id]);
826 wrap->DefineSection(2, -zlen, mWrapperMinRadius[id], mWrapperMaxRadius[id]);
827 zlen = mWrapperZSpan[id] / 2 - coneRingAZlen[0];
828 wrap->DefineSection(3, zlen, mWrapperMinRadius[id], mWrapperMaxRadius[id]);
829 wrap->DefineSection(4, zlen, coneRingARmax, mWrapperMaxRadius[id]);
830 zlen = mWrapperZSpan[id] / 2 + coneRingAZlen[1];
831 wrap->DefineSection(5, zlen, coneRingARmax, mWrapperMaxRadius[id]);
832 tube = (TGeoShape*)wrap;
833 } break;
834 default: // Can never happen, keeps gcc quiet
835 break;
836 }
837
838 TGeoMedium* medAir = gGeoManager->GetMedium(Form("%s_AIR$", GetName()));
839
840 char volnam[30];
841 snprintf(volnam, 29, "%s%d", GeometryTGeo::getITSWrapVolPattern(), id);
842
843 auto* wrapper = new TGeoVolume(volnam, tube, medAir);
844
845 return wrapper;
846}
847
849{
850 // Create the detector materials
852
853 // Construct the detector geometry
855}
856
858{
859 // Create the geometry and insert it in the mother volume ITSV
860 TGeoManager* geoManager = gGeoManager;
861
862 TGeoVolume* vALIC = geoManager->GetVolume("barrel");
863
864 if (!vALIC) {
865 LOG(fatal) << "Could not find the top volume";
866 }
867
868 new TGeoVolumeAssembly(GeometryTGeo::getITSVolPattern());
869 TGeoVolume* vITSV = geoManager->GetVolume(GeometryTGeo::getITSVolPattern());
870 vALIC->AddNode(vITSV, 2, new TGeoTranslation(0, 30., 0)); // Copy number is 2 to cheat AliGeoManager::CheckSymNamesLUT
871
872 const Int_t kLength = 100;
873 Char_t vstrng[kLength] = "xxxRS"; //?
874 vITSV->SetTitle(vstrng);
875
876 // Check that we have all needed parameters for OB (no need IB, which is managed by the DescriptorInnerBarrel)
877 for (Int_t j = mNumberInnerLayers; j < mNumberLayers; j++) {
878 if (mLayerRadii[j] <= 0) {
879 LOG(fatal) << "Wrong layer radius for layer " << j << "(" << mLayerRadii[j] << ")";
880 }
881 if (mStavePerLayer[j] <= 0) {
882 LOG(fatal) << "Wrong number of staves for layer " << j << "(" << mStavePerLayer[j] << ")";
883 }
884 if (mUnitPerStave[j] <= 0) {
885 LOG(fatal) << "Wrong number of chips for layer " << j << "(" << mUnitPerStave[j] << ")";
886 }
887 if (mChipThickness[j] < 0) {
888 LOG(fatal) << "Wrong chip thickness for layer " << j << "(" << mChipThickness[j] << ")";
889 }
890 if (mTurboLayer[j] && mStaveWidth[j] <= 0) {
891 LOG(fatal) << "Wrong stave width for layer " << j << "(" << mStaveWidth[j] << ")";
892 }
893 if (mDetectorThickness[j] < 0) {
894 LOG(fatal) << "Wrong Sensor thickness for layer " << j << "(" << mDetectorThickness[j] << ")";
895 }
896
897 if (j > 0) {
898 if (mLayerRadii[j] <= mLayerRadii[j - 1]) {
899 LOG(fatal) << "Layer " << j << " radius (" << mLayerRadii[j] << ") is smaller than layer " << j - 1
900 << " radius (" << mLayerRadii[j - 1] << ")";
901 }
902 }
903
904 if (mChipThickness[j] == 0) {
905 LOG(info) << "Chip thickness for layer " << j << " not set, using default";
906 }
907 }
908
909 // Create the wrapper volumes
910 TGeoVolume** wrapVols = nullptr;
911
913 wrapVols = new TGeoVolume*[sNumberOfWrapperVolumes];
914 for (int id = 0; id < sNumberOfWrapperVolumes; id++) {
915 wrapVols[id] = createWrapperVolume(id);
916 vITSV->AddNode(wrapVols[id], 1, nullptr);
917 }
918 }
919
920 // Now create the actual geometry
921 for (Int_t j = 0; j < mNumberLayers; j++) {
922
923 if (j < mNumberInnerLayers) {
924 TString detName = GetName();
925 if (detName == "ITS") {
926 mGeometry[j] = ((DescriptorInnerBarrelITS2*)mDescriptorIB.get())->createLayer(j, wrapVols[0]); // define IB layers on first wrapper volume always
927 } else if (detName == "IT3") {
928#ifdef ENABLE_UPGRADES
929 ((DescriptorInnerBarrelITS3*)mDescriptorIB.get())->createLayer(j, wrapVols[0]); // define IB layers on first wrapper volume always
930#endif
931 }
932 mWrapperLayerId[j] = 0;
933 } else {
934 TGeoVolume* dest = vITSV;
935 mWrapperLayerId[j] = -1;
936
937 if (mTurboLayer[j]) {
938 mGeometry[j] = new V3Layer(j, kTRUE, kFALSE, GetName());
939 mGeometry[j]->setStaveWidth(mStaveWidth[j]);
940 mGeometry[j]->setStaveTilt(mStaveTilt[j]);
941 } else {
942 mGeometry[j] = new V3Layer(j, kFALSE, kFALSE, GetName());
943 }
944
945 mGeometry[j]->setPhi0(mLayerPhi0[j]);
946 mGeometry[j]->setRadius(mLayerRadii[j]);
947 mGeometry[j]->setNumberOfStaves(mStavePerLayer[j]);
948 mGeometry[j]->setNumberOfUnits(mUnitPerStave[j]);
949 mGeometry[j]->setChipType(mChipTypeID[j]);
950 mGeometry[j]->setBuildLevel(mBuildLevel[j]);
951
952 mGeometry[j]->setStaveModel(V3Layer::kOBModel2);
953
954 LOG(debug1) << "mBuildLevel: " << mBuildLevel[j];
955
956 if (mChipThickness[j] != 0) {
957 mGeometry[j]->setChipThick(mChipThickness[j]);
958 }
959 if (mDetectorThickness[j] != 0) {
960 mGeometry[j]->setSensorThick(mDetectorThickness[j]);
961 }
962
963 for (int iw = 0; iw < sNumberOfWrapperVolumes; iw++) {
965 LOG(debug) << "Will embed layer " << j << " in wrapper volume " << iw;
966
967 dest = wrapVols[iw];
968 mWrapperLayerId[j] = iw;
969 break;
970 }
971 }
972 mGeometry[j]->createLayer(dest);
973 }
974 }
975
976 // Now create the services
977 TString detName = GetName();
978 if (detName == "ITS") {
979 ((DescriptorInnerBarrelITS2*)mDescriptorIB.get())->createServices(wrapVols[0]);
980 } else if (detName == "IT3") {
981#ifdef ENABLE_UPGRADES
982 ((DescriptorInnerBarrelITS3*)mDescriptorIB.get())->createServices(wrapVols[0]);
983#endif
984 }
985
986 mServicesGeometry = new V3Services(detName);
987 createMiddlBarrelServices(wrapVols[1]);
988 createOuterBarrelServices(wrapVols[2]);
990
991 createITSServices(vALIC);
992
994
995 // Finally create and place the cage
996 V3Cage* cagePtr = new V3Cage(GetName());
997 cagePtr->createAndPlaceCage(vALIC); // vALIC = barrel
998
999 delete[] wrapVols; // delete pointer only, not the volumes
1000}
1001
1002void Detector::createMiddlBarrelServices(TGeoVolume* motherVolume)
1003{
1004 //
1005 // Creates the Middle Barrel Service structures
1006 //
1007 // Input:
1008 // motherVolume : the volume hosting the services
1009 //
1010 // Output:
1011 //
1012 // Return:
1013 //
1014 // Created: 24 Sep 2019 Mario Sitta
1015 //
1016
1017 // Create the End Wheels on Side A
1019
1020 // Create the End Wheels on Side C
1022}
1023
1024void Detector::createOuterBarrelServices(TGeoVolume* motherVolume)
1025{
1026 //
1027 // Creates the Outer Barrel Service structures
1028 //
1029 // Input:
1030 // motherVolume : the volume hosting the services
1031 //
1032 // Output:
1033 //
1034 // Return:
1035 //
1036 // Created: 27 Sep 2019 Mario Sitta
1037 //
1038
1039 // Create the End Wheels on Side A
1041
1042 // Create the End Wheels on Side C
1044}
1045
1046void Detector::createOuterBarrelSupports(TGeoVolume* motherVolume)
1047{
1048 //
1049 // Creates the Outer Barrel Service structures
1050 //
1051 // Input:
1052 // motherVolume : the volume hosting the supports
1053 //
1054 // Output:
1055 //
1056 // Return:
1057 //
1058 // Created: 26 Jan 2020 Mario Sitta
1059 // Updated: 02 Mar 2020 Mario Sitta
1060 //
1061
1062 // Create the Cone on Side A
1063 mServicesGeometry->createOBConeSideA(motherVolume);
1064
1065 // Create the Cone on Side C
1066 mServicesGeometry->createOBConeSideC(motherVolume);
1067
1068 // Create the CYSS Cylinder
1070}
1071
1072void Detector::createITSServices(TGeoVolume* motherVolume)
1073{
1074 //
1075 // Creates the ITS services: tubes, cables and the like
1076 //
1077 // Input:
1078 // motherVolume : the volume hosting the supports
1079 //
1080 // Output:
1081 //
1082 // Return:
1083 //
1084 // Created: 12 Apr 2023 Mario Sitta
1085 //
1086
1088}
1089
1091{
1092 //
1093 // Creates entries for alignable volumes associating the symbolic volume
1094 // name with the corresponding volume path.
1095 //
1096 // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot)
1097 //
1098
1099 LOG(info) << "Add ITS alignable volumes";
1100
1101 if (!gGeoManager) {
1102 LOG(fatal) << "TGeoManager doesn't exist !";
1103 return;
1104 }
1105
1106 TString detName = GetName();
1107 TString path = Form("/cave_1/barrel_1/%s_2", GeometryTGeo::getITSVolPattern());
1108 TString sname = GeometryTGeo::composeSymNameITS((detName == "IT3"));
1109
1110 LOG(debug) << sname << " <-> " << path;
1111
1112 if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) {
1113 LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path;
1114 }
1115
1116 Int_t lastUID = 0;
1117 for (Int_t lr = 0; lr < mNumberLayers; lr++) {
1118 if (lr < mNumberInnerLayers) {
1119 if (detName == "ITS") {
1121 }
1122 } else {
1123 addAlignableVolumesLayer(lr, path, lastUID);
1124 }
1125 }
1126
1127 return;
1128}
1129
1130void Detector::addAlignableVolumesLayer(int lr, TString& parent, Int_t& lastUID) const
1131{
1132 //
1133 // Add alignable volumes for a Layer and its daughters
1134 //
1135 // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot)
1136 // Updated: 06 Jul 2021 Mario Sitta Do not set Layer as alignable volume
1137 //
1138
1139 TString wrpV =
1140 mWrapperLayerId[lr] != -1 ? Form("%s%d_1", GeometryTGeo::getITSWrapVolPattern(), mWrapperLayerId[lr]) : "";
1141 TString path = Form("%s/%s/%s%d_1", parent.Data(), wrpV.Data(), GeometryTGeo::getITSLayerPattern(), lr);
1142 TString sname = GeometryTGeo::composeSymNameLayer(lr);
1143
1144 const V3Layer* lrobj = mGeometry[lr];
1145 Int_t nhbarrel = lrobj->getNumberOfHalfBarrelsPerParent();
1146 Int_t start = nhbarrel > 0 ? 0 : -1;
1147 for (Int_t hb = start; hb < nhbarrel; hb++) {
1148 addAlignableVolumesHalfBarrel(lr, hb, path, lastUID);
1149 }
1150
1151 return;
1152}
1153
1154void Detector::addAlignableVolumesHalfBarrel(Int_t lr, Int_t hb, TString& parent, Int_t& lastUID) const
1155{
1156 //
1157 // Add alignable volumes for a Half barrel and its daughters
1158 //
1159 // Created: 28 Jun 2021 Mario Sitta First version (based on similar methods)
1160 //
1161
1162 TString path = parent;
1163 if (hb >= 0) {
1164 path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSHalfBarrelPattern(), lr, hb);
1165 TString sname = GeometryTGeo::composeSymNameHalfBarrel(lr, hb);
1166
1167 LOG(debug) << "Add " << sname << " <-> " << path;
1168
1169 if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) {
1170 LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path;
1171 }
1172 }
1173
1174 const V3Layer* lrobj = mGeometry[lr];
1175 Int_t nstaves = lrobj->getNumberOfStavesPerParent();
1176 for (int st = 0; st < nstaves; st++) {
1177 addAlignableVolumesStave(lr, hb, st, path, lastUID);
1178 }
1179
1180 return;
1181}
1182
1183void Detector::addAlignableVolumesStave(Int_t lr, Int_t hb, Int_t st, TString& parent, Int_t& lastUID) const
1184{
1185 //
1186 // Add alignable volumes for a Stave and its daughters
1187 //
1188 // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot)
1189 // Updated: 29 Jun 2021 Mario Sitta Hal Barrel index added
1190 //
1191
1192 TString path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSStavePattern(), lr, st);
1193 TString sname = GeometryTGeo::composeSymNameStave(lr, hb, st);
1194
1195 LOG(debug) << "Add " << sname << " <-> " << path;
1196
1197 if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) {
1198 LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path;
1199 }
1200
1201 const V3Layer* lrobj = mGeometry[lr];
1202 Int_t nhstave = lrobj->getNumberOfHalfStavesPerParent();
1203 Int_t start = nhstave > 0 ? 0 : -1;
1204 for (Int_t sst = start; sst < nhstave; sst++) {
1205 addAlignableVolumesHalfStave(lr, hb, st, sst, path, lastUID);
1206 }
1207
1208 return;
1209}
1210
1211void Detector::addAlignableVolumesHalfStave(Int_t lr, Int_t hb, Int_t st, Int_t hst, TString& parent, Int_t& lastUID) const
1212{
1213 //
1214 // Add alignable volumes for a HalfStave (if any) and its daughters
1215 //
1216 // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot)
1217 // Updated: 29 Jun 2021 Mario Sitta Hal Barrel index added
1218 //
1219
1220 TString path = parent;
1221 if (hst >= 0) {
1222 path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSHalfStavePattern(), lr, hst);
1223 TString sname = GeometryTGeo::composeSymNameHalfStave(lr, hb, st, hst);
1224
1225 LOG(debug) << "Add " << sname << " <-> " << path;
1226
1227 if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) {
1228 LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path;
1229 }
1230 }
1231
1232 const V3Layer* lrobj = mGeometry[lr];
1233 Int_t nmodules = lrobj->getNumberOfModulesPerParent();
1234 Int_t start = nmodules > 0 ? 0 : -1;
1235 for (Int_t md = start; md < nmodules; md++) {
1236 addAlignableVolumesModule(lr, hb, st, hst, md, path, lastUID);
1237 }
1238
1239 return;
1240}
1241
1242void Detector::addAlignableVolumesModule(Int_t lr, Int_t hb, Int_t st, Int_t hst, Int_t md, TString& parent, Int_t& lastUID) const
1243{
1244 //
1245 // Add alignable volumes for a Module (if any) and its daughters
1246 //
1247 // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot)
1248 // Updated: 29 Jun 2021 Mario Sitta Hal Barrel index added
1249 //
1250
1251 TString path = parent;
1252 if (md >= 0) {
1253 path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSModulePattern(), lr, md);
1254 TString sname = GeometryTGeo::composeSymNameModule(lr, hb, st, hst, md);
1255
1256 LOG(debug) << "Add " << sname << " <-> " << path;
1257
1258 if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) {
1259 LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path;
1260 }
1261 }
1262
1263 const V3Layer* lrobj = mGeometry[lr];
1264 Int_t nchips = lrobj->getNumberOfChipsPerParent();
1265 for (Int_t ic = 0; ic < nchips; ic++) {
1266 addAlignableVolumesChip(lr, hb, st, hst, md, ic, path, lastUID);
1267 }
1268
1269 return;
1270}
1271
1272void Detector::addAlignableVolumesChip(Int_t lr, Int_t hb, Int_t st, Int_t hst, Int_t md, Int_t ch, TString& parent,
1273 Int_t& lastUID) const
1274{
1275 //
1276 // Add alignable volumes for a Chip
1277 //
1278 // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot)
1279 // Updated: 29 Jun 2021 Mario Sitta Hal Barrel index added
1280 //
1281
1282 TString path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSChipPattern(), lr, ch);
1283 TString sname = GeometryTGeo::composeSymNameChip(lr, hb, st, hst, md, ch);
1284 Int_t modUID = chipVolUID(lastUID++);
1285
1286 LOG(debug) << "Add " << sname << " <-> " << path;
1287
1288 if (gGeoManager->SetAlignableEntry(sname, path.Data(), modUID) == nullptr) {
1289 LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path;
1290 }
1291}
1292
1294{
1295 TGeoManager* geoManager = gGeoManager;
1296 TGeoVolume* v = nullptr;
1297
1298 TString volumeName;
1299
1300 // The names of the ITS sensitive volumes have the format: ITSUSensor(0...mNumberLayers-1)
1301 for (Int_t j = 0; j < mNumberLayers; j++) {
1302 TString detName = GetName();
1303 if (j < mNumberInnerLayers && detName == "IT3") {
1304 volumeName = GeometryTGeo::getITS3SensorPattern() + TString::Itoa(j, 10);
1305 } else {
1306 volumeName = GeometryTGeo::getITSSensorPattern() + TString::Itoa(j, 10);
1307 }
1308 v = geoManager->GetVolume(volumeName.Data());
1309 AddSensitiveVolume(v);
1310 }
1311}
1312
1314{
1315 TGeoParallelWorld* pw = gGeoManager->GetParallelWorld();
1316 if (pw == nullptr) {
1317 LOG(error) << "Parallel world was not created";
1318 return;
1319 }
1320 auto& param = ITSSimParam::Instance();
1321
1322 for (int iL{0}; iL < mNumberLayers; ++iL) {
1323 auto const layer = mGeometry[iL];
1324 int nhbarrels = layer->getNumberOfHalfBarrelsPerParent();
1325 int nstaves = layer->getNumberOfStavesPerParent();
1326 int nhstaves = layer->getNumberOfHalfStavesPerParent();
1327 int nmodules = layer->getNumberOfModulesPerParent();
1328 int nchips = layer->getNumberOfChipsPerParent();
1329
1330 for (int iHB{0}; iHB < nhbarrels; ++iHB) {
1331 for (int iS{0}; iS < nstaves; ++iS) {
1332 for (int iHS{nhstaves > 0 ? 0 : -1}; iHS < nhstaves; ++iHS) {
1333 for (int iM{nmodules > 0 ? 0 : -1}; iM < nmodules; ++iM) {
1334 for (int iC{0}; iC < nchips; ++iC) {
1335 TString sname = GeometryTGeo::composeSymNameChip(iL, iHB, iS, iHS, iM, iC);
1336 TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(sname);
1337 auto path = pne->GetTitle();
1338
1339 if (param.addMetalToPW) {
1340 TString metalPath = Form("%s/MetalStack_1", path);
1341 gGeoManager->MakePhysicalNode(metalPath);
1342 pw->AddNode(metalPath);
1343 }
1344 if (param.addSensorToPW) {
1345 TString sensorPath = Form("%s/ITSUSensor%d_1", path, iL);
1346 gGeoManager->MakePhysicalNode(sensorPath);
1347 pw->AddNode(sensorPath);
1348 }
1349 if (param.addChipToPW) {
1350 pw->AddNode(path);
1351 }
1352 }
1353 }
1354 }
1355 }
1356 }
1357 }
1358}
1359
1360Hit* Detector::addHit(int trackID, int detID, const TVector3& startPos, const TVector3& endPos,
1361 const TVector3& startMom, double startE, double endTime, double eLoss, unsigned char startStatus,
1362 unsigned char endStatus)
1363{
1364 mHits->emplace_back(trackID, detID, startPos, endPos, startMom, startE, endTime, eLoss, startStatus, endStatus);
1365 return &(mHits->back());
1366}
1367
1369
1370// Define Factory method for calling from the outside
1371extern "C" {
1376}
Definition of the Stack class.
Definition of the ITSMFT Hit class.
int32_t i
Definition of the GeometryTGeo class.
Definition of the Detector class.
o2::base::Detector * create_detector_its(const char *name, bool active)
ClassImp(IdPath)
uint32_t j
Definition RawData.h:0
uint32_t stack
Definition RawData.h:1
Definition of the SegmentationAlpide class.
Definition of the V3Cage class.
Definition of the V3Layer class.
Definition of the V3Services class.
std::ostringstream debug
benchmark::State & st
void setUserId(Int_t userId)
void setTrackID(Int_t track)
Detector & operator=(const Detector &)
Definition Detector.cxx:46
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 createOuterBarrelSupports(TGeoVolume *motherVolume)
Double_t mWrapperZSpan[sNumberOfWrapperVolumes]
Max radius of wrapper volume.
Definition Detector.h:256
void addAlignableVolumesModule(Int_t lr, Int_t hb, Int_t st, Int_t hst, Int_t md, TString &parent, Int_t &lastUID) const
struct o2::its::Detector::TrackData mTrackData
~Detector() override
Default destructor.
Definition Detector.cxx:251
Detector & operator=(const Detector &)
Definition Detector.cxx:260
std::vector< int > mStavePerLayer
Vector of layer radii.
Definition Detector.h:262
virtual void getLayerParameters(Int_t nlay, Double_t &phi0, Double_t &r, Int_t &nladd, Int_t &nmod, Double_t &width, Double_t &tilt, Double_t &lthick, Double_t &mthick, UInt_t &dettype) const
Definition Detector.cxx:745
void InitializeO2Detector() override
Initialization of the detector is done here.
Definition Detector.cxx:302
std::vector< V3Layer * > mGeometry
Definition Detector.h:306
Int_t chipVolUID(Int_t id) const
Definition Detector.h:219
virtual void createMaterials()
Create the detector materials.
Definition Detector.cxx:412
std::vector< double > mStaveWidth
Vector of chip thicknesses.
Definition Detector.h:265
Bool_t mModifyGeometry
Definition Detector.h:252
void defineLayer(Int_t nlay, Double_t phi0, Double_t r, Int_t nladd, Int_t nmod, Double_t lthick=0., Double_t dthick=0., UInt_t detType=0, Int_t buildFlag=0) override
Definition Detector.cxx:706
void addAlignableVolumesLayer(Int_t lr, TString &parent, Int_t &lastUID) const
std::vector< double > mChipThickness
Vector of number of "units" per stave.
Definition Detector.h:264
void createITSServices(TGeoVolume *motherVolume)
void addAlignableVolumesHalfStave(Int_t lr, Int_t hb, Int_t st, Int_t hst, TString &parent, Int_t &lastUID) const
std::vector< int > mWrapperLayerId
Z span of wrapper volume.
Definition Detector.h:257
void EndOfEvent() override
Definition Detector.cxx:674
std::vector< double > mStaveTilt
Vector of stave width (only used for turbo)
Definition Detector.h:266
std::vector< int > mBuildLevel
Vector of detector type id.
Definition Detector.h:269
o2::itsmft::Hit * addHit(int trackID, int detID, const TVector3 &startPos, const TVector3 &endPos, const TVector3 &startMom, double startE, double endTime, double eLoss, unsigned char startStatus, unsigned char endStatus)
This method is an example of how to add your own point of type Hit to the clones array.
std::vector< bool > mTurboLayer
Id of wrapper layer to which layer belongs (-1 if not wrapped)
Definition Detector.h:259
void constructDetectorGeometry()
Construct the detector geometry.
Definition Detector.cxx:857
void Register() override
Registers the produced collections in FAIRRootManager.
Definition Detector.cxx:676
std::vector< uint > mChipTypeID
Vector of detector thicknesses.
Definition Detector.h:268
Double_t mWrapperMinRadius[sNumberOfWrapperVolumes]
Definition Detector.h:254
Bool_t ProcessHits(FairVolume *v=nullptr) override
This method is called for each step during simulation (see FairMCApplication::Stepping())
Definition Detector.cxx:317
std::vector< int > mUnitPerStave
Vector of number of staves per layer.
Definition Detector.h:263
void ConstructGeometry() override
Base class to create the detector geometry.
Definition Detector.cxx:848
void addAlignableVolumesHalfBarrel(Int_t lr, Int_t hb, TString &parent, Int_t &lastUID) const
static constexpr Int_t sNumberOfWrapperVolumes
Number of wrapper volumes.
Definition Detector.h:75
static constexpr Int_t sNumberOuterLayers
Number of outer layers in ITSU (fixed)
Definition Detector.h:74
void addAlignableVolumes() const override
Add alignable top volumes.
void addAlignableVolumesChip(Int_t lr, Int_t hb, Int_t st, Int_t hst, Int_t md, Int_t ch, TString &parent, Int_t &lastUID) const
Detector()
Default constructor.
Definition Detector.cxx:67
void defineSensitiveVolumes()
Define the sensitive volumes of the geometry.
void createOuterBarrelServices(TGeoVolume *motherVolume)
static o2::base::Detector * create(const char *name, bool active)
Definition Detector.h:83
std::vector< double > mLayerPhi0
True for "turbo" layers.
Definition Detector.h:260
void fillParallelWorld() const override
Add ITS chip volumes to parallel world geometry.
int mNumberLayers
Number of inner layers (depends on ITS version)
Definition Detector.h:245
V3Services * mServicesGeometry
Geometry.
Definition Detector.h:307
std::vector< o2::itsmft::Hit > * mHits
Vector of Material Budget Studies.
Definition Detector.h:272
void createMiddlBarrelServices(TGeoVolume *motherVolume)
std::vector< double > mLayerRadii
Vector of layer's 1st stave phi in lab.
Definition Detector.h:261
std::vector< int > mLayerID
Number of layers (depends on inner layer version)
Definition Detector.h:247
Double_t mWrapperMaxRadius[sNumberOfWrapperVolumes]
Min radius of wrapper volume.
Definition Detector.h:255
Int_t mNumberOfDetectors
layer names
Definition Detector.h:250
std::shared_ptr< DescriptorInnerBarrel > mDescriptorIB
Services Geometry.
Definition Detector.h:309
std::vector< double > mDetectorThickness
Vector of stave tilt (only used for turbo)
Definition Detector.h:267
void addAlignableVolumesStave(Int_t lr, Int_t hb, Int_t st, TString &parent, Int_t &lastUID) const
std::vector< TString > mLayerName
layer identifiers
Definition Detector.h:248
TGeoVolume * createWrapperVolume(const Int_t nLay)
Creates an air-filled wrapper cylindrical volume.
Definition Detector.cxx:781
void Reset() override
Has to be called after each event to reset the containers.
Definition Detector.cxx:687
GeometryTGeo * mGeometryTGeo
Definition Detector.h:232
void defineWrapperVolume(Int_t id, Double_t rmin, Double_t rmax, Double_t zspan) override
Set per wrapper volume parameters.
Definition Detector.cxx:694
void configOuterBarrelITS(int nInnerBarrelLayers, int buildLevel=0)
We need this as a method to access members.
Definition Detector.cxx:86
static const char * getITSLayerPattern()
static const char * composeSymNameLayer(int lr, bool isITS3=false)
sym name of the layer
static const char * composeSymNameITS(bool isITS3=false)
sym name of the layer
static const char * getITS3SensorPattern()
static const char * getITSSensorPattern()
static const char * getITSHalfBarrelPattern()
static const char * composeSymNameHalfBarrel(int lr, int hba, bool isITS3=false)
Sym name of the half barrel at given layer.
static const char * composeSymNameHalfStave(int lr, int hba, int sta, int ssta, bool isITS3=false)
Sym name of the stave at given layer/halfbarrel.
static GeometryTGeo * Instance()
static const char * composeSymNameChip(int lr, int hba, int sta, int ssta, int mod, int chip, bool isITS3=false)
Sym name of the chip in the given layer/halfbarrel/stave/substave/module.
static const char * getITSChipPattern()
static const char * composeSymNameModule(int lr, int hba, int sta, int ssta, int mod, bool isITS3=false)
Sym name of the substave at given layer/halfbarrel/stave.
static const char * getITSVolPattern()
static const char * getITSModulePattern()
int getChipIndex(int lay, int detInLay) const
static const char * composeSymNameStave(int lr, int hba, int sta, bool isITS3=false)
Sym name of the stave at given layer.
static const char * getITSHalfStavePattern()
static const char * getITSStavePattern()
static const char * getITSWrapVolPattern()
This class defines the Geometry for the Cage of the ITS Upgrade using TGeo.
Definition V3Cage.h:38
void createAndPlaceCage(TGeoVolume *mother, const TGeoManager *mgr=gGeoManager)
Definition V3Cage.cxx:184
Int_t getNumberOfChipsPerParent() const
Definition V3Layer.h:110
Int_t getNumberOfHalfStavesPerParent() const
Definition V3Layer.h:106
Int_t getNumberOfHalfBarrelsPerParent() const
Definition V3Layer.h:102
Int_t getNumberOfStavesPerParent() const
Definition V3Layer.h:104
Int_t getNumberOfModulesPerParent() const
Definition V3Layer.h:108
This class defines the Geometry for the Services of the ITS Upgrade using TGeo.
Definition V3Services.h:39
void createMBEndWheelsSideC(TGeoVolume *mother, const TGeoManager *mgr=gGeoManager)
void createOBConeSideA(TGeoVolume *mother, const TGeoManager *mgr=gGeoManager)
void createMBEndWheelsSideA(TGeoVolume *mother, const TGeoManager *mgr=gGeoManager)
void createOBCYSSCylinder(TGeoVolume *mother, const TGeoManager *mgr=gGeoManager)
void createOBConeSideC(TGeoVolume *mother, const TGeoManager *mgr=gGeoManager)
void createOBEndWheelsSideC(TGeoVolume *mother, const TGeoManager *mgr=gGeoManager)
void createOBEndWheelsSideA(TGeoVolume *mother, const TGeoManager *mgr=gGeoManager)
void createAllITSServices(TGeoVolume *motherVolume, const TGeoManager *mgr=gGeoManager)
void createOBGammaConvWire(TGeoVolume *mother, const TGeoManager *mgr=gGeoManager)
static constexpr float SensorLayerThickness
static ShmManager & Instance()
Definition ShmManager.h:61
const GLdouble * v
Definition glcorearb.h:832
GLuint const GLchar * name
Definition glcorearb.h:781
GLint GLsizei width
Definition glcorearb.h:270
GLboolean * data
Definition glcorearb.h:298
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
GLboolean r
Definition glcorearb.h:1233
GLuint start
Definition glcorearb.h:469
GLenum GLfloat param
Definition glcorearb.h:271
GLuint id
Definition glcorearb.h:650
void freeSimVector(std::vector< T > *ptr)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Common utility functions.
double mEnergyLoss
momentum
Definition Detector.h:241
TLorentzVector mMomentumStart
position at entrance
Definition Detector.h:240
TLorentzVector mPositionStart
track status flag
Definition Detector.h:239
unsigned char mTrkStatusStart
hit creation started
Definition Detector.h:238
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"