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