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(debug, "{}: 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 // Density includes soldering
481 Float_t aCeramic[3] = {137.327, 47.867, 15.999};
482 Float_t zCeramic[3] = {56, 22, 8}; // Ba, Ti, O
483 Float_t wCeramic[3] = {1, 1, 3}; // Molecular composition
484 Float_t dCeramic = 8.28;
485
486 // Rohacell (C9 H13 N1 O2)
487 Float_t aRohac[4] = {12.01, 1.01, 14.010, 16.};
488 Float_t zRohac[4] = {6., 1., 7., 8.};
489 Float_t wRohac[4] = {9., 13., 1., 2.};
490 Float_t dRohac = 0.05;
491
492 // Rohacell RIST 110
493 Float_t dRist = 0.11;
494
495 // EN AW 7075 (Al alloy with Cu Mg Zn)
496 Float_t aENAW7075[4] = {26.98, 63.55, 24.31, 65.41};
497 Float_t zENAW7075[4] = {13., 29., 12., 30.};
498 Float_t wENAW7075[4] = {0., 0.015, 0.025, 0.055}; // [0] will be computed
499 Float_t dENAW7075 = 2.85;
500
501 // Brass CuZn39Pb3 (Cu Zn Pb)
502 Float_t aBrass[3] = {63.55, 65.41, 207.2};
503 Float_t zBrass[3] = {29., 30., 82.};
504 Float_t wBrass[3] = {0.58, 0.39, 0.03};
505 Float_t dBrass = 8.46;
506
507 // Polymer for ITS services
508 Float_t aPoly[2] = {12.01, 1.};
509 Float_t zPoly[2] = {6., 1.};
510 Float_t wPoly[2] = {0.857, .143};
511 Float_t dPoly = 0.9;
512
513 // Vespel for Beam Pipe Support (same definition of Polyimide in Pipe.cxx)
514 Float_t aVesp[4] = {16., 14., 12., 1.};
515 Float_t zVesp[4] = {8., 7., 6., 1.};
516 Float_t wVesp[4] = {5., 2., 22., 10.};
517 Float_t dVesp = 1.42;
518
519 o2::base::Detector::Mixture(1, "AIR$", aAir, zAir, dAir, 4, wAir);
520 o2::base::Detector::Medium(1, "AIR$", 1, 0, ifield, fieldm, tmaxfdAir, stemaxAir, deemaxAir, epsilAir, stminAir);
521
522 o2::base::Detector::Mixture(2, "WATER$", aWater, zWater, dWater, 2, wWater);
523 o2::base::Detector::Medium(2, "WATER$", 2, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
524
525 o2::base::Detector::Material(3, "SI$", 0.28086E+02, 0.14000E+02, 0.23300E+01, 0.93600E+01, 0.99900E+03);
526 o2::base::Detector::Medium(3, "SI$", 3, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
527
528 o2::base::Detector::Material(4, "BERILLIUM$", 9.01, 4., 1.848, 35.3, 36.7); // From AliPIPEv3
529 o2::base::Detector::Medium(4, "BERILLIUM$", 4, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
530
531 o2::base::Detector::Material(5, "COPPER$", 0.63546E+02, 0.29000E+02, 0.89600E+01, 0.14300E+01, 0.99900E+03);
532 o2::base::Detector::Medium(5, "COPPER$", 5, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
533
534 // needed for STAVE , Carbon, kapton, Epoxy, flexcable
535
536 // AliceO2::Base::Detector::Material(6,"CARBON$",12.0107,6,2.210,999,999);
537 o2::base::Detector::Material(6, "CARBON$", 12.0107, 6, 2.210 / 1.3, 999, 999);
538 o2::base::Detector::Medium(6, "CARBON$", 6, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
539
540 o2::base::Detector::Mixture(7, "KAPTON(POLYCH2)$", aKapton, zKapton, dKapton, 4, wKapton);
541 o2::base::Detector::Medium(7, "KAPTON(POLYCH2)$", 7, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
542
543 // values below modified as compared to source AliITSv11 !
544
545 // BEOL (Metal interconnection stack in Si sensors)
546 o2::base::Detector::Mixture(29, "METALSTACK$", aBEOL, zBEOL, dBEOL, 3, wBEOL);
547 o2::base::Detector::Medium(29, "METALSTACK$", 29, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
548
549 // Glue between IB chip and FPC: density reduced to take into account
550 // empty spaces (160 glue spots/chip , diam. 1 spot = 1 mm)
551 o2::base::Detector::Material(30, "GLUE_IBFPC$", 12.011, 6, 1.05 * 0.3, 999, 999);
552 o2::base::Detector::Medium(30, "GLUE_IBFPC$", 30, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
553
554 // Ceramic for IB capacitors (nmat < 0 => wmat contains number of atoms)
555 o2::base::Detector::Mixture(31, "CERAMIC$", aCeramic, zCeramic, dCeramic, -3, wCeramic);
556 o2::base::Detector::Medium(31, "CERAMIC$", 31, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
557
558 // All types of carbon
559 // Unidirectional prepreg
560 o2::base::Detector::Material(8, "K13D2U2k$", 12.0107, 6, 1.643, 999, 999);
561 o2::base::Detector::Medium(8, "K13D2U2k$", 8, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
562 o2::base::Detector::Material(17, "K13D2U120$", 12.0107, 6, 1.583, 999, 999);
563 o2::base::Detector::Medium(17, "K13D2U120$", 17, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
564 // Carbon prepreg woven
565 o2::base::Detector::Material(18, "F6151B05M$", 12.0107, 6, 2.133, 999, 999);
566 o2::base::Detector::Medium(18, "F6151B05M$", 18, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
567 // Impregnated thread
568 o2::base::Detector::Material(9, "M60J3K$", 12.0107, 6, 2.21, 999, 999);
569 o2::base::Detector::Medium(9, "M60J3K$", 9, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
570 // Impregnated thread
571 o2::base::Detector::Material(10, "M55J6K$", 12.0107, 6, 1.63, 999, 999);
572 o2::base::Detector::Medium(10, "M55J6K$", 10, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
573 // Fabric(0/90)
574 o2::base::Detector::Material(11, "T300$", 12.0107, 6, 1.725, 999, 999);
575 o2::base::Detector::Medium(11, "T300$", 11, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
576 // AMEC Thermasol
577 o2::base::Detector::Material(12, "FGS003$", 12.0107, 6, 1.6, 999, 999);
578 o2::base::Detector::Medium(12, "FGS003$", 12, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
579 // Carbon fleece
580 o2::base::Detector::Material(13, "CarbonFleece$", 12.0107, 6, 0.4, 999, 999);
581 o2::base::Detector::Medium(13, "CarbonFleece$", 13, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
582 // AS4C 200 gsm EX1515
583 o2::base::Detector::Material(37, "AS4C200$", 12.0107, 6, 1.48, 999, 999);
584 o2::base::Detector::Medium(37, "AS4C200$", 37, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
585
586 // Rohacell (various types)
587 o2::base::Detector::Mixture(32, "ROHACELL$", aRohac, zRohac, dRohac, -4, wRohac);
588 o2::base::Detector::Medium(32, "ROHACELL$", 32, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
589
590 o2::base::Detector::Mixture(38, "RIST110$", aRohac, zRohac, dRist, -4, wRohac);
591 o2::base::Detector::Medium(38, "RIST110$", 38, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
592
593 // Carbon prepreg (Cage)
594 o2::base::Detector::Material(33, "M46J6K$", 12.0107, 6, 1.48, 999, 999);
595 o2::base::Detector::Medium(33, "M46J6K$", 33, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
596
597 // PEEK CF30
598 o2::base::Detector::Mixture(19, "PEEKCF30$", aPEEK, zPEEK, dPEEK, -3, wPEEK);
599 o2::base::Detector::Medium(19, "PEEKCF30$", 19, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
600
601 // Flex cable
602 Float_t aFCm[5] = {12.0107, 1.00794, 14.0067, 15.9994, 26.981538};
603 Float_t zFCm[5] = {6., 1., 7., 8., 13.};
604 Float_t wFCm[5] = {0.520088819984, 0.01983871336, 0.0551367996, 0.157399667056, 0.247536};
605 // Float_t dFCm = 1.6087; // original
606 // Float_t dFCm = 2.55; // conform with STAR
607 Float_t dFCm = 2.595; // conform with Corrado
608
609 o2::base::Detector::Mixture(14, "FLEXCABLE$", aFCm, zFCm, dFCm, 5, wFCm);
610 o2::base::Detector::Medium(14, "FLEXCABLE$", 14, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
611
612 // AliceO2::Base::Detector::Material(7,"GLUE$",0.12011E+02,0.60000E+01,0.1930E+01/2.015,999,999);
613 // // original
614 o2::base::Detector::Material(15, "GLUE$", 12.011, 6, 1.93 / 2.015, 999, 999); // conform with ATLAS, Corrado, Stefan
615 o2::base::Detector::Medium(15, "GLUE$", 15, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
616
617 o2::base::Detector::Material(16, "ALUMINUM$", 0.26982E+02, 0.13000E+02, 0.26989E+01, 0.89000E+01, 0.99900E+03);
618 o2::base::Detector::Medium(16, "ALUMINUM$", 16, 0, ifield, fieldm, tmaxfd, stemax, deemax, epsil, stmin);
619
620 o2::base::Detector::Mixture(20, "TUNGCARB$", aWC, zWC, dWC, 2, wWC);
621 o2::base::Detector::Medium(20, "TUNGCARB$", 20, 0, ifield, fieldm, tmaxfd, stemax, deemaxSi, epsilSi, stminSi);
622
623 wInox304[3] = 1. - wInox304[0] - wInox304[1] - wInox304[2];
624 o2::base::Detector::Mixture(21, "INOX304$", aInox304, zInox304, dInox304, 4, wInox304);
625 o2::base::Detector::Medium(21, "INOX304$", 21, 0, ifield, fieldm, tmaxfd, stemax, deemaxSi, epsilSi, stminSi);
626
627 // Tungsten (for gamma converter rods)
628 o2::base::Detector::Material(28, "TUNGSTEN$", 183.84, 74, 19.25, 999, 999);
629 o2::base::Detector::Medium(28, "TUNGSTEN$", 28, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
630
631 // EN AW 7075 (Al alloy with Cu Mg Zn) (for Cage rails)
632 wENAW7075[0] = 1. - wENAW7075[1] - wENAW7075[2] - wENAW7075[3];
633 o2::base::Detector::Mixture(36, "ENAW7075$", aENAW7075, zENAW7075, dENAW7075, 4, wENAW7075);
634 o2::base::Detector::Medium(36, "ENAW7075$", 36, 0, ifield, fieldm, tmaxfd, stemax, deemaxSi, epsilSi, stminSi);
635
636 // Brass CuZn39Pb3
637 o2::base::Detector::Mixture(34, "BRASS$", aBrass, zBrass, dBrass, 3, wBrass);
638 o2::base::Detector::Medium(34, "BRASS$", 34, 0, ifield, fieldm, tmaxfd, stemax, deemaxSi, epsilSi, stminSi);
639
640 // Titanium
641 o2::base::Detector::Material(35, "TITANIUM$", 47.867, 22, 4.506, 999, 999);
642 o2::base::Detector::Medium(35, "TITANIUM$", 35, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
643
644 // Carbon-Fiber-Reinforced Polymer
645 o2::base::Detector::Material(43, "CFRP$", 12.01, 6, 1.55, 999, 999);
646 o2::base::Detector::Medium(43, "CFRP$", 43, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
647
648 // Vespel for Beam Pipe Support
649 o2::base::Detector::Mixture(44, "VESPEL$", aVesp, zVesp, dVesp, -4, wVesp);
650 o2::base::Detector::Medium(44, "VESPEL$", 44, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
651
652 // Carbon for ITS services
653 o2::base::Detector::Material(41, "C4SERVICES$", 12.01, 6, 1.75, 999, 999);
654 o2::base::Detector::Medium(41, "C4SERVICES$", 41, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
655
656 // Polymer for ITS services
657 o2::base::Detector::Mixture(42, "POLY4SERVICES$", aPoly, zPoly, dPoly, 2, wPoly);
658 o2::base::Detector::Medium(42, "POLY4SERVICES$", 42, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
659
660 // For ITS3
661
662 // Araldite 2011
663 Float_t dAraldite = 1.05;
664
665 // ERG Duocel
666 o2::base::Detector::Material(39, "ERGDUOCEL$", 12.0107, 6, 0.06, 999, 999);
667 o2::base::Detector::Medium(39, "ERGDUOCEL$", 39, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
668
669 // Impregnated carbon fleece
670 // (as educated guess we assume 50% carbon fleece 50% Araldite glue)
671 o2::base::Detector::Material(40, "IMPREG_FLEECE$", 12.0107, 6, 0.5 * (dAraldite + 0.4), 999, 999);
672 o2::base::Detector::Medium(40, "IMPREG_FLEECE$", 40, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
673}
674
676
678{
679 // This will create a branch in the output tree called Hit, setting the last
680 // parameter to kFALSE means that this collection will not be written to the file,
681 // it will exist only during the simulation
682
683 if (FairRootManager::Instance()) {
684 FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, kTRUE);
685 }
686}
687
689{
690 if (!o2::utils::ShmManager::Instance().isOperational()) {
691 mHits->clear();
692 }
693}
694
695void Detector::defineWrapperVolume(Int_t id, Double_t rmin, Double_t rmax, Double_t zspan)
696{
697 // set parameters of id-th wrapper volume
698 if (id >= sNumberOfWrapperVolumes || id < 0) {
699 LOG(fatal) << "id " << id << " of wrapper volume is not in 0-" << sNumberOfWrapperVolumes - 1 << " range";
700 }
701
702 mWrapperMinRadius[id] = rmin;
703 mWrapperMaxRadius[id] = rmax;
704 mWrapperZSpan[id] = zspan;
705}
706
707void Detector::defineLayer(Int_t nlay, Double_t phi0, Double_t r, Int_t nstav, Int_t nunit, Double_t lthick,
708 Double_t dthick, UInt_t dettypeID, Int_t buildLevel)
709{
710 // Sets the layer parameters
711 // Inputs:
712 // nlay layer number
713 // phi0 layer phi0
714 // r layer radius
715 // nstav number of staves
716 // nunit IB: number of chips per stave
717 // OB: number of modules per half stave
718 // lthick stave thickness (if omitted, defaults to 0)
719 // dthick detector thickness (if omitted, defaults to 0)
720 // dettypeID ??
721 // buildLevel (if 0, all geometry is build, used for material budget studies)
722 // Outputs:
723 // none.
724 // Return:
725 // none.
726
727 LOG(debug) << "L# " << nlay << " Phi:" << phi0 << " R:" << r << " Nst:" << nstav << " Nunit:" << nunit
728 << " Lthick:" << lthick << " Dthick:" << dthick << " DetID:" << dettypeID << " B:" << buildLevel;
729
730 if (nlay >= mNumberLayers || nlay < 0) {
731 LOG(error) << "Wrong layer number " << nlay;
732 return;
733 }
734
735 mTurboLayer[nlay] = kFALSE;
736 mLayerPhi0[nlay] = phi0;
737 mLayerRadii[nlay] = r;
738 mStavePerLayer[nlay] = nstav;
739 mUnitPerStave[nlay] = nunit;
740 mChipThickness[nlay] = lthick;
741 mDetectorThickness[nlay] = dthick;
742 mChipTypeID[nlay] = dettypeID;
743 mBuildLevel[nlay] = buildLevel;
744}
745
746void Detector::getLayerParameters(Int_t nlay, Double_t& phi0, Double_t& r, Int_t& nstav, Int_t& nmod, Double_t& width,
747 Double_t& tilt, Double_t& lthick, Double_t& dthick, UInt_t& dettype) const
748{
749 // Gets the layer parameters
750 // Inputs:
751 // nlay layer number
752 // Outputs:
753 // phi0 phi of 1st stave
754 // r layer radius
755 // nstav number of staves
756 // nmod IB: number of chips per stave
757 // OB: number of modules per half stave
758 // width stave width
759 // tilt stave tilt angle
760 // lthick stave thickness
761 // dthick detector thickness
762 // dettype detector type
763 // Return:
764 // none.
765
766 if (nlay >= mNumberLayers || nlay < 0) {
767 LOG(error) << "Wrong layer number " << nlay;
768 return;
769 }
770
771 phi0 = mLayerPhi0[nlay];
772 r = mLayerRadii[nlay];
773 nstav = mStavePerLayer[nlay];
774 nmod = mUnitPerStave[nlay];
775 width = mStaveWidth[nlay];
776 tilt = mStaveTilt[nlay];
777 lthick = mChipThickness[nlay];
778 dthick = mDetectorThickness[nlay];
779 dettype = mChipTypeID[nlay];
780}
781
782TGeoVolume* Detector::createWrapperVolume(Int_t id)
783{
784 // Creates an air-filled wrapper cylindrical volume
785 // For OB a Pcon is needed to host the support rings
786 // while avoiding overlaps with MFT structures and OB cones
787
788 const Double_t suppRingAZlen = 4.;
789 const Double_t coneRingARmax = 33.96;
790 const Double_t coneRingAZlen[2] = {5.6, 0.3};
791 const Double_t suppRingCZlen[3] = {4.8, 4.0, 2.1};
792 const Double_t suppRingsRmin[3] = {23.35, 20.05, 35.4};
793
794 if (id > 0 && (mWrapperMinRadius[id] < 0 || mWrapperMaxRadius[id] < 0 || mWrapperZSpan[id] < 0)) { // check only for OB, IB managed in DescriptorInnerBarrel
795 LOG(fatal) << "Wrapper volume " << id << " was requested but not defined";
796 }
797
798 // Now create the actual shape and volume
799 TGeoShape* tube = nullptr;
800 Double_t zlen;
801 switch (id) {
802 case 0: // IB Layer 0,1,2: simple cylinder
803 {
804 tube = (TGeoShape*)mDescriptorIB->defineWrapperVolume();
805 } break;
806 case 1: // MB Layer 3,4: complex Pcon to avoid MFT overlaps
807 {
808 TGeoPcon* wrap = new TGeoPcon(0, 360, 6);
809 zlen = mWrapperZSpan[id] / 2 + suppRingCZlen[0];
810 wrap->DefineSection(0, -zlen, suppRingsRmin[0], mWrapperMaxRadius[id]);
811 zlen = mWrapperZSpan[id] / 2 + suppRingCZlen[1];
812 wrap->DefineSection(1, -zlen, suppRingsRmin[0], mWrapperMaxRadius[id]);
813 wrap->DefineSection(2, -zlen, suppRingsRmin[1], mWrapperMaxRadius[id]);
814 wrap->DefineSection(3, -mWrapperZSpan[id] / 2., suppRingsRmin[1], mWrapperMaxRadius[id]);
815 wrap->DefineSection(4, -mWrapperZSpan[id] / 2., mWrapperMinRadius[id], mWrapperMaxRadius[id]);
816 zlen = mWrapperZSpan[id] / 2 + suppRingAZlen;
817 wrap->DefineSection(5, zlen, mWrapperMinRadius[id], mWrapperMaxRadius[id]);
818 tube = (TGeoShape*)wrap;
819 } break;
820 case 2: // OB Layer 5,6: simpler Pcon to avoid OB cones overlaps
821 {
822 TGeoPcon* wrap = new TGeoPcon(0, 360, 6);
823 zlen = mWrapperZSpan[id] / 2;
824 wrap->DefineSection(0, -zlen, suppRingsRmin[2], mWrapperMaxRadius[id]);
825 zlen -= suppRingCZlen[2];
826 wrap->DefineSection(1, -zlen, suppRingsRmin[2], mWrapperMaxRadius[id]);
827 wrap->DefineSection(2, -zlen, mWrapperMinRadius[id], mWrapperMaxRadius[id]);
828 zlen = mWrapperZSpan[id] / 2 - coneRingAZlen[0];
829 wrap->DefineSection(3, zlen, mWrapperMinRadius[id], mWrapperMaxRadius[id]);
830 wrap->DefineSection(4, zlen, coneRingARmax, mWrapperMaxRadius[id]);
831 zlen = mWrapperZSpan[id] / 2 + coneRingAZlen[1];
832 wrap->DefineSection(5, zlen, coneRingARmax, mWrapperMaxRadius[id]);
833 tube = (TGeoShape*)wrap;
834 } break;
835 default: // Can never happen, keeps gcc quiet
836 break;
837 }
838
839 TGeoMedium* medAir = gGeoManager->GetMedium(Form("%s_AIR$", GetName()));
840
841 char volnam[30];
842 snprintf(volnam, 29, "%s%d", GeometryTGeo::getITSWrapVolPattern(), id);
843
844 auto* wrapper = new TGeoVolume(volnam, tube, medAir);
845
846 return wrapper;
847}
848
850{
851 // Create the detector materials
853
854 // Construct the detector geometry
856}
857
859{
860 // Create the geometry and insert it in the mother volume ITSV
861 TGeoManager* geoManager = gGeoManager;
862
863 TGeoVolume* vALIC = geoManager->GetVolume("barrel");
864
865 if (!vALIC) {
866 LOG(fatal) << "Could not find the top volume";
867 }
868
869 new TGeoVolumeAssembly(GeometryTGeo::getITSVolPattern());
870 TGeoVolume* vITSV = geoManager->GetVolume(GeometryTGeo::getITSVolPattern());
871 vALIC->AddNode(vITSV, 2, new TGeoTranslation(0, 30., 0)); // Copy number is 2 to cheat AliGeoManager::CheckSymNamesLUT
872
873 const Int_t kLength = 100;
874 Char_t vstrng[kLength] = "xxxRS"; //?
875 vITSV->SetTitle(vstrng);
876
877 // Check that we have all needed parameters for OB (no need IB, which is managed by the DescriptorInnerBarrel)
878 for (Int_t j = mNumberInnerLayers; j < mNumberLayers; j++) {
879 if (mLayerRadii[j] <= 0) {
880 LOG(fatal) << "Wrong layer radius for layer " << j << "(" << mLayerRadii[j] << ")";
881 }
882 if (mStavePerLayer[j] <= 0) {
883 LOG(fatal) << "Wrong number of staves for layer " << j << "(" << mStavePerLayer[j] << ")";
884 }
885 if (mUnitPerStave[j] <= 0) {
886 LOG(fatal) << "Wrong number of chips for layer " << j << "(" << mUnitPerStave[j] << ")";
887 }
888 if (mChipThickness[j] < 0) {
889 LOG(fatal) << "Wrong chip thickness for layer " << j << "(" << mChipThickness[j] << ")";
890 }
891 if (mTurboLayer[j] && mStaveWidth[j] <= 0) {
892 LOG(fatal) << "Wrong stave width for layer " << j << "(" << mStaveWidth[j] << ")";
893 }
894 if (mDetectorThickness[j] < 0) {
895 LOG(fatal) << "Wrong Sensor thickness for layer " << j << "(" << mDetectorThickness[j] << ")";
896 }
897
898 if (j > 0) {
899 if (mLayerRadii[j] <= mLayerRadii[j - 1]) {
900 LOG(fatal) << "Layer " << j << " radius (" << mLayerRadii[j] << ") is smaller than layer " << j - 1
901 << " radius (" << mLayerRadii[j - 1] << ")";
902 }
903 }
904
905 if (mChipThickness[j] == 0) {
906 LOG(info) << "Chip thickness for layer " << j << " not set, using default";
907 }
908 }
909
910 // Create the wrapper volumes
911 TGeoVolume** wrapVols = nullptr;
912
914 wrapVols = new TGeoVolume*[sNumberOfWrapperVolumes];
915 for (int id = 0; id < sNumberOfWrapperVolumes; id++) {
916 wrapVols[id] = createWrapperVolume(id);
917 vITSV->AddNode(wrapVols[id], 1, nullptr);
918 }
919 }
920
921 // Now create the actual geometry
922 for (Int_t j = 0; j < mNumberLayers; j++) {
923
924 if (j < mNumberInnerLayers) {
925 TString detName = GetName();
926 if (detName == "ITS") {
927 mGeometry[j] = ((DescriptorInnerBarrelITS2*)mDescriptorIB.get())->createLayer(j, wrapVols[0]); // define IB layers on first wrapper volume always
928 } else if (detName == "IT3") {
929#ifdef ENABLE_UPGRADES
930 ((DescriptorInnerBarrelITS3*)mDescriptorIB.get())->createLayer(j, wrapVols[0]); // define IB layers on first wrapper volume always
931#endif
932 }
933 mWrapperLayerId[j] = 0;
934 } else {
935 TGeoVolume* dest = vITSV;
936 mWrapperLayerId[j] = -1;
937
938 if (mTurboLayer[j]) {
939 mGeometry[j] = new V3Layer(j, kTRUE, kFALSE, GetName());
940 mGeometry[j]->setStaveWidth(mStaveWidth[j]);
941 mGeometry[j]->setStaveTilt(mStaveTilt[j]);
942 } else {
943 mGeometry[j] = new V3Layer(j, kFALSE, kFALSE, GetName());
944 }
945
946 mGeometry[j]->setPhi0(mLayerPhi0[j]);
947 mGeometry[j]->setRadius(mLayerRadii[j]);
948 mGeometry[j]->setNumberOfStaves(mStavePerLayer[j]);
949 mGeometry[j]->setNumberOfUnits(mUnitPerStave[j]);
950 mGeometry[j]->setChipType(mChipTypeID[j]);
951 mGeometry[j]->setBuildLevel(mBuildLevel[j]);
952
953 mGeometry[j]->setStaveModel(V3Layer::kOBModel2);
954
955 LOG(debug1) << "mBuildLevel: " << mBuildLevel[j];
956
957 if (mChipThickness[j] != 0) {
958 mGeometry[j]->setChipThick(mChipThickness[j]);
959 }
960 if (mDetectorThickness[j] != 0) {
961 mGeometry[j]->setSensorThick(mDetectorThickness[j]);
962 }
963
964 for (int iw = 0; iw < sNumberOfWrapperVolumes; iw++) {
966 LOG(debug) << "Will embed layer " << j << " in wrapper volume " << iw;
967
968 dest = wrapVols[iw];
969 mWrapperLayerId[j] = iw;
970 break;
971 }
972 }
973 mGeometry[j]->createLayer(dest);
974 }
975 }
976
977 // Now create the services
978 TString detName = GetName();
979 if (detName == "ITS") {
980 ((DescriptorInnerBarrelITS2*)mDescriptorIB.get())->createServices(wrapVols[0]);
981 } else if (detName == "IT3") {
982#ifdef ENABLE_UPGRADES
983 ((DescriptorInnerBarrelITS3*)mDescriptorIB.get())->createServices(wrapVols[0]);
984#endif
985 }
986
987 mServicesGeometry = new V3Services(detName);
988 createMiddlBarrelServices(wrapVols[1]);
989 createOuterBarrelServices(wrapVols[2]);
991
992 createITSServices(vALIC);
993
995
996 // Finally create and place the cage
997 V3Cage* cagePtr = new V3Cage(GetName());
998 cagePtr->createAndPlaceCage(vALIC); // vALIC = barrel
999
1000 delete[] wrapVols; // delete pointer only, not the volumes
1001}
1002
1003void Detector::createMiddlBarrelServices(TGeoVolume* motherVolume)
1004{
1005 //
1006 // Creates the Middle Barrel Service structures
1007 //
1008 // Input:
1009 // motherVolume : the volume hosting the services
1010 //
1011 // Output:
1012 //
1013 // Return:
1014 //
1015 // Created: 24 Sep 2019 Mario Sitta
1016 //
1017
1018 // Create the End Wheels on Side A
1020
1021 // Create the End Wheels on Side C
1023}
1024
1025void Detector::createOuterBarrelServices(TGeoVolume* motherVolume)
1026{
1027 //
1028 // Creates the Outer Barrel Service structures
1029 //
1030 // Input:
1031 // motherVolume : the volume hosting the services
1032 //
1033 // Output:
1034 //
1035 // Return:
1036 //
1037 // Created: 27 Sep 2019 Mario Sitta
1038 //
1039
1040 // Create the End Wheels on Side A
1042
1043 // Create the End Wheels on Side C
1045}
1046
1047void Detector::createOuterBarrelSupports(TGeoVolume* motherVolume)
1048{
1049 //
1050 // Creates the Outer Barrel Service structures
1051 //
1052 // Input:
1053 // motherVolume : the volume hosting the supports
1054 //
1055 // Output:
1056 //
1057 // Return:
1058 //
1059 // Created: 26 Jan 2020 Mario Sitta
1060 // Updated: 02 Mar 2020 Mario Sitta
1061 //
1062
1063 // Create the Cone on Side A
1064 mServicesGeometry->createOBConeSideA(motherVolume);
1065
1066 // Create the Cone on Side C
1067 mServicesGeometry->createOBConeSideC(motherVolume);
1068
1069 // Create the CYSS Cylinder
1071}
1072
1073void Detector::createITSServices(TGeoVolume* motherVolume)
1074{
1075 //
1076 // Creates the ITS services: tubes, cables and the like
1077 //
1078 // Input:
1079 // motherVolume : the volume hosting the supports
1080 //
1081 // Output:
1082 //
1083 // Return:
1084 //
1085 // Created: 12 Apr 2023 Mario Sitta
1086 //
1087
1089}
1090
1092{
1093 //
1094 // Creates entries for alignable volumes associating the symbolic volume
1095 // name with the corresponding volume path.
1096 //
1097 // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot)
1098 //
1099
1100 LOG(info) << "Add ITS alignable volumes";
1101
1102 if (!gGeoManager) {
1103 LOG(fatal) << "TGeoManager doesn't exist !";
1104 return;
1105 }
1106
1107 TString detName = GetName();
1108 TString path = Form("/cave_1/barrel_1/%s_2", GeometryTGeo::getITSVolPattern());
1109 TString sname = GeometryTGeo::composeSymNameITS((detName == "IT3"));
1110
1111 LOG(debug) << sname << " <-> " << path;
1112
1113 if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) {
1114 LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path;
1115 }
1116
1117 Int_t lastUID = 0;
1118 for (Int_t lr = 0; lr < mNumberLayers; lr++) {
1119 if (lr < mNumberInnerLayers) {
1120 if (detName == "ITS") {
1122 }
1123 } else {
1124 addAlignableVolumesLayer(lr, path, lastUID);
1125 }
1126 }
1127
1128 return;
1129}
1130
1131void Detector::addAlignableVolumesLayer(int lr, TString& parent, Int_t& lastUID) const
1132{
1133 //
1134 // Add alignable volumes for a Layer and its daughters
1135 //
1136 // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot)
1137 // Updated: 06 Jul 2021 Mario Sitta Do not set Layer as alignable volume
1138 //
1139
1140 TString wrpV =
1141 mWrapperLayerId[lr] != -1 ? Form("%s%d_1", GeometryTGeo::getITSWrapVolPattern(), mWrapperLayerId[lr]) : "";
1142 TString path = Form("%s/%s/%s%d_1", parent.Data(), wrpV.Data(), GeometryTGeo::getITSLayerPattern(), lr);
1143 TString sname = GeometryTGeo::composeSymNameLayer(lr);
1144
1145 const V3Layer* lrobj = mGeometry[lr];
1146 Int_t nhbarrel = lrobj->getNumberOfHalfBarrelsPerParent();
1147 Int_t start = nhbarrel > 0 ? 0 : -1;
1148 for (Int_t hb = start; hb < nhbarrel; hb++) {
1149 addAlignableVolumesHalfBarrel(lr, hb, path, lastUID);
1150 }
1151
1152 return;
1153}
1154
1155void Detector::addAlignableVolumesHalfBarrel(Int_t lr, Int_t hb, TString& parent, Int_t& lastUID) const
1156{
1157 //
1158 // Add alignable volumes for a Half barrel and its daughters
1159 //
1160 // Created: 28 Jun 2021 Mario Sitta First version (based on similar methods)
1161 //
1162
1163 TString path = parent;
1164 if (hb >= 0) {
1165 path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSHalfBarrelPattern(), lr, hb);
1166 TString sname = GeometryTGeo::composeSymNameHalfBarrel(lr, hb);
1167
1168 LOG(debug) << "Add " << sname << " <-> " << path;
1169
1170 if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) {
1171 LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path;
1172 }
1173 }
1174
1175 const V3Layer* lrobj = mGeometry[lr];
1176 Int_t nstaves = lrobj->getNumberOfStavesPerParent();
1177 for (int st = 0; st < nstaves; st++) {
1178 addAlignableVolumesStave(lr, hb, st, path, lastUID);
1179 }
1180
1181 return;
1182}
1183
1184void Detector::addAlignableVolumesStave(Int_t lr, Int_t hb, Int_t st, TString& parent, Int_t& lastUID) const
1185{
1186 //
1187 // Add alignable volumes for a Stave and its daughters
1188 //
1189 // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot)
1190 // Updated: 29 Jun 2021 Mario Sitta Hal Barrel index added
1191 //
1192
1193 TString path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSStavePattern(), lr, st);
1194 TString sname = GeometryTGeo::composeSymNameStave(lr, hb, st);
1195
1196 LOG(debug) << "Add " << sname << " <-> " << path;
1197
1198 if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) {
1199 LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path;
1200 }
1201
1202 const V3Layer* lrobj = mGeometry[lr];
1203 Int_t nhstave = lrobj->getNumberOfHalfStavesPerParent();
1204 Int_t start = nhstave > 0 ? 0 : -1;
1205 for (Int_t sst = start; sst < nhstave; sst++) {
1206 addAlignableVolumesHalfStave(lr, hb, st, sst, path, lastUID);
1207 }
1208
1209 return;
1210}
1211
1212void Detector::addAlignableVolumesHalfStave(Int_t lr, Int_t hb, Int_t st, Int_t hst, TString& parent, Int_t& lastUID) const
1213{
1214 //
1215 // Add alignable volumes for a HalfStave (if any) and its daughters
1216 //
1217 // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot)
1218 // Updated: 29 Jun 2021 Mario Sitta Hal Barrel index added
1219 //
1220
1221 TString path = parent;
1222 if (hst >= 0) {
1223 path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSHalfStavePattern(), lr, hst);
1224 TString sname = GeometryTGeo::composeSymNameHalfStave(lr, hb, st, hst);
1225
1226 LOG(debug) << "Add " << sname << " <-> " << path;
1227
1228 if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) {
1229 LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path;
1230 }
1231 }
1232
1233 const V3Layer* lrobj = mGeometry[lr];
1234 Int_t nmodules = lrobj->getNumberOfModulesPerParent();
1235 Int_t start = nmodules > 0 ? 0 : -1;
1236 for (Int_t md = start; md < nmodules; md++) {
1237 addAlignableVolumesModule(lr, hb, st, hst, md, path, lastUID);
1238 }
1239
1240 return;
1241}
1242
1243void Detector::addAlignableVolumesModule(Int_t lr, Int_t hb, Int_t st, Int_t hst, Int_t md, TString& parent, Int_t& lastUID) const
1244{
1245 //
1246 // Add alignable volumes for a Module (if any) and its daughters
1247 //
1248 // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot)
1249 // Updated: 29 Jun 2021 Mario Sitta Hal Barrel index added
1250 //
1251
1252 TString path = parent;
1253 if (md >= 0) {
1254 path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSModulePattern(), lr, md);
1255 TString sname = GeometryTGeo::composeSymNameModule(lr, hb, st, hst, md);
1256
1257 LOG(debug) << "Add " << sname << " <-> " << path;
1258
1259 if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) {
1260 LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path;
1261 }
1262 }
1263
1264 const V3Layer* lrobj = mGeometry[lr];
1265 Int_t nchips = lrobj->getNumberOfChipsPerParent();
1266 for (Int_t ic = 0; ic < nchips; ic++) {
1267 addAlignableVolumesChip(lr, hb, st, hst, md, ic, path, lastUID);
1268 }
1269
1270 return;
1271}
1272
1273void Detector::addAlignableVolumesChip(Int_t lr, Int_t hb, Int_t st, Int_t hst, Int_t md, Int_t ch, TString& parent,
1274 Int_t& lastUID) const
1275{
1276 //
1277 // Add alignable volumes for a Chip
1278 //
1279 // Created: 06 Mar 2018 Mario Sitta First version (mainly ported from AliRoot)
1280 // Updated: 29 Jun 2021 Mario Sitta Hal Barrel index added
1281 //
1282
1283 TString path = Form("%s/%s%d_%d", parent.Data(), GeometryTGeo::getITSChipPattern(), lr, ch);
1284 TString sname = GeometryTGeo::composeSymNameChip(lr, hb, st, hst, md, ch);
1285 Int_t modUID = chipVolUID(lastUID++);
1286
1287 LOG(debug) << "Add " << sname << " <-> " << path;
1288
1289 if (gGeoManager->SetAlignableEntry(sname, path.Data(), modUID) == nullptr) {
1290 LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path;
1291 }
1292}
1293
1295{
1296 TGeoManager* geoManager = gGeoManager;
1297 TGeoVolume* v = nullptr;
1298
1299 TString volumeName;
1300
1301 // The names of the ITS sensitive volumes have the format: ITSUSensor(0...mNumberLayers-1)
1302 for (Int_t j = 0; j < mNumberLayers; j++) {
1303 TString detName = GetName();
1304 if (j < mNumberInnerLayers && detName == "IT3") {
1305 volumeName = GeometryTGeo::getITS3SensorPattern() + TString::Itoa(j, 10);
1306 } else {
1307 volumeName = GeometryTGeo::getITSSensorPattern() + TString::Itoa(j, 10);
1308 }
1309 v = geoManager->GetVolume(volumeName.Data());
1310 AddSensitiveVolume(v);
1311 }
1312}
1313
1315{
1316 TGeoParallelWorld* pw = gGeoManager->GetParallelWorld();
1317 if (pw == nullptr) {
1318 LOG(error) << "Parallel world was not created";
1319 return;
1320 }
1321 auto& param = ITSSimParam::Instance();
1322
1323 for (int iL{0}; iL < mNumberLayers; ++iL) {
1324 auto const layer = mGeometry[iL];
1325 int nhbarrels = layer->getNumberOfHalfBarrelsPerParent();
1326 int nstaves = layer->getNumberOfStavesPerParent();
1327 int nhstaves = layer->getNumberOfHalfStavesPerParent();
1328 int nmodules = layer->getNumberOfModulesPerParent();
1329 int nchips = layer->getNumberOfChipsPerParent();
1330
1331 for (int iHB{0}; iHB < nhbarrels; ++iHB) {
1332 for (int iS{0}; iS < nstaves; ++iS) {
1333 for (int iHS{nhstaves > 0 ? 0 : -1}; iHS < nhstaves; ++iHS) {
1334 for (int iM{nmodules > 0 ? 0 : -1}; iM < nmodules; ++iM) {
1335 for (int iC{0}; iC < nchips; ++iC) {
1336 TString sname = GeometryTGeo::composeSymNameChip(iL, iHB, iS, iHS, iM, iC);
1337 TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(sname);
1338 auto path = pne->GetTitle();
1339
1340 if (param.addMetalToPW) {
1341 TString metalPath = Form("%s/MetalStack_1", path);
1342 gGeoManager->MakePhysicalNode(metalPath);
1343 pw->AddNode(metalPath);
1344 }
1345 if (param.addSensorToPW) {
1346 TString sensorPath = Form("%s/ITSUSensor%d_1", path, iL);
1347 gGeoManager->MakePhysicalNode(sensorPath);
1348 pw->AddNode(sensorPath);
1349 }
1350 if (param.addChipToPW) {
1351 pw->AddNode(path);
1352 }
1353 }
1354 }
1355 }
1356 }
1357 }
1358 }
1359}
1360
1361Hit* Detector::addHit(int trackID, int detID, const TVector3& startPos, const TVector3& endPos,
1362 const TVector3& startMom, double startE, double endTime, double eLoss, unsigned char startStatus,
1363 unsigned char endStatus)
1364{
1365 mHits->emplace_back(trackID, detID, startPos, endPos, startMom, startE, endTime, eLoss, startStatus, endStatus);
1366 return &(mHits->back());
1367}
1368
1370
1371// Define Factory method for calling from the outside
1372extern "C" {
1377}
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: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:746
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:707
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:675
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:858
void Register() override
Registers the produced collections in FAIRRootManager.
Definition Detector.cxx:677
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:849
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:782
void Reset() override
Has to be called after each event to reset the containers.
Definition Detector.cxx:688
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:695
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: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"