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
12#include <TParticle.h>
13#include <TVirtualMC.h>
14#include <TGeoVolume.h>
15#include <TGeoManager.h>
16#include <TGeoBBox.h>
17#include <TGeoCompositeShape.h>
18
19#include <FairVolume.h>
20
21#include "DetectorsBase/Stack.h"
23#include "FOCALBase/Geometry.h"
24#include "FOCALBase/Hit.h"
25
26using namespace o2::focal;
27
28Detector::Detector(bool active, std::string geofilename)
29 : o2::base::DetImpl<Detector>("FOC", active),
30 mHits(o2::utils::createSimVector<Hit>()),
31 mHitIndexMapping(),
32 mGeometry(nullptr),
33 mMedSensHCal(-1),
34 mMedSensECalPad(-1),
35 mMedSensECalPix(-1),
36 mGeoCompositions(),
37 mSuperParentsIndices(),
38 mSuperParents(),
39 mCurrentSuperparent(nullptr),
40 mCurrentTrack(-1),
41 mCurrentPrimaryID(-1),
42 mCurrentParentID(-1),
43 mVolumeIDScintillator(-1)
44{
45 mGeometry = getGeometry(geofilename);
46 if (!mGeometry) {
47 LOG(fatal) << "Geometry is nullptr";
48 }
49}
50
52 : o2::base::DetImpl<Detector>(rhs)
53{
54 mGeometry = rhs.mGeometry;
55 mMedSensHCal = rhs.mMedSensHCal;
56 mMedSensECalPad = rhs.mMedSensECalPad;
57 mMedSensECalPix = rhs.mMedSensECalPix;
58 mSensitive = rhs.mSensitive;
59 // mSensitiveHCAL = rhs.mSensitiveHCAL;
60 // mSensitiveECALPad = rhs.mSensitiveECALPad;
61 // mSensitiveECALPix = rhs.mSensitiveECALPix;
62 mVolumeIDScintillator = rhs.mVolumeIDScintillator;
63}
64
69
71{
72 if (!mGeometry) {
73 mGeometry = Geometry::getInstance(name);
74 }
75 if (!mGeometry) {
76 LOG(error) << "Failure accessing geometry";
77 }
78 return mGeometry;
79}
80
82{
83
84 LOG(info) << "Intializing FOCAL detector";
85
86 // All FOCAL volumes must be declared as sensitive, otherwise
87 // the decay chains are broken by volumes not processed in ProceeHits
88 for (const auto& child : mSensitive) {
89 LOG(debug1) << "Adding sensitive volume " << child;
90 auto svolID = registerSensitiveVolumeAndGetVolID(child);
91 // HCAL
92 if (child == "ScintFiber" || child == "HScint") {
93 LOG(debug1) << "Adding ScintFiber/HScint volume as sensitive volume with ID " << svolID;
94 mVolumeIDScintillator = svolID;
95 }
96 // ECAL Pads
97 else if (child == "EMSC1" || child == "EMSC2") {
98 LOG(debug1) << "Adding EMC SILICON volume as sensitive volume with ID " << svolID;
99 mVolumeIDScintillator = svolID;
100 }
101 }
102
103 mMedSensHCal = getMediumID(ID_SC);
104 mMedSensECalPad = getMediumID(ID_SIPAD);
105 mMedSensECalPix = getMediumID(ID_SIPIX);
106}
107
108Bool_t Detector::ProcessHits(FairVolume* v)
109{
110 int track = fMC->GetStack()->GetCurrentTrackNumber(),
111 directparent = fMC->GetStack()->GetCurrentParentTrackNumber();
112 // Like other calorimeters FOCAL will create a huge amount of shower particles during tracking
113 // Instead, the hits should be assigned to the incoming particle in FOCAL.
114 // Implementation of the incoming particle search taken from implementation in EMCAL.
115 if (track != mCurrentTrack) {
116 LOG(debug4) << "Doing new track " << track << " current (" << mCurrentTrack << "), direct parent (" << directparent << ")";
117 // new current track - check parentage
118 auto hasSuperParent = mSuperParentsIndices.find(directparent);
119 if (hasSuperParent != mSuperParentsIndices.end()) {
120 // same superparent as direct parent
121 mCurrentParentID = hasSuperParent->second;
122 mSuperParentsIndices[track] = hasSuperParent->second;
123 auto superparent = mSuperParents.find(mCurrentParentID);
124 if (superparent != mSuperParents.end()) {
125 mCurrentSuperparent = &(superparent->second);
126 } else {
127 LOG(error) << "Attention: No superparent object found (parent " << mCurrentParentID << ")";
128 mCurrentSuperparent = nullptr;
129 }
130 LOG(debug4) << "Found superparent " << mCurrentParentID;
131 } else {
132 // start of new chain
133 // for new incoming tracks the super parent index is equal to the track ID (for recursion)
134 mSuperParentsIndices[track] = track;
135 mCurrentSuperparent = AddSuperparent(track, fMC->TrackPid(), fMC->Etot());
136 mCurrentParentID = track;
137 }
138 mCurrentTrack = track;
139 }
140
141 // Processing HCAL hits
142 bool flagHCAL = true;
143 if (fMC->CurrentMedium() == mMedSensHCal) {
144 flagHCAL = ProcessHitsHCAL(v);
145 }
146
147 // Processing ECAL Pad hits
148 bool flagECALPad = true;
149 if (TVirtualMC::GetMC()->CurrentMedium() == mMedSensECalPad) {
150 flagECALPad = ProcessHitsEPad(v);
151 }
152
153 // Processing ECAL Pixel hits
154 bool flagECALPix = true;
155 if (fMC->CurrentMedium() == mMedSensECalPix) {
156 flagECALPix = ProcessHitsEPix(v);
157 }
158
159 return (flagHCAL || flagECALPad || flagECALPix);
160 // return true;
161}
162
163Hit* Detector::AddHit(int trackID, int primary, double initialEnergy, int detID, o2::focal::Hit::Subsystem_t subsystem,
164 const math_utils::Point3D<float>& pos, double time, double eLoss)
165{
166 LOG(debug3) << "Adding hit for track " << trackID << " with position (" << pos.X() << ", "
167 << pos.Y() << ", " << pos.Z() << ") with energy " << initialEnergy << " loosing " << eLoss;
168 mHits->emplace_back(primary, trackID, detID, subsystem, initialEnergy, pos, time, eLoss);
169
170 auto [isin, col, row, layer, segment] = mGeometry->getVirtualInfo(pos.X(), pos.Y(), pos.Z());
171 mHitIndexMapping.insert(std::pair<Hit::HitID, unsigned int>({trackID, uint8_t(row), uint8_t(col), uint8_t(layer)}, static_cast<unsigned int>(mHits->size() - 1)));
172
173 return &(mHits->back());
174}
175
176Hit* Detector::FindHit(int parentID, int col, int row, int layer)
177{
178 Hit::HitID hitToFind{parentID, uint8_t(row), uint8_t(col), uint8_t(layer)};
179 auto found = mHitIndexMapping.find(hitToFind);
180
181 if (found == mHitIndexMapping.end()) {
182 return nullptr;
183 }
184
185 return &((*mHits)[found->second]);
186}
187
188Parent* Detector::AddSuperparent(int trackID, int pdg, double energy)
189{
190 LOG(debug3) << "Adding superparent for track " << trackID << " with PID " << pdg << " and energy " << energy;
191 auto entry = mSuperParents.insert({trackID, {pdg, energy, false}});
192 return &(entry.first->second);
193}
194
196
198{
199 FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, kTRUE);
200}
201
203{
204 LOG(debug) << "Cleaning FOCAL hits ...";
205 if (!o2::utils::ShmManager::Instance().isOperational()) {
206 mHits->clear();
207 }
208 mHitIndexMapping.clear();
209
210 mSuperParentsIndices.clear();
211 mSuperParents.clear();
212 mCurrentTrack = -1;
213 mCurrentParentID = -1;
214}
215
217{
218
219 // --- Define the various materials for GEANT ---
220
222 float aSi = 28.09;
223 float zSi = 14.0;
224 float dSi = 2.33;
225 float x0Si = 9.36;
226 Material(1, "Si $", aSi, zSi, dSi, x0Si, 18.5);
227
229 float aW = 183.84;
230 float zW = 74.0;
231 float dW = 19.3;
232 float x0W = 0.35;
233 Material(0, "W $", aW, zW, dW, x0W, 17.1);
234
235 // Cu
236 Material(3, "Cu $", 63.54, 29., 8.96, 1.43, 15.);
237
238 // Al
239 Material(9, "Al$", 26.98, 13.0, 2.7, 8.9, 37.2);
240
242 Material(10, "Pb $", 207.19, 82., 11.35, .56, 18.5);
243
245 // --- The polysterene scintillator (CH) ---
246 float aP[2] = {12.011, 1.00794};
247 float zP[2] = {6.0, 1.0};
248 float wP[2] = {1.0, 1.0};
249 float dP = 1.032;
250 Mixture(11, "Polystyrene$", aP, zP, dP, -2, wP);
251
252 // G10
253
254 float aG10[4] = {1., 12.011, 15.9994, 28.086};
255 float zG10[4] = {1., 6., 8., 14.};
256 // PH float wG10[4]={0.148648649,0.104054054,0.483499056,0.241666667};
257 float wG10[4] = {0.15201, 0.10641, 0.49444, 0.24714};
258 Mixture(2, "G10 $", aG10, zG10, 1.7, 4, wG10);
259
261 float aAlloy[3] = {183.84, 58.6934, 63.54};
262 float zAlloy[3] = {74.0, 28, 29};
263 float wAlloy[3] = {0.94, 0.04, 0.02};
264 float dAlloy = wAlloy[0] * 19.3 + wAlloy[1] * 8.908 + wAlloy[2] * 8.96;
265 Mixture(5, "Alloy $", aAlloy, zAlloy, dAlloy, 3, wAlloy);
266
267 // Steel
268 float aSteel[4] = {55.847, 51.9961, 58.6934, 28.0855};
269 float zSteel[4] = {26., 24., 28., 14.};
270 float wSteel[4] = {.715, .18, .1, .005};
271 float dSteel = 7.88;
272 Mixture(4, "STAINLESS STEEL$", aSteel, zSteel, dSteel, 4, wSteel);
273
274 // Air
275 float aAir[4] = {12.0107, 14.0067, 15.9994, 39.948};
276 float zAir[4] = {6., 7., 8., 18.};
277 float wAir[4] = {0.000124, 0.755268, 0.231781, 0.012827};
278 float dAir1 = 1.20479E-10;
279 float dAir = 1.20479E-3;
280 Mixture(98, "Vacum$", aAir, zAir, dAir1, 4, wAir);
281 Mixture(99, "Air $", aAir, zAir, dAir, 4, wAir);
282
283 // Ceramic
284 // Ceramic 97.2% Al2O3 , 2.8% SiO2
285 // float wcer[2]={0.972,0.028}; // Not used
286 float aal2o3[2] = {26.981539, 15.9994};
287 float zal2o3[2] = {13., 8.};
288 float wal2o3[2] = {2., 3.};
289 float denscer = 3.6;
290 // SiO2
291 float aglass[2] = {28.0855, 15.9994};
292 float zglass[2] = {14., 8.};
293 float wglass[2] = {1., 2.};
294 float dglass = 2.65;
295 Mixture(6, "Al2O3 $", aal2o3, zal2o3, denscer, -2, wal2o3);
296 Mixture(7, "glass $", aglass, zglass, dglass, -2, wglass);
297
298 // Ceramic is a mixtur of glass and Al2O3 ?
299 // Not clear how to do this with AliMixture
300 // Not needed; so skip for now
301
302 /*
303float acer[2],zcer[2];
304char namate[21]="";
305float a,z,d,radl,absl,buf[1];
306Int_t nbuf;
307fMC->Gfmate((*fIdmate)[6], namate, a, z, d, radl, absl, buf, nbuf);
308acer[0]=a;
309zcer[0]=z;
310fMC->Gfmate((*fIdmate)[7], namate, a, z, d, radl, absl, buf, nbuf);
311acer[1]=a;
312zcer[1]=z;
313
314AliMixture( 8, "Ceramic $", acer, zcer, denscer, 2, wcer);
315*/
316
317 // Use Al2O3 instead:
318
319 Mixture(8, "Ceramic $", aal2o3, zal2o3, denscer, -2, wal2o3);
320
321 // Define tracking media
322 // format
323
324 float tmaxfdSi = 10.0; // 0.1; // .10000E+01; // Degree
325 float stemaxSi = 0.1; // .10000E+01; // cm
326 float deemaxSi = 0.1; // 0.30000E-02; // Fraction of particle's energy 0<deemax<=1
327 // float epsilSi = 1.e-3;//1e-3;//1.0E-4;// .10000E+01;
328 float epsilSi = 1.e-3; // 1.0E-4;// .10000E+01; // This drives the step size ? 1e-4 makes multiple steps even in pixels?
329 float stminSi = 0.001; // cm "Default value used"
330
331 float epsil = 0.001;
332 // MvL: need to look up itdmed dynamically?
333 // or move to TGeo: uses pointers for medium
334
335 int isxfld = 2;
336 float sxmgmx = 10.0;
338
340 Medium(ID_TUNGSTEN, "W conv.$", 0, 0,
341 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.1, nullptr, 0);
343 Medium(ID_SIPAD, "Si sens pad$", 1, 0,
344 isxfld, sxmgmx, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi, nullptr, 0);
346 Medium(ID_SIPIX, "Si sens pix$", 1, 0,
347 isxfld, sxmgmx, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi, nullptr, 0);
348
350 Medium(ID_G10, "G10 plate$", 2, 0,
351 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.01, nullptr, 0);
352
354 Medium(ID_COPPER, "Cu$", 3, 0,
355 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.0001, nullptr, 0);
356
358 Medium(ID_STEEL, "S steel$", 4, 0,
359 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.0001, nullptr, 0);
360
362 Medium(ID_ALLOY, "Alloy conv.$", 5, 0,
363 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.1, nullptr, 0);
364
366 Medium(ID_CERAMIC, "Ceramic$", 8, 0,
367 isxfld, sxmgmx, 10.0, 0.01, 0.1, 0.003, 0.003, nullptr, 0);
368
369 // HCAL materials // Need to double-check tracking pars for this
371 Medium(ID_PB, "Pb // The Scintillator must be first in order in vector for Rin to be set$", 10, 0,
372 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.1, nullptr, 0);
374 Medium(ID_SC, "Scint$", 11, 0,
375 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.001, 0.001, nullptr, 0);
376
378 Medium(ID_SIINSENS, "Si insens$", 1, 0,
379 isxfld, sxmgmx, 10.0, 0.1, 0.1, epsil, 0.001, nullptr, 0);
380
381 // Al for the cold plates
382 Medium(ID_ALUMINIUM, "Aluminium$", 9, 0,
383 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.1, nullptr, 0);
384
386 Medium(ID_VAC, "Vacuum $", 98, 0,
387 isxfld, sxmgmx, 10.0, 1.0, 0.1, 0.1, 1.0, nullptr, 0);
388
390 Medium(ID_AIR, "Air gaps$", 99, 0,
391 isxfld, sxmgmx, 10.0, 1.0, 0.1, epsil, 0.001, nullptr, 0);
392}
393
394//____________________________________________________________________________
396{
397 // Create entries for alignable volumes associating the symbolic volume
398 // name with the corresponding volume path. Needs to be syncronized with
399 // eventual changes in the geometry
400 // Alignable volumes are:
401
404}
405
406//____________________________________________________________________________
408{
409 const std::string vpsector = "/cave_1/barrel_1/FOCAL_1/HCAL_1";
410 const std::string snsector = "FOCAL/HCAL";
411
412 if (!gGeoManager->SetAlignableEntry(snsector.c_str(), vpsector.c_str())) {
413 LOG(fatal) << "Alignable entry " << snsector << " not created. Volume path " << vpsector << "not valid.";
414 }
415}
416
417//____________________________________________________________________________
419{
420 const std::string vpsector = "/cave_1/barrel_1/FOCAL_1/ECAL_1";
421 const std::string snsector = "FOCAL/ECAL";
422
423 if (!gGeoManager->SetAlignableEntry(snsector.c_str(), vpsector.c_str())) {
424 LOG(fatal) << "Alignable entry " << snsector << " not created. Volume path " << vpsector << "not valid.";
425 }
426}
427
429{
430
441
442 LOG(debug) << "Creating FOCAL geometry\n";
443
445
447 mGeoCompositions = mGeometry->getFOCALMicroModule(-1);
448 if (!mGeoCompositions.size()) {
449 LOG(error) << "FOCAL compositions not found!!";
450 return;
451 }
452
453 float pars[4];
454 pars[0] = (mGeometry->getFOCALSizeX() + 2 * mGeometry->getMiddleTowerOffset()) / 2;
455 pars[1] = mGeometry->getFOCALSizeY() / 2;
456 pars[2] = mGeometry->getFOCALSizeZ() / 2;
457 // Add space to place 2 SiPad layers in front of ECAL
458 // The global position of ECAL and HCAL remains the same, but the FOCAL box needs to be slightly larger to accomodate
459 // the 2 SiPad layers which will sit at z=698 and 699cm (2 and 1 cm in front of ECAL)
460 if (mGeometry->getInsertFrontPadLayers()) {
461 pars[2] += 1.0;
462 }
463 if (mGeometry->getInsertHCalReadoutMaterial()) {
464 pars[2] += (1.0 + 0.5); // place Aluminium 1cm thick box (0.5 means half) at 2cm behind HCal to simulate SiPM readout material
465 pars[1] += (10.0 + 1.0); // place Aluminium 1cm thick box at 10 cm below FOCAL
466 }
467 pars[3] = 0;
468
469 LOG(info) << "Creating FOCAL with dimensions X: " << (mGeometry->getFOCALSizeX() + 2 * mGeometry->getMiddleTowerOffset()) << ", Y: "
470 << mGeometry->getFOCALSizeY() << ", Z: " << mGeometry->getFOCALSizeZ() + (mGeometry->getInsertFrontPadLayers() ? 2.0 : 0.0) + (mGeometry->getInsertHCalReadoutMaterial() ? 3.0 : 0.0);
471
472 TVirtualMC::GetMC()->Gsvolu("FOCAL", "BOX", getMediumID(ID_AIR), pars, 4);
473 mSensitive.push_back("FOCAL");
474 // mSensitiveHCAL.push_back("FOCAL");
475 // mSensitiveECALPad.push_back("FOCAL");
476 // mSensitiveECALPix.push_back("FOCAL");
477
478 // ECAL part
479 LOG(debug2) << "ECAL geometry : " << GetTitle();
481
482 // HCAL part
483 if (mGeometry->getUseHCALSandwich()) {
485 } else {
487 }
488 // const float z0 = 1312.5; // center of barrel mother volume
489 TVirtualMC::GetMC()->Gspos("FOCAL", 1, "barrel", 0, 30., mGeometry->getFOCALZ0() - (mGeometry->getInsertFrontPadLayers() ? 2.0 : 0.0) + (mGeometry->getInsertHCalReadoutMaterial() ? 1.5 : 0.0), 0, "ONLY");
490}
491
493{
494 TGeoVolumeAssembly* volHCAL = new TGeoVolumeAssembly("HCAL");
495
496 TGeoVolumeAssembly* HcalTube = gGeoManager->MakeVolumeAssembly("ScintCuTubes");
497
498 TGeoVolume* volCuTube;
499 TGeoVolume* volSciFi;
500
501 float RScint = 0.;
502 float Rin = 0.;
503 float Rout = 0.;
504 float Length = 0.;
505
506 for (auto& icomp : mGeoCompositions) {
507 Length = icomp->sizeZ() / 2;
508
509 if (icomp->material() == "Pb") {
510 Rout = icomp->sizeX() / 2;
511 TGeoMedium* medium = gGeoManager->GetMedium(getMediumID(ID_PB));
512 volCuTube = gGeoManager->MakeTube("Tube", medium, Rin, Rout, Length); // The Scintillator must be first in order in vector for Rin to be set
513 volCuTube->SetLineWidth(2);
514 volCuTube->SetLineColor(kRed);
515 mSensitive.push_back(volCuTube->GetName());
516 // mSensitiveHCAL.push_back(volCuTube->GetName());
517 HcalTube->AddNode(volCuTube, 1, nullptr);
518 }
519 if (icomp->material() == "Scint") {
520 RScint = icomp->sizeX() / 2;
521 Rin = RScint + 0.005;
522 TGeoMedium* medium = gGeoManager->GetMedium(getMediumID(ID_SC));
523 volSciFi = gGeoManager->MakeTube("ScintFiber", medium, 0., RScint, Length);
524 volSciFi->SetLineWidth(2);
525 volSciFi->SetLineColor(kBlue);
526 // mSensitiveHCAL.push_back(volSciFi->GetName());
527 mSensitive.push_back(volSciFi->GetName());
528 HcalTube->AddNode(volSciFi, 1, nullptr);
529 }
530 if (icomp->material() == "CuHCAL") {
531 Rout = icomp->sizeX() / 2;
532 TGeoMedium* medium = gGeoManager->GetMedium(getMediumID(ID_COPPER));
533 volCuTube = gGeoManager->MakeTube("Tube", medium, Rin, Rout, Length); // The Scintillator must be first in order in vector for Rin to be set
534 volCuTube->SetLineWidth(2);
535 volCuTube->SetLineColor(kRed);
536 // mSensitiveHCAL.push_back(volCuTube->GetName());
537 mSensitive.push_back(volCuTube->GetName());
538 HcalTube->AddNode(volCuTube, 1, nullptr);
539 }
540 }
541
542 double TowerSize = mGeometry->getHCALTowerSize();
543 double CuBoxThickness = 0.3; // Thickness of the Cu box carrying capillary tubes
544
545 TGeoBBox* ODBox = new TGeoBBox("TowerOD", TowerSize / 2, TowerSize / 2, Length);
546 TGeoBBox* IDBox = new TGeoBBox("TowerID", (TowerSize - CuBoxThickness) / 2, (TowerSize - CuBoxThickness) / 2, Length + 0.01);
547 TGeoCompositeShape* TowerHCAL = new TGeoCompositeShape("TowerHCAL", "TowerOD - TowerID");
548 TGeoVolume* volTower = new TGeoVolume("volTower", TowerHCAL, gGeoManager->GetMedium(getMediumID(ID_COPPER)));
549 volTower->SetLineWidth(2);
550 volTower->SetLineColor(42);
551 // mSensitiveHCAL.push_back(volTower->GetName());
552 mSensitive.push_back(volTower->GetName());
553
554 TGeoVolumeAssembly* volTowerHCAL = new TGeoVolumeAssembly("volTowerHCAL");
555 volTowerHCAL->AddNode(volTower, 1, nullptr);
556
557 int Rows = 0;
558 float RowPos = 0.;
559 int Columns = 0;
560 int NumTubes = 1;
561
562 // Packing circles in Hexagonal shape
563 while (RowPos + CuBoxThickness / 2 + Rout + 2 * Rout < TowerSize) {
564 Columns = 0;
565 float ColumnPos = (Rows % 2 == 0) ? 0. : Rout;
566 while (ColumnPos + CuBoxThickness / 2 + Rout + 2 * Rout < TowerSize) {
567
568 TGeoTranslation* trans = new TGeoTranslation(ColumnPos - TowerSize / 2 + CuBoxThickness / 2 + Rout, RowPos - TowerSize / 2 + CuBoxThickness / 2 + Rout, 0.);
569
570 trans->SetName(Form("trans_Num_%d", NumTubes));
571 trans->RegisterYourself();
572
573 volTowerHCAL->AddNode(HcalTube, NumTubes, trans);
574 // volTowerHCAL->AddNode(volCuTube, NumTubes, trans);
575 // volTowerHCAL->AddNode(volSciFi, NumTubes, trans);
576
577 Columns++;
578 ColumnPos = Columns * 2 * Rout + ((Rows % 2 == 0) ? 0. : Rout);
579 NumTubes++;
580 }
581
582 Rows++;
583 RowPos = Rows * 2 * Rout * TMath::Sin(TMath::Pi() / 3);
584 }
585
586 // Define the distance from the beam pipe in which towers will ommitted
587 Double_t BeamPipeRadius = 3.0; // in cm To be changed later
588 Double_t TowerHalfDiag = TMath::Sqrt2() * 0.5 * TowerSize; // tower half diagonal
589 Double_t MinRadius = BeamPipeRadius + TowerSize / 2;
590
591 float SizeXHCAL = mGeometry->getHCALTowersInX() * TowerSize;
592 float SizeYHCAL = mGeometry->getHCALTowersInY() * TowerSize;
593
594 int nTowersX = mGeometry->getHCALTowersInX();
595 int nTowersY = mGeometry->getHCALTowersInY();
596
597 Rows = 0;
598 Columns = 0;
599 RowPos = 0.;
600 Int_t NumTowers = 1;
601 for (Rows = 0; Rows < nTowersY; Rows++) {
602
603 float ColumnPos = 0.;
604 RowPos = Rows * TowerSize;
605 for (Columns = 0; Columns < nTowersX; Columns++) {
606 ColumnPos = Columns * TowerSize;
607 TGeoTranslation* trans = new TGeoTranslation(ColumnPos - SizeXHCAL / 2 + TowerSize / 2, RowPos - SizeYHCAL / 2 + TowerSize / 2, 0.);
608
609 // Remove the Towers that overlaps with the beam pipe
610 Double_t RadialDistance = TMath::Power(trans->GetTranslation()[0], 2) + TMath::Power(trans->GetTranslation()[1], 2);
611
612 if (RadialDistance < MinRadius * MinRadius || TMath::Abs(trans->GetTranslation()[0]) > SizeXHCAL / 2) {
613 continue;
614 }
615
616 // Adding the Tower to the HCAL
617 volHCAL->AddNode(volTowerHCAL, NumTowers, trans);
618
619 NumTowers++;
620 }
621 }
622
623 LOG(info) << "Number of Towers is: " << (NumTowers - 1);
624 LOG(info) << "Number of tubes is: " << (NumTubes - 1) * (NumTowers - 1);
625
626 // Create Aluminium plate at the back of HCal to simulate the electronics readout material
627 // Hardcoded thickness of 1cm and placement at 2 cm behind HCAL
628 TGeoBBox* alHcalBox = new TGeoBBox("AlHCalBox", SizeXHCAL / 2.0, SizeYHCAL / 2.0, 0.5 / 2.0);
629 TGeoVolume* volumeAlHcalBox = new TGeoVolume("volAlHcalBox", alHcalBox, gGeoManager->GetMedium(getMediumID(ID_ALUMINIUM)));
630 volumeAlHcalBox->SetLineColor(kOrange);
631 if (mGeometry->getInsertHCalReadoutMaterial()) {
632 TVirtualMC::GetMC()->Gspos("volAlHcalBox", 9999, "FOCAL", 0.0, 0.0, +1.0 * mGeometry->getFOCALSizeZ() / 2.0 + 1.0, 0, "ONLY");
633 // mSensitiveHCAL.push_back("volAlHcalBox");
634 mSensitive.push_back("volAlHcalBox");
635 }
636 TGeoBBox* alUnderBox = new TGeoBBox("AlUnderBox", SizeXHCAL / 2.0, 0.5, mGeometry->getFOCALSizeZ() / 2.0 + 1.5);
637 TGeoVolume* volumeAlUnderBox = new TGeoVolume("volAlUnderBox", alUnderBox, gGeoManager->GetMedium(getMediumID(ID_ALUMINIUM)));
638 volumeAlUnderBox->SetLineColor(kOrange);
639 if (mGeometry->getInsertHCalReadoutMaterial()) {
640 TVirtualMC::GetMC()->Gspos("volAlUnderBox", 9999, "FOCAL", 0.0, -1.0 * mGeometry->getFOCALSizeY() / 2 - 10.5, 0.0, 0, "ONLY");
641 // mSensitiveHCAL.push_back("volAlUnderBox");
642 mSensitive.push_back("volAlUnderBox");
643 }
644
645 volHCAL->SetVisibility();
646 volHCAL->SetVisDaughters();
647 TVirtualMC::GetMC()->Gspos("HCAL", 1, "FOCAL", 0, 0, mGeometry->getHCALCenterZ() - mGeometry->getFOCALSizeZ() / 2 + 0.01 + (mGeometry->getInsertFrontPadLayers() ? 2.0 : 0.0) - (mGeometry->getInsertHCalReadoutMaterial() ? 1.5 : 0.0), 0, "ONLY");
648}
649
650//_____________________________________________________________________________
652{
653 TGeoVolumeAssembly* volHCAL = new TGeoVolumeAssembly("HCAL");
654
656 Float_t pars[4]; // this is HMSC Assembly
657 pars[0] = mGeometry->getHCALTowerSize() / 2;
658 pars[1] = mGeometry->getHCALTowerSize() / 2;
659 pars[2] = mGeometry->getECALSizeZ() + mGeometry->getHCALSizeZ() / 2; // ECAL sizeZ is already added to the HCAL materials CenterZ, so it is also treated as offset
660 pars[3] = 0;
661
662 float offset = pars[2];
663
664 TGeoVolumeAssembly* volTower = new TGeoVolumeAssembly("Tower");
665
666 int iCu(0), iScint(0);
667 for (auto& icomp : mGeoCompositions) {
668
669 pars[0] = icomp->sizeX() / 2;
670 pars[1] = icomp->sizeY() / 2;
671 pars[2] = icomp->sizeZ() / 2;
672 pars[3] = 0;
673
674 // HCal materials
675
676 if (icomp->material() == "Pb") {
677 iCu++;
678 const TGeoMedium* medium = gGeoManager->GetMedium(getMediumID(ID_PB));
679 const TGeoBBox* HPadBox = new TGeoBBox("HPadBox", pars[0], pars[1], pars[2]);
680 TGeoVolume* HPad = new TGeoVolume("HPad", HPadBox, medium);
681 HPad->SetLineColor(kGray);
682 // mSensitiveHCAL.push_back(HPad->GetName());
683 mSensitive.push_back(HPad->GetName());
684 TGeoTranslation* trans = new TGeoTranslation(icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset);
685 volTower->AddNode(HPad, iCu, trans);
686 }
687 if (icomp->material() == "Scint") {
688 iScint++;
689 const TGeoMedium* medium = gGeoManager->GetMedium(getMediumID(ID_SC));
690 const TGeoBBox* HScintBox = new TGeoBBox("HScintBox", pars[0], pars[1], pars[2]);
691 TGeoVolume* HScint = new TGeoVolume("HScint", HScintBox, medium);
692 HScint->SetLineColor(kBlue);
693 // mSensitiveHCAL.push_back(HScint->GetName());
694 mSensitive.push_back(HScint->GetName());
695 TGeoTranslation* trans = new TGeoTranslation(icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset);
696 volTower->AddNode(HScint, iScint, trans);
697 }
698 if (icomp->material() == "CuHCAL") {
699 iCu++;
700 const TGeoMedium* medium = gGeoManager->GetMedium(getMediumID(ID_COPPER));
701 const TGeoBBox* HPadBox = new TGeoBBox("HPadBox", pars[0], pars[1], pars[2]);
702 TGeoVolume* HPad = new TGeoVolume("HPad", HPadBox, medium);
703 HPad->SetLineColor(kRed);
704 // mSensitiveHCAL.push_back(HPad->GetName());
705 mSensitive.push_back(HPad->GetName());
706 TGeoTranslation* trans = new TGeoTranslation(icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset);
707 volTower->AddNode(HPad, iCu, trans);
708 }
709 }
710 double TowerSize = mGeometry->getHCALTowerSize();
711
712 // Define the distance from the beam pipe in which towers will ommitted
713 double BeamPipeRadius = 3.6; // in cm
714 double TowerHalfDiag = TMath::Sqrt2() * 0.5 * TowerSize; // tower half diagonal
715 double MinRadius = BeamPipeRadius + TowerHalfDiag;
716
717 float SizeXHCAL = mGeometry->getHCALTowersInX() * TowerSize;
718 float SizeYHCAL = mGeometry->getHCALTowersInY() * TowerSize;
719
720 int nTowersX = mGeometry->getHCALTowersInX();
721 int nTowersY = mGeometry->getHCALTowersInY();
722
723 int Rows = 0;
724 int Columns = 0;
725 double RowPos = 0.;
726 int NumTowers = 1;
727
728 // Arranging towers
729 for (Rows = 0; Rows < nTowersY; Rows++) {
730 Columns = 0;
731 float ColumnPos = 0.;
732 RowPos = Rows * TowerSize;
733 for (Columns = 0; Columns < nTowersX; Columns++) {
734 ColumnPos = Columns * TowerSize;
735
736 TGeoTranslation* trans = new TGeoTranslation(ColumnPos - SizeXHCAL / 2 + TowerSize / 2, RowPos - SizeYHCAL / 2 + TowerSize / 2, 0.);
737
738 // Remove the Towers that overlaps with the beam pipe
739 double RadialDistance = TMath::Power(ColumnPos - SizeXHCAL / 2 + TowerSize / 2, 2) + TMath::Power(RowPos - SizeYHCAL / 2 + TowerSize / 2, 2);
740
741 if (RadialDistance < MinRadius * MinRadius) {
742 continue;
743 }
744
745 // Adding the Tower to the HCAL
746 volHCAL->AddNode(volTower, NumTowers, trans);
747
748 NumTowers++;
749 }
750 }
751 LOG(info) << "Number of Towers is: " << (NumTowers - 1);
752
753 // Create an Aluminium plate at the back of HCal to simulate the electronics readout material
754 // Hardcoded thickness of 1cm and placement at 2 cm behind HCAL
755 TGeoBBox* alHcalBox = new TGeoBBox("AlHCalBox", SizeXHCAL / 2.0, SizeYHCAL / 2.0, 0.5 / 2.0);
756 TGeoVolume* volumeAlHcalBox = new TGeoVolume("volAlHcalBox", alHcalBox, gGeoManager->GetMedium(getMediumID(ID_ALUMINIUM)));
757 volumeAlHcalBox->SetLineColor(kOrange);
758 if (mGeometry->getInsertHCalReadoutMaterial()) {
759 TVirtualMC::GetMC()->Gspos("volAlHcalBox", 9999, "FOCAL", 0.0, 0.0, +1.0 * mGeometry->getFOCALSizeZ() / 2.0 + 1.0, 0, "ONLY");
760 }
761 TGeoBBox* alUnderBox = new TGeoBBox("AlUnderBox", SizeXHCAL / 2.0, 0.5, mGeometry->getFOCALSizeZ() / 2.0 + 1.5);
762 TGeoVolume* volumeAlUnderBox = new TGeoVolume("volAlUnderBox", alUnderBox, gGeoManager->GetMedium(getMediumID(ID_ALUMINIUM)));
763 volumeAlUnderBox->SetLineColor(kOrange);
764 if (mGeometry->getInsertHCalReadoutMaterial()) {
765 TVirtualMC::GetMC()->Gspos("volAlUnderBox", 9999, "FOCAL", 0.0, -1.0 * mGeometry->getFOCALSizeY() / 2 - 10.5, 0.0, 0, "ONLY");
766 }
767
768 TGeoVolume* volFOCAL = gGeoManager->GetVolume("FOCAL");
769 volFOCAL->AddNode(volHCAL, 1, new TGeoTranslation(0, 0, mGeometry->getHCALCenterZ() - mGeometry->getFOCALSizeZ() / 2 + 0.01 + (mGeometry->getInsertFrontPadLayers() ? 2.0 : 0.0) - (mGeometry->getInsertHCalReadoutMaterial() ? 1.5 : 0.0))); // 0.01 to avoid overlap with ECAL
770}
771
772//_____________________________________________________________________________
774{
775 // using boost::algorithm::contains; // only when string operations
776 Geometry* geom = getGeometry();
777
778 // Int_t *idtmed = fIdtmed->GetArray() - 3599; //599 -> 3599
779
783
785 double pars[4]; // this is EMSC Assembly
786 pars[0] = geom->getTowerSizeX() / 2. + geom->getTowerGapSizeX() / 2.;
787 pars[1] = geom->getTowerSizeY() / 2. + geom->getTowerGapSizeY() / 2.;
788 // pars[2] = fGeom->GetFOCALSizeZ() / 2;
789 pars[2] = geom->getECALSizeZ() / 2;
790 pars[3] = 0;
791 // this shifts all the pixel layers to the center near the beampipe
792 double pixshift = geom->getTowerSizeX() - (geom->getGlobalPixelWaferSizeX() * geom->getNumberOfPIXsInX());
793
794 float offset = pars[2];
795 // gMC->Gsvolu("EMSC1", "BOX", idtmed[3698], pars, 4);//Left towers (pixels shifted right)
796 // gMC->Gsvolu("EMSC2", "BOX", idtmed[3698], pars, 4);//Right towers (pixels shifted left)
797
798 TVirtualMC::GetMC()->Gsvolu("EMSC1", "BOX", getMediumID(ID_AIR), pars, 4); // Left towers (pixels shifted right)
799 TVirtualMC::GetMC()->Gsvolu("EMSC2", "BOX", getMediumID(ID_AIR), pars, 4); // Right towers (pixels shifted left)
800 // mSensitiveECALPad.push_back("EMSC1");
801 // mSensitiveECALPad.push_back("EMSC2");
802 mSensitive.push_back("EMSC1");
803 mSensitive.push_back("EMSC2");
804
805 // const Composition *icomp = new Composition(); //to be removed
806 // for(int i = 0; i < 20; i++){ // old
807 // icomp = geom->getComposition(i, 0); // obsolete
808
809 // loop over geometry composition elements
810 for (auto& icomp : mGeoCompositions) {
811
812 pars[0] = icomp->sizeX() / 2.;
813 pars[1] = icomp->sizeY() / 2.;
814 pars[2] = icomp->sizeZ() / 2.;
815 pars[3] = 0;
816
817 if (icomp->material() == "PureW") {
818 // TVirtualMC::GetMC()->Gsvolu("EW1", "BOX", idtmed[3599], pars, 4);
819 TVirtualMC::GetMC()->Gsvolu("EW1", "BOX", getMediumID(ID_TUNGSTEN), pars, 4);
820 // mSensitiveECALPad.push_back("EW1");
821 mSensitive.push_back("EW1");
822 gGeoManager->GetVolume("EW1")->SetLineColor(kBlue);
823 TVirtualMC::GetMC()->Gspos("EW1", icomp->id() + 1, "EMSC1",
824 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
825 TVirtualMC::GetMC()->Gspos("EW1", icomp->id() + 1, "EMSC2",
826 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
827 }
828 if (icomp->material() == "Alloy") {
829 // TVirtualMC::GetMC()->Gsvolu("EW1", "BOX", idtmed[3604], pars, 4);
830 TVirtualMC::GetMC()->Gsvolu("EW1", "BOX", getMediumID(ID_ALLOY), pars, 4);
831 // mSensitiveECALPad.push_back("EW1");
832 mSensitive.push_back("EW1");
833 TVirtualMC::GetMC()->Gspos("EW1", icomp->id() + 1, "EMSC1",
834 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
835 TVirtualMC::GetMC()->Gspos("EW1", icomp->id() + 1, "EMSC2",
836 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
837 }
838
839 if (icomp->material() == "G10") {
840 // TVirtualMC::GetMC()->Gsvolu("G10RO1", "BOX", idtmed[3601], pars, 4);
841 TVirtualMC::GetMC()->Gsvolu("G10RO1", "BOX", getMediumID(ID_G10), pars, 4);
842 // mSensitiveECALPad.push_back("G10RO1");
843 mSensitive.push_back("G10RO1");
844 gGeoManager->GetVolume("G10RO1")->SetLineColor(kGreen);
845 TVirtualMC::GetMC()->Gspos("G10RO1", icomp->id() + 1, "EMSC1",
846 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
847 TVirtualMC::GetMC()->Gspos("G10RO1", icomp->id() + 1, "EMSC2",
848 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
849 }
850
851 if (icomp->material() == "Cu") {
852 // TVirtualMC::GetMC()->Gsvolu("EWCU", "BOX", idtmed[3602], pars, 4);
853 TVirtualMC::GetMC()->Gsvolu("EWCU", "BOX", getMediumID(ID_COPPER), pars, 4);
854 // mSensitiveECALPad.push_back("EWCU");
855 mSensitive.push_back("EWCU");
856 gGeoManager->GetVolume("EWCU")->SetLineColor(kViolet);
857 TVirtualMC::GetMC()->Gspos("EWCU", icomp->id() + 1, "EMSC1",
858 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
859 TVirtualMC::GetMC()->Gspos("EWCU", icomp->id() + 1, "EMSC2",
860 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
861 }
862
863 if (icomp->material() == "Air") {
864 // TVirtualMC::GetMC()->Gsvolu("EWAIR1", "BOX", idtmed[3698], pars, 4);
865 TVirtualMC::GetMC()->Gsvolu("EWAIR1", "BOX", getMediumID(ID_AIR), pars, 4);
866 // mSensitiveECALPad.push_back("EWAIR1");
867 mSensitive.push_back("EWAIR1");
868 gGeoManager->GetVolume("EWAIR1")->SetLineColor(kGray);
869 TVirtualMC::GetMC()->Gspos("EWAIR1", icomp->id() + 1, "EMSC1",
870 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
871 TVirtualMC::GetMC()->Gspos("EWAIR1", icomp->id() + 1, "EMSC2",
872 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
873 }
874
875 if (icomp->material() == "Ceramic") {
876 // TVirtualMC::GetMC()->Gsvolu("EWAIR1", "BOX", idtmed[3607], pars, 4);
877 TVirtualMC::GetMC()->Gsvolu("EWAIR1", "BOX", getMediumID(ID_CERAMIC), pars, 4);
878 // mSensitiveECALPad.push_back("EWAIR1");
879 mSensitive.push_back("EWAIR1");
880 TVirtualMC::GetMC()->Gspos("EWAIR1", icomp->id() + 1, "EMSC1",
881 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
882 TVirtualMC::GetMC()->Gspos("EWAIR1", icomp->id() + 1, "EMSC2",
883 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
884 }
885
886 if (icomp->material() == "SiPad") {
887 // TVirtualMC::GetMC()->Gsvolu("EWSIPAD1", "BOX", idtmed[3600], pars, 4);
888 TVirtualMC::GetMC()->Gsvolu("EWSIPAD1", "BOX", getMediumID(ID_SIPAD), pars, 4);
889 // mSensitiveECALPad.push_back("EWSIPAD1");
890 mSensitive.push_back("EWSIPAD1");
891 gGeoManager->GetVolume("EWSIPAD1")->SetLineColor(kOrange - 7);
892 int number = (icomp->id()) + (icomp->stack() << 12) + (icomp->layer() << 16);
893 // cout<<" pad : "<< icomp->material()<<" "<<number<<" x: "<< pars[0] << " y: " << pars[1] <<" Z coord: " << icomp->centerZ()-offset <<endl;
894 TVirtualMC::GetMC()->Gspos("EWSIPAD1", number + 1, "EMSC1",
895 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
896 TVirtualMC::GetMC()->Gspos("EWSIPAD1", number + 1, "EMSC2",
897 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
898 }
899
900 // Pixels (sensitive layer)
901 if (icomp->material() == "SiPix") {
902 // TVirtualMC::GetMC()->Gsvolu("EWSIPIX1", "BOX", idtmed[3600], pars, 4);
903 TVirtualMC::GetMC()->Gsvolu("EWSIPIX1", "BOX", getMediumID(ID_SIPIX), pars, 4);
904 // mSensitiveECALPix.push_back("EWSIPIX1");
905 mSensitive.push_back("EWSIPIX1");
906 gGeoManager->GetVolume("EWSIPIX1")->SetLineColor(kPink);
907
908 int number = (icomp->id()) + (icomp->stack() << 12) + (icomp->layer() << 16);
909 TVirtualMC::GetMC()->Gspos("EWSIPIX1", number + 1, "EMSC1",
910 icomp->centerX() - geom->getGlobalPixelOffsetX() + pixshift, icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
911 TVirtualMC::GetMC()->Gspos("EWSIPIX1", number + 1, "EMSC2",
912 icomp->centerX() + geom->getGlobalPixelOffsetX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
913 }
914
915 // Passive silicon
916 if (icomp->material() == "Si") {
917 // TVirtualMC::GetMC()->Gsvolu("EWSI1", "BOX", idtmed[3610], pars, 4);
918 TVirtualMC::GetMC()->Gsvolu("EWSI1", "BOX", getMediumID(ID_SIINSENS), pars, 4);
919 // mSensitiveECALPix.push_back("EWSI1");
920 mSensitive.push_back("EWSI1");
921 gGeoManager->GetVolume("EWSI1")->SetLineColor(kPink);
922 TVirtualMC::GetMC()->Gspos("EWSI1", icomp->id() + 1, "EMSC1",
923 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
924 TVirtualMC::GetMC()->Gspos("EWSI1", icomp->id() + 1, "EMSC2",
925 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
926 }
927 } // end of loop over composition elements
928
929 // Add the coldplates to each of the left and right towers
930 TGeoBBox* coldPlateBox = new TGeoBBox("ColdPlateBox", geom->getTowerSizeX() / 2.0, geom->getTowerGapSizeY() / 2.0, geom->getECALSizeZ() / 2.0);
931 TGeoVolume* volumeColdPlate = nullptr;
932
933 if (geom->getTowerGapMaterial() == "Cu") { // Copper
934 // if (contains(geom->getTowerGapMaterial(), "Cu")) { // Copper
935 volumeColdPlate = new TGeoVolume("volColdPlate", coldPlateBox, gGeoManager->GetMedium(getMediumID(ID_COPPER)));
936 } else if (geom->getTowerGapMaterial() == "Al") { // Aluminium
937 // else if (contains(geom->getTowerGapMaterial(), "Al")) { // Aluminium
938 volumeColdPlate = new TGeoVolume("volColdPlate", coldPlateBox, gGeoManager->GetMedium(getMediumID(ID_ALUMINIUM)));
939 } else {
940 volumeColdPlate = new TGeoVolume("volColdPlate", coldPlateBox, gGeoManager->GetMedium(getMediumID(ID_AIR)));
941 }
942 // mSensitiveECALPad.push_back(volumeColdPlate->GetName());
943 mSensitive.push_back(volumeColdPlate->GetName());
944 volumeColdPlate->SetLineColor(kOrange);
945 TVirtualMC::GetMC()->Gspos("volColdPlate", 1, "EMSC1", 0.0, geom->getTowerSizeY() / 2.0 + geom->getTowerGapSizeY() / 2.0, 0.0, 0, "ONLY");
946 TVirtualMC::GetMC()->Gspos("volColdPlate", 1, "EMSC2", 0.0, geom->getTowerSizeY() / 2.0 + geom->getTowerGapSizeY() / 2.0, 0.0, 0, "ONLY");
947
948 // Place the towers in the ECAL
949 // --- Place the ECAL in FOCAL
950 float fcal_pars[4];
951 fcal_pars[0] = (geom->getFOCALSizeX() + 2. * geom->getMiddleTowerOffset()) / 2.;
952 fcal_pars[1] = geom->getFOCALSizeY() / 2.;
953 fcal_pars[2] = geom->getECALSizeZ() / 2.;
954 fcal_pars[3] = 0.;
955
956 // TVirtualMC::GetMC()->Gsvolu("ECAL", "BOX", idtmed[3698], fcal_pars, 4);
957 TVirtualMC::GetMC()->Gsvolu("ECAL", "BOX", getMediumID(ID_AIR), fcal_pars, 4);
958 // mSensitiveECALPad.push_back("ECAL");
959 mSensitive.push_back("ECAL");
960
961 // Create SiPad box for the two sensitive layers to be placed in front of ECAL
962 TGeoBBox* siPadBox = new TGeoBBox("SiPadBox", geom->getTowerSizeX() / 2. + geom->getTowerGapSizeX() / 2.,
963 geom->getTowerSizeY() / 2. + geom->getTowerGapSizeY() / 2., 0.03 / 2.0);
964 TGeoVolume* volumeSiPad = new TGeoVolume("volSiPad", siPadBox, gGeoManager->GetMedium(getMediumID(ID_SIPAD)));
965 volumeSiPad->SetLineColor(kOrange + 7);
966 // mSensitiveECALPad.push_back(volumeSiPad->GetName());
967 if (geom->getInsertFrontPadLayers()) {
968 mSensitive.push_back(volumeSiPad->GetName());
969 }
970
971 double xp, yp, zp;
972 int itowerx, itowery;
973 // int number = i + j * geom->getNumberOfTowersInX();
974 for (int number = 0; number < geom->getNumberOfTowersInX() * geom->getNumberOfTowersInY(); number++) {
975 itowerx = number % geom->getNumberOfTowersInX();
976 itowery = number / geom->getNumberOfTowersInX();
977 // const auto towerCenter = geom->getGeoTowerCenter(number); //only ECAL part, second parameter = -1 by default
978 // xp = std::get<0>towerCenter;
979 // std::tie(xp, yp, zp) = geom->getGeoTowerCenter(number);
980 const auto [xp, yp, zp] = geom->getGeoTowerCenter(number); // only ECAL part, second parameter = -1 by default
981
982 if (itowerx == 0) {
983 TVirtualMC::GetMC()->Gspos("EMSC1", number + 1, "ECAL", xp, yp, 0, 0, "ONLY");
984 // Add the SiPad front volumes directly under the FOCAL volume
985 if (geom->getInsertFrontPadLayers()) {
986 TVirtualMC::GetMC()->Gspos("volSiPad", -1 * (number + 1), "FOCAL", xp, yp, -1.0 * geom->getFOCALSizeZ() / 2.0, 0, "ONLY");
987 // mSensitiveECALPad.push_back("volSiPad");
988 mSensitive.push_back("volSiPad");
989 TVirtualMC::GetMC()->Gspos("volSiPad", -1 * (geom->getNumberOfTowersInX() * geom->getNumberOfTowersInY() + number + 1), "FOCAL", xp - 0.5, yp + 0.5, -1.0 * geom->getFOCALSizeZ() / 2.0 + 1.0, 0, "ONLY");
990 // mSensitiveECALPad.push_back("volSiPad");
991 mSensitive.push_back("volSiPad");
992 }
993 }
994 if (itowerx == 1) {
995 TVirtualMC::GetMC()->Gspos("EMSC2", number + 1, "ECAL", xp, yp, 0, 0, "ONLY");
996 // Add the SiPad front volumes directly under the FOCAL volume
997 if (geom->getInsertFrontPadLayers()) {
998 TVirtualMC::GetMC()->Gspos("volSiPad", -1 * (number + 1), "FOCAL", xp, yp, -1.0 * geom->getFOCALSizeZ() / 2.0, 0, "ONLY");
999 // mSensitiveECALPad.push_back("volSiPad");
1000 mSensitive.push_back("volSiPad");
1001 TVirtualMC::GetMC()->Gspos("volSiPad", -1 * (geom->getNumberOfTowersInX() * geom->getNumberOfTowersInY() + number + 1), "FOCAL", xp + 0.5, yp + 0.5, -1.0 * geom->getFOCALSizeZ() / 2.0 + 1.0, 0, "ONLY");
1002 // mSensitiveECALPad.push_back("volSiPad");
1003 mSensitive.push_back("volSiPad");
1004 }
1005 }
1006 } // end of loop over ECAL towers (TowersInX x TowersInY)
1007
1008 TVirtualMC::GetMC()->Gspos("ECAL", 1, "FOCAL", 0, 0, geom->getECALCenterZ() - geom->getFOCALSizeZ() / 2.0 + (geom->getInsertFrontPadLayers() ? 2.0 : 0.0) - (geom->getInsertHCalReadoutMaterial() ? 1.5 : 0.0), 0, "ONLY");
1009}
1010
1012{
1013 mCurrentPrimaryID = fMC->GetStack()->GetCurrentTrackNumber();
1014 LOG(debug) << "Starting primary " << mCurrentPrimaryID << " with energy " << fMC->GetStack()->GetCurrentTrack()->Energy();
1015}
1016
1018{
1019 LOG(debug) << "Finishing primary " << mCurrentPrimaryID;
1020 // Resetting primary and parent ID
1021 mCurrentPrimaryID = -1;
1022}
1023
1025{
1026 LOG(debug) << "We are in sensitive volume " << v->GetName() << ": " << TVirtualMC::GetMC()->CurrentVolPath();
1027
1028 double eloss = TVirtualMC::GetMC()->Edep() * 1e9; // energy in eV (GeV->eV)
1029 if (eloss < DBL_EPSILON) {
1030 return false; // only process hits which actually deposit some energy in the FOCAL
1031 }
1032
1033 // In case of new parent track create new track reference
1034 auto o2stack = static_cast<o2::data::Stack*>(TVirtualMC::GetMC()->GetStack());
1035 if (!mCurrentSuperparent->mHasTrackReference) {
1036 float x, y, z, px, py, pz, e;
1037 TVirtualMC::GetMC()->TrackPosition(x, y, z);
1038 TVirtualMC::GetMC()->TrackMomentum(px, py, pz, e);
1039 o2::TrackReference trackref(x, y, z, px, py, pz, TVirtualMC::GetMC()->TrackLength(), TVirtualMC::GetMC()->TrackTime(), mCurrentParentID, GetDetId());
1040 o2stack->addTrackReference(trackref);
1041 mCurrentSuperparent->mHasTrackReference = true;
1042 }
1043
1044 float posX, posY, posZ;
1045 TVirtualMC::GetMC()->TrackPosition(posX, posY, posZ);
1046
1047 auto [indetector, col, row, layer, segment] = mGeometry->getVirtualInfo(posX, posY, posZ);
1048
1049 if (!indetector) {
1050 // particle outside the detector
1051 return true;
1052 }
1053
1054 auto currenthit = FindHit(mCurrentParentID, col, row, layer);
1055 if (!currenthit) {
1056 // Condition for new hit:
1057 // - Processing different partent track (parent track must be produced outside FOCAL)
1058 // - Inside different cell
1059 // - First track of the event
1060 Double_t time = TVirtualMC::GetMC()->TrackTime() * 1e9; // time in ns
1061 LOG(debug3) << "Adding new hit for parent " << mCurrentParentID << " and cell Col: " << col << " Row: " << row << " segment: " << segment;
1062
1064 AddHit(mCurrentParentID, mCurrentPrimaryID, mCurrentSuperparent->mEnergy, row * col + col, o2::focal::Hit::Subsystem_t::EPADS, math_utils::Point3D<float>(posX, posY, posZ), time, eloss);
1065 o2stack->addHit(GetDetId());
1066 } else {
1067 LOG(debug3) << "Adding energy to the current hit";
1068 currenthit->SetEnergyLoss(currenthit->GetEnergyLoss() + eloss);
1069 }
1070 return true;
1071}
1072
1074{
1075 LOG(debug) << "We are in sensitive volume " << v->GetName() << ": " << fMC->CurrentVolPath();
1076
1077 double eloss = fMC->Edep() * 1e9; // energy in eV (GeV->eV)
1078 if (eloss < DBL_EPSILON) {
1079 return false; // only process hits which actually deposit some energy in the FOCAL
1080 }
1081
1082 // In case of new parent track create new track reference
1083 auto o2stack = static_cast<o2::data::Stack*>(fMC->GetStack());
1084 if (!mCurrentSuperparent->mHasTrackReference) {
1085 float x, y, z, px, py, pz, e;
1086 fMC->TrackPosition(x, y, z);
1087 fMC->TrackMomentum(px, py, pz, e);
1088 o2::TrackReference trackref(x, y, z, px, py, pz, fMC->TrackLength(), fMC->TrackTime(), mCurrentParentID, GetDetId());
1089 o2stack->addTrackReference(trackref);
1090 mCurrentSuperparent->mHasTrackReference = true;
1091 }
1092
1093 float posX, posY, posZ;
1094 fMC->TrackPosition(posX, posY, posZ);
1095
1096 auto [indetector, col, row, layer, segment] = mGeometry->getVirtualInfo(posX, posY, posZ);
1097
1098 if (!indetector) {
1099 // particle outside the detector
1100 return true;
1101 }
1102
1103 auto currenthit = FindHit(mCurrentParentID, col, row, layer);
1104 if (!currenthit) {
1105 // Condition for new hit:
1106 // - Processing different partent track (parent track must be produced outside FOCAL)
1107 // - Inside different cell
1108 // - First track of the event
1109 Double_t time = fMC->TrackTime() * 1e9; // time in ns
1110 LOG(debug3) << "Adding new hit for parent " << mCurrentParentID << " and cell Col: " << col << " Row: " << row << " segment: " << segment;
1111
1113 AddHit(mCurrentParentID, mCurrentPrimaryID, mCurrentSuperparent->mEnergy, row * col + col, o2::focal::Hit::Subsystem_t::HCAL, math_utils::Point3D<float>(posX, posY, posZ), time, eloss);
1114 o2stack->addHit(GetDetId());
1115 } else {
1116 LOG(debug3) << "Adding energy to the current hit";
1117 currenthit->SetEnergyLoss(currenthit->GetEnergyLoss() + eloss);
1118 }
1119 return true;
1120}
1121
1123{
1124 LOG(debug) << "We are in sensitive volume " << v->GetName() << ": " << fMC->CurrentVolPath();
1125
1126 double eloss = fMC->Edep() * 1e9; // energy in eV (GeV->eV)
1127 if (eloss < DBL_EPSILON) {
1128 return false; // only process hits which actually deposit some energy in the FOCAL
1129 }
1130
1131 // In case of new parent track create new track reference
1132 auto o2stack = static_cast<o2::data::Stack*>(fMC->GetStack());
1133 if (!mCurrentSuperparent->mHasTrackReference) {
1134 float x, y, z, px, py, pz, e;
1135 fMC->TrackPosition(x, y, z);
1136 fMC->TrackMomentum(px, py, pz, e);
1137 o2::TrackReference trackref(x, y, z, px, py, pz, fMC->TrackLength(), fMC->TrackTime(), mCurrentParentID, GetDetId());
1138 o2stack->addTrackReference(trackref);
1139 mCurrentSuperparent->mHasTrackReference = true;
1140 }
1141
1142 float posX, posY, posZ;
1143 fMC->TrackPosition(posX, posY, posZ);
1144
1145 auto [indetector, col, row, layer, segment] = mGeometry->getVirtualInfo(posX, posY, posZ);
1146
1147 if (!indetector) {
1148 // particle outside the detector
1149 return true;
1150 }
1151
1152 auto currenthit = FindHit(mCurrentParentID, col, row, layer);
1153 if (!currenthit) {
1154 // Condition for new hit:
1155 // - Processing different partent track (parent track must be produced outside FOCAL)
1156 // - Inside different cell
1157 // - First track of the event
1158 Double_t time = fMC->TrackTime() * 1e9; // time in ns
1159 LOG(debug3) << "Adding new hit for parent " << mCurrentParentID << " and cell Col: " << col << " Row: " << row << " segment: " << segment;
1160
1162 AddHit(mCurrentParentID, mCurrentPrimaryID, mCurrentSuperparent->mEnergy, row * col + col, o2::focal::Hit::Subsystem_t::EPIXELS, math_utils::Point3D<float>(posX, posY, posZ), time, eloss);
1163 o2stack->addHit(GetDetId());
1164 } else {
1165 LOG(debug3) << "Adding energy to the current hit";
1166 currenthit->SetEnergyLoss(currenthit->GetEnergyLoss() + eloss);
1167 }
1168 return true;
1169}
Definition of the Stack class.
int16_t time
Definition RawEventData.h:4
uint16_t pos
Definition RawData.h:3
uint32_t col
Definition RawData.h:4
std::ostringstream debug
int registerSensitiveVolumeAndGetVolID(std::string const &name)
Definition Detector.cxx:190
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
int getMediumID(int imed) const
Definition Detector.h:135
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
FOCAL detector simulation.
Definition Detector.h:54
bool ProcessHitsEPad(FairVolume *v=nullptr)
Processing hit creation in the ECAL Pad sensitive volume.
void addAlignableVolumesHCAL() const
Definition Detector.cxx:407
~Detector() override
Destructor.
Definition Detector.cxx:65
void InitializeO2Detector() override
Initializing detector.
Definition Detector.cxx:81
bool ProcessHitsHCAL(FairVolume *v=nullptr)
Processing hit creation in the HCAL sensitive volume.
virtual void CreateHCALSandwich()
Definition Detector.cxx:651
void Register() override
register container with hits
Definition Detector.cxx:197
Hit * AddHit(int trackID, int primary, double initialEnergy, int detID, o2::focal::Hit::Subsystem_t subsystem, const math_utils::Point3D< float > &pos, double time, double energyloss)
Add FOCAL hit.
Definition Detector.cxx:163
void FinishPrimary() override
Finish current primary.
virtual void CreateHCALSpaghetti()
Definition Detector.cxx:492
void ConstructGeometry() override
Definition Detector.cxx:428
void addAlignableVolumesECAL() const
Definition Detector.cxx:418
bool ProcessHitsEPix(FairVolume *v=nullptr)
Processing hit creation in the ECAL Pixel sensitive volume.
virtual void addAlignableVolumes() const override
declare alignable volumes of detector
Definition Detector.cxx:395
void CreateMaterials()
Creating detector materials for the FOCAL detector.
Definition Detector.cxx:216
Hit * FindHit(int parentID, int col, int row, int layer)
Try to find hit with same cell and parent track ID.
Definition Detector.cxx:176
Bool_t ProcessHits(FairVolume *v=nullptr) final
Processing hit creation in the FOCAL sensitive volume.
Definition Detector.cxx:108
void EndOfEvent() final
Steps to be carried out at the end of the event.
Definition Detector.cxx:195
void BeginPrimary() override
Begin primaray.
void CreateECALGeometry()
Generate ECAL geometry.
Definition Detector.cxx:773
Detector()=default
Dummy constructor.
Parent * AddSuperparent(int trackID, int pdg, double energy)
Add new superparent to the container.
Definition Detector.cxx:188
void Reset() final
Clean point collection.
Definition Detector.cxx:202
Geometry * getGeometry(std::string name="")
Get the FOCAL geometry desciption.
Definition Detector.cxx:70
double getTowerGapSizeY() const
Definition Geometry.h:127
double getFOCALSizeY() const
Definition Geometry.cxx:830
int getNumberOfTowersInX() const
Definition Geometry.h:123
bool getInsertFrontPadLayers() const
Definition Geometry.h:135
bool getInsertHCalReadoutMaterial() const
Definition Geometry.h:136
double getTowerGapSizeX() const
Definition Geometry.h:126
double getHCALSizeZ() const
Definition Geometry.cxx:869
int getNumberOfTowersInY() const
Definition Geometry.h:124
double getECALSizeZ() const
Definition Geometry.cxx:848
int getHCALTowersInY() const
Definition Geometry.h:103
std::tuple< bool, int, int, int, int > getVirtualInfo(double x, double y, double z) const
double getGlobalPixelWaferSizeX() const
Definition Geometry.h:129
double getFOCALSizeZ() const
Definition Geometry.cxx:836
float getHCALTowerSize() const
Definition Geometry.h:101
static Geometry * getInstance()
Definition Geometry.cxx:41
int getHCALTowersInX() const
Definition Geometry.h:102
double getHCALCenterZ() const
Definition Geometry.cxx:880
std::tuple< double, double, double > getGeoTowerCenter(int tower, int segment=-1) const
this gives global position of the center of tower
Definition Geometry.cxx:671
double getTowerSizeX() const
Definition Geometry.cxx:810
std::vector< const Composition * > getFOCALMicroModule(int layer) const
Definition Geometry.cxx:650
std::string_view getTowerGapMaterial() const
Definition Geometry.h:140
double getFOCALZ0() const
Definition Geometry.h:122
float getMiddleTowerOffset() const
Definition Geometry.h:134
double getFOCALSizeX() const
Definition Geometry.cxx:824
bool getUseHCALSandwich()
Definition Geometry.h:158
double getTowerSizeY() const
Definition Geometry.cxx:817
int getNumberOfPIXsInX() const
Definition Geometry.h:99
double getECALCenterZ() const
Definition Geometry.cxx:860
double getGlobalPixelOffsetX() const
Definition Geometry.h:132
Common FOCAL hit class for the detector simulation.
Definition Hit.h:28
Subsystem_t
Subsystem index of the Hit.
Definition Hit.h:32
static ShmManager & Instance()
Definition ShmManager.h:61
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint segment
Definition glcorearb.h:4945
GLuint entry
Definition glcorearb.h:5735
const GLdouble * v
Definition glcorearb.h:832
GLuint const GLchar * name
Definition glcorearb.h:781
GLint y
Definition glcorearb.h:270
GLboolean * data
Definition glcorearb.h:298
GLintptr offset
Definition glcorearb.h:660
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
D const SVectorGPU< T, D > & rhs
Definition SMatrixGPU.h:191
void freeSimVector(std::vector< T > *ptr)
std::vector< T > * createSimVector()
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Common utility functions.
Mapped information of a channel.
Definition Hit.h:41
Information about superparent (particle entering any FOCAL volume)
Definition Detector.h:32
double mEnergy
Total energy.
Definition Detector.h:34
bool mHasTrackReference
Flag indicating whether parent has a track reference.
Definition Detector.h:35
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< int > row