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 mHits(o2::utils::createSimVector<Hit>()),
54 mCurrentSuperparent(nullptr),
55 mCurrentTrack(-1),
56 mCurrentPrimaryID(-1),
57 mCurrentParentID(-1)
58{
59 mGeometry = rhs.mGeometry;
60 mMedSensHCal = rhs.mMedSensHCal;
61 mMedSensECalPad = rhs.mMedSensECalPad;
62 mMedSensECalPix = rhs.mMedSensECalPix;
63 mSensitive = rhs.mSensitive;
64 // mSensitiveHCAL = rhs.mSensitiveHCAL;
65 // mSensitiveECALPad = rhs.mSensitiveECALPad;
66 // mSensitiveECALPix = rhs.mSensitiveECALPix;
67 mVolumeIDScintillator = rhs.mVolumeIDScintillator;
68}
69
74
76{
77 if (!mGeometry) {
78 mGeometry = Geometry::getInstance(name);
79 }
80 if (!mGeometry) {
81 LOG(error) << "Failure accessing geometry";
82 }
83 return mGeometry;
84}
85
87{
88
89 LOG(info) << "Intializing FOCAL detector";
90
91 // All FOCAL volumes must be declared as sensitive, otherwise
92 // the decay chains are broken by volumes not processed in ProceeHits
93 for (const auto& child : mSensitive) {
94 LOG(debug1) << "Adding sensitive volume " << child;
95 auto svolID = registerSensitiveVolumeAndGetVolID(child);
96 // HCAL
97 if (child == "ScintFiber" || child == "HScint") {
98 LOG(debug1) << "Adding ScintFiber/HScint volume as sensitive volume with ID " << svolID;
99 mVolumeIDScintillator = svolID;
100 }
101 // ECAL Pads
102 else if (child == "EMSC1" || child == "EMSC2") {
103 LOG(debug1) << "Adding EMC SILICON volume as sensitive volume with ID " << svolID;
104 mVolumeIDScintillator = svolID;
105 }
106 }
107
108 mMedSensHCal = getMediumID(ID_SC);
109 mMedSensECalPad = getMediumID(ID_SIPAD);
110 mMedSensECalPix = getMediumID(ID_SIPIX);
111}
112
114{
115 int track = fMC->GetStack()->GetCurrentTrackNumber(),
116 directparent = fMC->GetStack()->GetCurrentParentTrackNumber();
117 // Like other calorimeters FOCAL will create a huge amount of shower particles during tracking
118 // Instead, the hits should be assigned to the incoming particle in FOCAL.
119 // Implementation of the incoming particle search taken from implementation in EMCAL.
120 if (track != mCurrentTrack) {
121 LOG(debug4) << "Doing new track " << track << " current (" << mCurrentTrack << "), direct parent (" << directparent << ")";
122 // new current track - check parentage
123 auto hasSuperParent = mSuperParentsIndices.find(directparent);
124 if (hasSuperParent != mSuperParentsIndices.end()) {
125 // same superparent as direct parent
126 mCurrentParentID = hasSuperParent->second;
127 mSuperParentsIndices[track] = hasSuperParent->second;
128 auto superparent = mSuperParents.find(mCurrentParentID);
129 if (superparent != mSuperParents.end()) {
130 mCurrentSuperparent = &(superparent->second);
131 } else {
132 LOG(error) << "Attention: No superparent object found (parent " << mCurrentParentID << ")";
133 mCurrentSuperparent = nullptr;
134 }
135 LOG(debug4) << "Found superparent " << mCurrentParentID;
136 } else {
137 // start of new chain
138 // for new incoming tracks the super parent index is equal to the track ID (for recursion)
139 mSuperParentsIndices[track] = track;
140 mCurrentSuperparent = AddSuperparent(track, fMC->TrackPid(), fMC->Etot());
141 mCurrentParentID = track;
142 }
143 mCurrentTrack = track;
144 }
145
146 // Processing HCAL hits
147 bool flagHCAL = true;
148 if (fMC->CurrentMedium() == mMedSensHCal) {
149 flagHCAL = ProcessHitsHCAL(v);
150 }
151
152 // Processing ECAL Pad hits
153 bool flagECALPad = true;
154 if (TVirtualMC::GetMC()->CurrentMedium() == mMedSensECalPad) {
155 flagECALPad = ProcessHitsEPad(v);
156 }
157
158 // Processing ECAL Pixel hits
159 bool flagECALPix = true;
160 if (fMC->CurrentMedium() == mMedSensECalPix) {
161 flagECALPix = ProcessHitsEPix(v);
162 }
163
164 return (flagHCAL || flagECALPad || flagECALPix);
165 // return true;
166}
167
168Hit* Detector::AddHit(int trackID, int primary, double initialEnergy, int detID, o2::focal::Hit::Subsystem_t subsystem,
169 const math_utils::Point3D<float>& pos, double time, double eLoss)
170{
171 LOG(debug3) << "Adding hit for track " << trackID << " with position (" << pos.X() << ", "
172 << pos.Y() << ", " << pos.Z() << ") with energy " << initialEnergy << " loosing " << eLoss;
173 mHits->emplace_back(primary, trackID, detID, subsystem, initialEnergy, pos, time, eLoss);
174
175 auto [isin, col, row, layer, segment] = mGeometry->getVirtualInfo(pos.X(), pos.Y(), pos.Z());
176 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)));
177
178 return &(mHits->back());
179}
180
181Hit* Detector::FindHit(int parentID, int col, int row, int layer)
182{
183 Hit::HitID hitToFind{parentID, uint8_t(row), uint8_t(col), uint8_t(layer)};
184 auto found = mHitIndexMapping.find(hitToFind);
185
186 if (found == mHitIndexMapping.end()) {
187 return nullptr;
188 }
189
190 return &((*mHits)[found->second]);
191}
192
193Parent* Detector::AddSuperparent(int trackID, int pdg, double energy)
194{
195 LOG(debug3) << "Adding superparent for track " << trackID << " with PID " << pdg << " and energy " << energy;
196 auto entry = mSuperParents.insert({trackID, {pdg, energy, false}});
197 return &(entry.first->second);
198}
199
201
203{
204 FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, kTRUE);
205}
206
208{
209 LOG(debug) << "Cleaning FOCAL hits ...";
210 if (!o2::utils::ShmManager::Instance().isOperational()) {
211 mHits->clear();
212 }
213 mHitIndexMapping.clear();
214
215 mSuperParentsIndices.clear();
216 mSuperParents.clear();
217 mCurrentTrack = -1;
218 mCurrentParentID = -1;
219}
220
222{
223
224 // --- Define the various materials for GEANT ---
225
227 float aSi = 28.09;
228 float zSi = 14.0;
229 float dSi = 2.33;
230 float x0Si = 9.36;
231 Material(1, "Si $", aSi, zSi, dSi, x0Si, 18.5);
232
234 float aW = 183.84;
235 float zW = 74.0;
236 float dW = 19.3;
237 float x0W = 0.35;
238 Material(0, "W $", aW, zW, dW, x0W, 17.1);
239
240 // Cu
241 Material(3, "Cu $", 63.54, 29., 8.96, 1.43, 15.);
242
243 // Al
244 Material(9, "Al$", 26.98, 13.0, 2.7, 8.9, 37.2);
245
247 Material(10, "Pb $", 207.19, 82., 11.35, .56, 18.5);
248
250 // --- The polysterene scintillator (CH) ---
251 float aP[2] = {12.011, 1.00794};
252 float zP[2] = {6.0, 1.0};
253 float wP[2] = {1.0, 1.0};
254 float dP = 1.032;
255 Mixture(11, "Polystyrene$", aP, zP, dP, -2, wP);
256
257 // G10
258
259 float aG10[4] = {1., 12.011, 15.9994, 28.086};
260 float zG10[4] = {1., 6., 8., 14.};
261 // PH float wG10[4]={0.148648649,0.104054054,0.483499056,0.241666667};
262 float wG10[4] = {0.15201, 0.10641, 0.49444, 0.24714};
263 Mixture(2, "G10 $", aG10, zG10, 1.7, 4, wG10);
264
266 float aAlloy[3] = {183.84, 58.6934, 63.54};
267 float zAlloy[3] = {74.0, 28, 29};
268 float wAlloy[3] = {0.94, 0.04, 0.02};
269 float dAlloy = wAlloy[0] * 19.3 + wAlloy[1] * 8.908 + wAlloy[2] * 8.96;
270 Mixture(5, "Alloy $", aAlloy, zAlloy, dAlloy, 3, wAlloy);
271
272 // Steel
273 float aSteel[4] = {55.847, 51.9961, 58.6934, 28.0855};
274 float zSteel[4] = {26., 24., 28., 14.};
275 float wSteel[4] = {.715, .18, .1, .005};
276 float dSteel = 7.88;
277 Mixture(4, "STAINLESS STEEL$", aSteel, zSteel, dSteel, 4, wSteel);
278
279 // Air
280 float aAir[4] = {12.0107, 14.0067, 15.9994, 39.948};
281 float zAir[4] = {6., 7., 8., 18.};
282 float wAir[4] = {0.000124, 0.755268, 0.231781, 0.012827};
283 float dAir1 = 1.20479E-10;
284 float dAir = 1.20479E-3;
285 Mixture(98, "Vacum$", aAir, zAir, dAir1, 4, wAir);
286 Mixture(99, "Air $", aAir, zAir, dAir, 4, wAir);
287
288 // Ceramic
289 // Ceramic 97.2% Al2O3 , 2.8% SiO2
290 // float wcer[2]={0.972,0.028}; // Not used
291 float aal2o3[2] = {26.981539, 15.9994};
292 float zal2o3[2] = {13., 8.};
293 float wal2o3[2] = {2., 3.};
294 float denscer = 3.6;
295 // SiO2
296 float aglass[2] = {28.0855, 15.9994};
297 float zglass[2] = {14., 8.};
298 float wglass[2] = {1., 2.};
299 float dglass = 2.65;
300 Mixture(6, "Al2O3 $", aal2o3, zal2o3, denscer, -2, wal2o3);
301 Mixture(7, "glass $", aglass, zglass, dglass, -2, wglass);
302
303 // Ceramic is a mixtur of glass and Al2O3 ?
304 // Not clear how to do this with AliMixture
305 // Not needed; so skip for now
306
307 /*
308float acer[2],zcer[2];
309char namate[21]="";
310float a,z,d,radl,absl,buf[1];
311Int_t nbuf;
312fMC->Gfmate((*fIdmate)[6], namate, a, z, d, radl, absl, buf, nbuf);
313acer[0]=a;
314zcer[0]=z;
315fMC->Gfmate((*fIdmate)[7], namate, a, z, d, radl, absl, buf, nbuf);
316acer[1]=a;
317zcer[1]=z;
318
319AliMixture( 8, "Ceramic $", acer, zcer, denscer, 2, wcer);
320*/
321
322 // Use Al2O3 instead:
323
324 Mixture(8, "Ceramic $", aal2o3, zal2o3, denscer, -2, wal2o3);
325
326 // Define tracking media
327 // format
328
329 float tmaxfdSi = 10.0; // 0.1; // .10000E+01; // Degree
330 float stemaxSi = 0.1; // .10000E+01; // cm
331 float deemaxSi = 0.1; // 0.30000E-02; // Fraction of particle's energy 0<deemax<=1
332 // float epsilSi = 1.e-3;//1e-3;//1.0E-4;// .10000E+01;
333 float epsilSi = 1.e-3; // 1.0E-4;// .10000E+01; // This drives the step size ? 1e-4 makes multiple steps even in pixels?
334 float stminSi = 0.001; // cm "Default value used"
335
336 float epsil = 0.001;
337 // MvL: need to look up itdmed dynamically?
338 // or move to TGeo: uses pointers for medium
339
340 int isxfld = 2;
341 float sxmgmx = 10.0;
343
345 Medium(ID_TUNGSTEN, "W conv.$", 0, 0,
346 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.1, nullptr, 0);
348 Medium(ID_SIPAD, "Si sens pad$", 1, 0,
349 isxfld, sxmgmx, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi, nullptr, 0);
351 Medium(ID_SIPIX, "Si sens pix$", 1, 0,
352 isxfld, sxmgmx, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi, nullptr, 0);
353
355 Medium(ID_G10, "G10 plate$", 2, 0,
356 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.01, nullptr, 0);
357
359 Medium(ID_COPPER, "Cu$", 3, 0,
360 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.0001, nullptr, 0);
361
363 Medium(ID_STEEL, "S steel$", 4, 0,
364 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.0001, nullptr, 0);
365
367 Medium(ID_ALLOY, "Alloy conv.$", 5, 0,
368 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.1, nullptr, 0);
369
371 Medium(ID_CERAMIC, "Ceramic$", 8, 0,
372 isxfld, sxmgmx, 10.0, 0.01, 0.1, 0.003, 0.003, nullptr, 0);
373
374 // HCAL materials // Need to double-check tracking pars for this
376 Medium(ID_PB, "Pb // The Scintillator must be first in order in vector for Rin to be set$", 10, 0,
377 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.1, nullptr, 0);
379 Medium(ID_SC, "Scint$", 11, 0,
380 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.001, 0.001, nullptr, 0);
381
383 Medium(ID_SIINSENS, "Si insens$", 1, 0,
384 isxfld, sxmgmx, 10.0, 0.1, 0.1, epsil, 0.001, nullptr, 0);
385
386 // Al for the cold plates
387 Medium(ID_ALUMINIUM, "Aluminium$", 9, 0,
388 isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.1, nullptr, 0);
389
391 Medium(ID_VAC, "Vacuum $", 98, 0,
392 isxfld, sxmgmx, 10.0, 1.0, 0.1, 0.1, 1.0, nullptr, 0);
393
395 Medium(ID_AIR, "Air gaps$", 99, 0,
396 isxfld, sxmgmx, 10.0, 1.0, 0.1, epsil, 0.001, nullptr, 0);
397}
398
399//____________________________________________________________________________
401{
402 // Create entries for alignable volumes associating the symbolic volume
403 // name with the corresponding volume path. Needs to be syncronized with
404 // eventual changes in the geometry
405 // Alignable volumes are:
406
409}
410
411//____________________________________________________________________________
413{
414 const std::string vpsector = "/cave_1/barrel_1/FOCAL_1/HCAL_1";
415 const std::string snsector = "FOCAL/HCAL";
416
417 if (!gGeoManager->SetAlignableEntry(snsector.c_str(), vpsector.c_str())) {
418 LOG(fatal) << "Alignable entry " << snsector << " not created. Volume path " << vpsector << "not valid.";
419 }
420}
421
422//____________________________________________________________________________
424{
425 const std::string vpsector = "/cave_1/barrel_1/FOCAL_1/ECAL_1";
426 const std::string snsector = "FOCAL/ECAL";
427
428 if (!gGeoManager->SetAlignableEntry(snsector.c_str(), vpsector.c_str())) {
429 LOG(fatal) << "Alignable entry " << snsector << " not created. Volume path " << vpsector << "not valid.";
430 }
431}
432
434{
435
446
447 LOG(debug) << "Creating FOCAL geometry\n";
448
450
452 mGeoCompositions = mGeometry->getFOCALMicroModule(-1);
453 if (!mGeoCompositions.size()) {
454 LOG(error) << "FOCAL compositions not found!!";
455 return;
456 }
457
458 float pars[4];
459 pars[0] = (mGeometry->getFOCALSizeX() + 2 * mGeometry->getMiddleTowerOffset() + mGeometry->getDetectorOpeningRight() + mGeometry->getDetectorOpeningLeft()) / 2;
460 pars[1] = mGeometry->getFOCALSizeY() / 2;
461 pars[2] = mGeometry->getFOCALSizeZ() / 2;
462 // Add space to place 2 SiPad layers in front of ECAL
463 // The global position of ECAL and HCAL remains the same, but the FOCAL box needs to be slightly larger to accomodate
464 // the 2 SiPad layers which will sit at z=698 and 699cm (2 and 1 cm in front of ECAL)
465 if (mGeometry->getInsertFrontPadLayers()) {
466 pars[2] += 1.0;
467 }
468 if (mGeometry->getInsertHCalReadoutMaterial()) {
469 pars[2] += (1.0 + 0.5); // place Aluminium 1cm thick box (0.5 means half) at 2cm behind HCal to simulate SiPM readout material
470 pars[1] += (10.0 + 1.0); // place Aluminium 1cm thick box at 10 cm below FOCAL
471 }
472 pars[3] = 0;
473
474 LOG(info) << "Creating FOCAL with dimensions X: " << (mGeometry->getFOCALSizeX() + 2 * mGeometry->getMiddleTowerOffset()) << ", Y: "
475 << mGeometry->getFOCALSizeY() << ", Z: " << mGeometry->getFOCALSizeZ() + (mGeometry->getInsertFrontPadLayers() ? 2.0 : 0.0) + (mGeometry->getInsertHCalReadoutMaterial() ? 3.0 : 0.0);
476
477 TVirtualMC::GetMC()->Gsvolu("FOCAL", "BOX", getMediumID(ID_AIR), pars, 4);
478 mSensitive.push_back("FOCAL");
479 // mSensitiveHCAL.push_back("FOCAL");
480 // mSensitiveECALPad.push_back("FOCAL");
481 // mSensitiveECALPix.push_back("FOCAL");
482
483 // ECAL part
484 LOG(debug2) << "ECAL geometry : " << GetTitle();
486
487 // HCAL part
488 switch (mGeometry->getHCALDesign()) {
491 break;
492
495 break;
496
499 break;
500
501 default:
502 break;
503 }
504
505 // const float z0 = 1312.5; // center of barrel mother volume
506 TVirtualMC::GetMC()->Gspos("FOCAL", 1, "barrel", 0, 30., mGeometry->getFOCALZ0() - (mGeometry->getInsertFrontPadLayers() ? 2.0 : 0.0) + (mGeometry->getInsertHCalReadoutMaterial() ? 1.5 : 0.0), 0, "ONLY");
507}
508
510{
511 TGeoVolumeAssembly* volHCAL = new TGeoVolumeAssembly("HCAL");
512
513 TGeoVolumeAssembly* HcalTube = gGeoManager->MakeVolumeAssembly("ScintCuTubes");
514
515 TGeoVolume* volCuTube;
516 TGeoVolume* volSciFi;
517
518 float RScint = 0.;
519 float Rin = 0.;
520 float Rout = 0.;
521 float Length = 0.;
522
523 for (auto& icomp : mGeoCompositions) {
524 Length = icomp->sizeZ() / 2;
525
526 if (icomp->material() == "Pb") {
527 Rout = icomp->sizeX() / 2;
528 TGeoMedium* medium = gGeoManager->GetMedium(getMediumID(ID_PB));
529 volCuTube = gGeoManager->MakeTube("Tube", medium, Rin, Rout, Length); // The Scintillator must be first in order in vector for Rin to be set
530 volCuTube->SetLineWidth(2);
531 volCuTube->SetLineColor(kRed);
532 mSensitive.push_back(volCuTube->GetName());
533 // mSensitiveHCAL.push_back(volCuTube->GetName());
534 HcalTube->AddNode(volCuTube, 1, nullptr);
535 }
536 if (icomp->material() == "Scint") {
537 RScint = icomp->sizeX() / 2;
538 Rin = RScint + 0.005;
539 TGeoMedium* medium = gGeoManager->GetMedium(getMediumID(ID_SC));
540 volSciFi = gGeoManager->MakeTube("ScintFiber", medium, 0., RScint, Length);
541 volSciFi->SetLineWidth(2);
542 volSciFi->SetLineColor(kBlue);
543 // mSensitiveHCAL.push_back(volSciFi->GetName());
544 mSensitive.push_back(volSciFi->GetName());
545 HcalTube->AddNode(volSciFi, 1, nullptr);
546 }
547 if (icomp->material() == "CuHCAL") {
548 Rout = icomp->sizeX() / 2;
549 TGeoMedium* medium = gGeoManager->GetMedium(getMediumID(ID_COPPER));
550 volCuTube = gGeoManager->MakeTube("Tube", medium, Rin, Rout, Length); // The Scintillator must be first in order in vector for Rin to be set
551 volCuTube->SetLineWidth(2);
552 volCuTube->SetLineColor(kRed);
553 // mSensitiveHCAL.push_back(volCuTube->GetName());
554 mSensitive.push_back(volCuTube->GetName());
555 HcalTube->AddNode(volCuTube, 1, nullptr);
556 }
557 }
558
559 bool splitDet = mGeometry->getDetectorOpeningRight() > 0.0 || mGeometry->getDetectorOpeningLeft() > 0.0;
560
561 double TowerSize = mGeometry->getHCALTowerSize();
562 double CuBoxThickness = 0.3; // Thickness of the Cu box carrying capillary tubes
563
564 TGeoBBox* ODBox = new TGeoBBox("TowerOD", TowerSize / 2, TowerSize / 2, Length);
565 TGeoBBox* IDBox = new TGeoBBox("TowerID", (TowerSize - CuBoxThickness) / 2, (TowerSize - CuBoxThickness) / 2, Length + 0.01);
566 TGeoCompositeShape* TowerHCAL = new TGeoCompositeShape("TowerHCAL", "TowerOD - TowerID");
567 TGeoVolume* volTower = new TGeoVolume("volTower", TowerHCAL, gGeoManager->GetMedium(getMediumID(ID_COPPER)));
568 volTower->SetLineWidth(2);
569 volTower->SetLineColor(42);
570 // mSensitiveHCAL.push_back(volTower->GetName());
571 mSensitive.push_back(volTower->GetName());
572
573 TGeoVolumeAssembly* volTowerHCAL = new TGeoVolumeAssembly("volTowerHCAL");
574 volTowerHCAL->AddNode(volTower, 1, nullptr);
575
576 int Rows = 0;
577 float RowPos = 0.;
578 int Columns = 0;
579 int NumTubes = 1;
580
581 // Packing circles in Hexagonal shape
582 while (RowPos + CuBoxThickness / 2 + Rout + 2 * Rout < TowerSize) {
583 Columns = 0;
584 float ColumnPos = (Rows % 2 == 0) ? 0. : Rout;
585 while (ColumnPos + CuBoxThickness / 2 + Rout + 2 * Rout < TowerSize) {
586
587 TGeoTranslation* trans = new TGeoTranslation(ColumnPos - TowerSize / 2 + CuBoxThickness / 2 + Rout, RowPos - TowerSize / 2 + CuBoxThickness / 2 + Rout, 0.);
588
589 trans->SetName(Form("trans_Num_%d", NumTubes));
590 trans->RegisterYourself();
591
592 volTowerHCAL->AddNode(HcalTube, NumTubes, trans);
593 // volTowerHCAL->AddNode(volCuTube, NumTubes, trans);
594 // volTowerHCAL->AddNode(volSciFi, NumTubes, trans);
595
596 Columns++;
597 ColumnPos = Columns * 2 * Rout + ((Rows % 2 == 0) ? 0. : Rout);
598 NumTubes++;
599 }
600
601 Rows++;
602 RowPos = Rows * 2 * Rout * TMath::Sin(TMath::Pi() / 3);
603 }
604
605 // Define the distance from the beam pipe in which towers will ommitted
606 Double_t BeamPipeRadius = 3.0; // in cm To be changed later
607 Double_t TowerHalfDiag = TMath::Sqrt2() * 0.5 * TowerSize; // tower half diagonal
608 Double_t MinRadius = BeamPipeRadius + TowerSize / 2;
609
610 float SizeXHCAL = mGeometry->getHCALTowersInX() * TowerSize;
611 float SizeYHCAL = mGeometry->getHCALTowersInY() * TowerSize;
612
613 int nTowersX = mGeometry->getHCALTowersInX();
614 int nTowersY = mGeometry->getHCALTowersInY();
615
616 Rows = 0;
617 Columns = 0;
618 RowPos = 0.;
619 Int_t NumTowers = 1;
620
621 if (splitDet) {
622 SizeXHCAL = SizeXHCAL / 2;
623
624 TGeoVolumeAssembly* volHalfHCAL = new TGeoVolumeAssembly("HalfHCAL");
625
626 for (Rows = 0; Rows < nTowersY; Rows++) {
627
628 float ColumnPos = 0.;
629 RowPos = Rows * TowerSize;
630 for (Columns = 0; Columns < nTowersX / 2; Columns++) {
631 ColumnPos = Columns * TowerSize;
632 TGeoTranslation* trans = new TGeoTranslation(ColumnPos - SizeXHCAL / 2 + TowerSize / 2, RowPos - SizeYHCAL / 2 + TowerSize / 2, 0.);
633
634 // Shit the beampipe towers by TowerSize/2
635 if (Rows == nTowersY / 2) {
636 trans->SetDx(trans->GetTranslation()[0] + TowerSize / 2);
637 }
638
639 // Adding the Tower to the HCAL
640 volHalfHCAL->AddNode(volTowerHCAL, NumTowers, trans);
641
642 NumTowers++;
643 }
644 volHCAL->AddNode(volHalfHCAL, 1, new TGeoTranslation(SizeXHCAL / 2 + mGeometry->getDetectorOpeningRight(), 0, 0));
645 TGeoRotation* rotFlipZ = new TGeoRotation();
646 rotFlipZ->RotateY(180); // Flip around Y to reverse Z
647 TGeoCombiTrans* combHalf = new TGeoCombiTrans(-SizeXHCAL / 2 - mGeometry->getDetectorOpeningLeft(), 0., 0., rotFlipZ);
648 volHCAL->AddNode(volHalfHCAL, 2, combHalf);
649 }
650 } else {
651 for (Rows = 0; Rows < nTowersY; Rows++) {
652
653 float ColumnPos = 0.;
654 RowPos = Rows * TowerSize;
655 for (Columns = 0; Columns < nTowersX; Columns++) {
656 ColumnPos = Columns * TowerSize;
657 TGeoTranslation* trans = new TGeoTranslation(ColumnPos - SizeXHCAL / 2 + TowerSize / 2, RowPos - SizeYHCAL / 2 + TowerSize / 2, 0.);
658
659 // Remove the Towers that overlaps with the beam pipe
660 Double_t RadialDistance = TMath::Power(trans->GetTranslation()[0], 2) + TMath::Power(trans->GetTranslation()[1], 2);
661
662 if (RadialDistance < MinRadius * MinRadius || TMath::Abs(trans->GetTranslation()[0]) > SizeXHCAL / 2) {
663 continue;
664 }
665
666 // Adding the Tower to the HCAL
667 volHCAL->AddNode(volTowerHCAL, NumTowers, trans);
668
669 NumTowers++;
670 }
671 }
672 }
673
674 LOG(info) << "Number of Towers is: " << (NumTowers - 1);
675 LOG(info) << "Number of tubes is: " << (NumTubes - 1) * (NumTowers - 1);
676
677 // Create Aluminium plate at the back of HCal to simulate the electronics readout material
678 // Hardcoded thickness of 1cm and placement at 2 cm behind HCAL
679 TGeoBBox* alHcalBox = new TGeoBBox("AlHCalBox", SizeXHCAL / 2.0, SizeYHCAL / 2.0, 0.5 / 2.0);
680 TGeoVolume* volumeAlHcalBox = new TGeoVolume("volAlHcalBox", alHcalBox, gGeoManager->GetMedium(getMediumID(ID_ALUMINIUM)));
681 volumeAlHcalBox->SetLineColor(kOrange);
682 if (mGeometry->getInsertHCalReadoutMaterial()) {
683 TVirtualMC::GetMC()->Gspos("volAlHcalBox", 9999, "FOCAL", 0.0, 0.0, +1.0 * mGeometry->getFOCALSizeZ() / 2.0 + 1.0, 0, "ONLY");
684 // mSensitiveHCAL.push_back("volAlHcalBox");
685 mSensitive.push_back("volAlHcalBox");
686 }
687 TGeoBBox* alUnderBox = new TGeoBBox("AlUnderBox", SizeXHCAL / 2.0, 0.5, mGeometry->getFOCALSizeZ() / 2.0 + 1.5);
688 TGeoVolume* volumeAlUnderBox = new TGeoVolume("volAlUnderBox", alUnderBox, gGeoManager->GetMedium(getMediumID(ID_ALUMINIUM)));
689 volumeAlUnderBox->SetLineColor(kOrange);
690 if (mGeometry->getInsertHCalReadoutMaterial()) {
691 TVirtualMC::GetMC()->Gspos("volAlUnderBox", 9999, "FOCAL", 0.0, -1.0 * mGeometry->getFOCALSizeY() / 2 - 10.5, 0.0, 0, "ONLY");
692 // mSensitiveHCAL.push_back("volAlUnderBox");
693 mSensitive.push_back("volAlUnderBox");
694 }
695
696 volHCAL->SetVisibility();
697 volHCAL->SetVisDaughters();
698 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");
699}
700
701//_____________________________________________________________________________
702TGeoVolumeAssembly* Detector::CreatePitchAssembly(double Lx,
703 double Ly1,
704 double Ly2,
705 double Lz,
706 double hole_diameter,
707 double hole_spacing,
708 int nholes,
709 double fiber_radius,
710 std::string suffix)
711{
712
713 // Z-alignment doesn't change
714 double zpos = 0;
715
716 TGeoMedium* copper = gGeoManager->GetMedium(getMediumID(ID_COPPER));
717 TGeoMedium* scint = gGeoManager->GetMedium(getMediumID(ID_SC));
718
719 TGeoVolumeAssembly* pitchAssembly = new TGeoVolumeAssembly("pitchAssembly");
720
721 // Hardcoded values for hole placement, to be set from outside
722 float holeStart = 0.15; // cm
723 float holeEnd = 0.35; // cm
724
725 TGeoVolumeAssembly* volLowerSheetwHoles = new TGeoVolumeAssembly(Form("volLowerSheetwHoles_%s", suffix.c_str()));
726 TGeoVolume* cuSheet = gGeoManager->MakeBox("cuSheet", copper, Lx / 2, (Ly1 - fiber_radius * 2) / 2, Lz / 2);
727 cuSheet->SetLineColor(kOrange + 2);
728 mSensitive.push_back(cuSheet->GetName());
729 TGeoVolume* boxbegin = gGeoManager->MakeBox("BoxBegin", copper, holeStart / 2, fiber_radius, Lz / 2);
730 boxbegin->SetLineColor(kOrange + 2);
731 mSensitive.push_back(boxbegin->GetName());
732 TGeoVolume* boxMiddle = gGeoManager->MakeBox("BoxMiddle", copper, (hole_spacing - hole_diameter) / 2, fiber_radius, Lz / 2);
733 boxMiddle->SetLineColor(kOrange + 2);
734 mSensitive.push_back(boxMiddle->GetName());
735 TGeoVolume* boxEnd = gGeoManager->MakeBox("BoxEnd", copper, holeEnd / 2, fiber_radius, Lz / 2);
736 boxEnd->SetLineColor(kOrange + 2);
737 mSensitive.push_back(boxEnd->GetName());
738
739 double yPlacement = Ly1 / 2 - fiber_radius;
740
741 // -----------------
742 // Layer 1: Lower sheet with holes (y = 0)
743 // -----------------
744
745 volLowerSheetwHoles->AddNode(cuSheet, 0, new TGeoTranslation(0, -Ly1 / 2 + (Ly1 - fiber_radius * 2) / 2, zpos));
746
747 // Add holes starting at x = 1.5 mm
748 float start_x = -Lx / 2 + holeStart;
749
750 for (int ihole = 0; ihole < nholes; ++ihole) {
751 float holePlacement = start_x + ihole * hole_spacing + hole_diameter / 2;
752 if (ihole == 0) {
753 volLowerSheetwHoles->AddNode(boxbegin, ihole, new TGeoTranslation(holePlacement - holeStart / 2 - hole_diameter / 2, yPlacement, zpos));
754 volLowerSheetwHoles->AddNode(boxMiddle, ihole, new TGeoTranslation(holePlacement + hole_diameter / 2 + (hole_spacing - hole_diameter) / 2, yPlacement, zpos));
755 } else if (ihole == nholes - 1) {
756 if ((holePlacement + hole_diameter / 2 + holeStart) < Lx / 2 - 0.005) {
757 volLowerSheetwHoles->AddNode(boxEnd, ihole, new TGeoTranslation(holePlacement + hole_diameter / 2 + holeEnd / 2, yPlacement, zpos));
758 } else {
759 volLowerSheetwHoles->AddNode(boxbegin, ihole, new TGeoTranslation(holePlacement + hole_diameter / 2 + holeStart / 2, yPlacement, zpos));
760 }
761 } else {
762 volLowerSheetwHoles->AddNode(boxMiddle, ihole, new TGeoTranslation(holePlacement + hole_diameter / 2 + (hole_spacing - hole_diameter) / 2, yPlacement, zpos));
763 }
764 }
765
766 pitchAssembly->AddNode(volLowerSheetwHoles, 0, new TGeoTranslation(0, Ly1 / 2, zpos)); // Add Ly1 / 2 so the lower edge of the sheets start y=0
767
768 // -----------------
769 // Layer 2: Full copper sheet
770 // -----------------
771 TGeoVolume* fullSheet1 = gGeoManager->MakeBox("FullSheet1", copper, Lx / 2, Ly2 / 2, Lz / 2);
772 fullSheet1->SetLineColor(kOrange + 2);
773 mSensitive.push_back(fullSheet1->GetName());
774 pitchAssembly->AddNode(fullSheet1, 0, new TGeoTranslation(0, Ly1 / 2 + Ly2 / 2 + Ly1 / 2, zpos)); // Add Ly1 / 2 so the lower edge of the sheets start y=0
775
776 // -----------------
777 // Layer 3: Upper sheet with holes (shifted)
778 // -----------------
779
780 TGeoVolumeAssembly* volUpperSheetwHoles = new TGeoVolumeAssembly(Form("volUpperSheetwHoles_%s", suffix.c_str()));
781
782 volUpperSheetwHoles->AddNode(cuSheet, 0, new TGeoTranslation(0, -Ly1 / 2 + (Ly1 - fiber_radius * 2) / 2, zpos));
783
784 // Add holes starting at x = 3.5 mm
785 float start_x2 = -Lx / 2 + holeEnd;
786
787 for (int ihole = 0; ihole < nholes; ++ihole) {
788 float holePlacement = start_x2 + ihole * hole_spacing + hole_diameter / 2;
789 if (ihole == 0) {
790 volUpperSheetwHoles->AddNode(boxEnd, ihole, new TGeoTranslation(holePlacement - hole_diameter / 2 - holeEnd / 2, yPlacement, zpos));
791 volUpperSheetwHoles->AddNode(boxMiddle, ihole, new TGeoTranslation(holePlacement + hole_diameter / 2 + (hole_spacing - hole_diameter) / 2, yPlacement, zpos));
792 } else if (ihole == nholes - 1) {
793 volUpperSheetwHoles->AddNode(boxbegin, ihole, new TGeoTranslation(holePlacement + holeStart / 2 + hole_diameter / 2, yPlacement, zpos));
794 } else {
795 if ((holePlacement + hole_spacing + hole_diameter / 2) < Lx / 2 - 0.005) {
796 volUpperSheetwHoles->AddNode(boxMiddle, ihole, new TGeoTranslation(holePlacement + hole_diameter / 2 + (hole_spacing - hole_diameter) / 2, yPlacement, zpos));
797 } else {
798 volUpperSheetwHoles->AddNode(boxEnd, ihole, new TGeoTranslation(holePlacement + hole_diameter / 2 + holeEnd / 2, yPlacement, zpos));
799 break;
800 }
801 }
802 }
803
804 pitchAssembly->AddNode(volUpperSheetwHoles, 0, new TGeoTranslation(0, Ly1 / 2 + Ly2 + Ly1 / 2 + Ly1 / 2, zpos)); // Add Ly1 / 2 so the lower edge of the sheets start y=0
805
806 // -----------------
807 // Layer 4: Full copper sheet
808 // -----------------
809 pitchAssembly->AddNode(fullSheet1, 1, new TGeoTranslation(0, Ly1 / 2 + Ly2 + Ly1 + Ly2 / 2 + Ly1 / 2, zpos)); // Add Ly1 / 2 so the lower edge of the sheets start y=0
810
811 // -----------------
812 // Scintillator Fibers
813 // -----------------
814 // Lower set of fibers
815 TGeoVolume* fiber = gGeoManager->MakeTube("Fiber", scint, 0, fiber_radius, Lz / 2);
816 fiber->SetLineColor(kBlue);
817 mSensitive.push_back(fiber->GetName());
818 for (int i = 0; i < nholes; ++i) {
819 float x_fiber = start_x + i * hole_spacing + hole_diameter / 2;
820 pitchAssembly->AddNode(fiber, i, new TGeoTranslation(x_fiber, Ly1 / 2 - fiber_radius + Ly1 / 2, zpos));
821 }
822
823 // Upper set of fibers
824 for (int i = 0; i < nholes; ++i) {
825 float x_fiber = start_x2 + i * hole_spacing + hole_diameter / 2;
826 if (x_fiber > Lx / 2 - 0.05) {
827 break;
828 }
829 pitchAssembly->AddNode(fiber, i + nholes, new TGeoTranslation(x_fiber, Ly1 / 2 + Ly2 + Ly1 / 2 + Ly1 / 2 - fiber_radius + Ly1 / 2, zpos));
830 }
831
832 return pitchAssembly;
833}
834
835//_____________________________________________________________________________
837{
838 TGeoVolumeAssembly* volHCAL = new TGeoVolumeAssembly("HCAL");
839
840 // Dimensions
841 double Lx = 49.81; // cm
842 double Ly1 = 0.20; // cm (sheets with holes)
843 double Ly2 = 0.15; // cm (full sheets)
844 double Lz = 110.0; // cm
845
846 double fiber_radius = 0.05;
847
848 // HCal materials
849 int icomp = 0;
850 for (auto& comp : mGeoCompositions) {
851 Lz = comp->sizeZ();
852
853 if (comp->material() == "Scint") {
854 fiber_radius = comp->sizeX() / 2;
855 }
856 if (comp->material() == "CuHCAL" && icomp == 0) {
857 Lx = comp->sizeX();
858 Ly1 = comp->sizeY();
859 }
860 if (comp->material() == "CuHCAL" && icomp == 2) {
861 Ly2 = comp->sizeY();
862 }
863 icomp++;
864 }
865
866 double hole_diameter = fiber_radius * 2 + 0.01; // hole radius
867 double hole_spacing = mGeometry->getHCALPitchSize();
868 int nholes = (int)(Lx / hole_spacing); // Number of holes in one HCAL sheet
869
870 double beamPipeHole = mGeometry->getHCALBeamPipeHoleSize(); // cm The size of the beam pipe opening
871 int nBeamPipeHoles = (int)((Lx - beamPipeHole / 2) / hole_spacing); // Number of beam pipe holes
872
873 // Compute module height (two sheets with holes + two full sheets)
874 float pitch_height = Ly1 + Ly2 + Ly1 + Ly2;
875
876 int totalNumberOfPitches = mGeometry->getHCALTowersInY() * 2; // Number of pitches in the whole HCAL
877 int numberOfPitchesBeamPipe = (int)((beamPipeHole + 0.001) / pitch_height); // Number of pitches in the beam pipe region
878 int numberofPitchesOnYaxis = (totalNumberOfPitches - numberOfPitchesBeamPipe); // Number of pitches in the HCAL ouside the beam pipe region
879
880 TGeoVolumeAssembly* pitchAssembly = CreatePitchAssembly(Lx, Ly1, Ly2, Lz, hole_diameter, hole_spacing, nholes, fiber_radius, "Main");
881 pitchAssembly->SetVisibility(true);
882 TGeoVolumeAssembly* beamPipeAssembly = CreatePitchAssembly(Lx - beamPipeHole / 2, Ly1, Ly2, Lz, hole_diameter, hole_spacing, nBeamPipeHoles, fiber_radius, "BeamPipe");
883 beamPipeAssembly->SetVisibility(true);
884
885 TGeoVolumeAssembly* HalfHCAL = new TGeoVolumeAssembly("HalfHCAL");
886
887 for (int iPitch = 0; iPitch < numberofPitchesOnYaxis; iPitch++) {
888 float placement = iPitch * pitch_height - pitch_height * (totalNumberOfPitches) / 2.0;
889 if (placement < -beamPipeHole / 2.0) {
890 HalfHCAL->AddNode(pitchAssembly, iPitch, new TGeoTranslation(0, placement, 0.));
891 } else {
892 placement += beamPipeHole;
893 HalfHCAL->AddNode(pitchAssembly, iPitch, new TGeoTranslation(0, placement, 0.));
894 }
895 }
896
897 for (int iPitch = 0; iPitch < numberOfPitchesBeamPipe; iPitch++) {
898 float placement = iPitch * pitch_height - beamPipeHole / 2.0;
899 HalfHCAL->AddNode(beamPipeAssembly, iPitch, new TGeoTranslation(-beamPipeHole / 4, placement, 0.));
900 }
901
902 HalfHCAL->SetVisibility(true);
903 HalfHCAL->SetVisDaughters(true);
904
905 volHCAL->AddNode(HalfHCAL, 0, new TGeoTranslation(-Lx / 2, 0, 0.));
906 TGeoRotation* rotFlipZ = new TGeoRotation();
907 rotFlipZ->RotateY(180); // Flip around Y to reverse Z
908 TGeoCombiTrans* combHalf = new TGeoCombiTrans(Lx / 2, 0., 0., rotFlipZ);
909 volHCAL->AddNode(HalfHCAL, 1, combHalf);
910
911 gMC->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");
912}
913
914//_____________________________________________________________________________
916{
917 TGeoVolumeAssembly* volHCAL = new TGeoVolumeAssembly("HCAL");
918
920 Float_t pars[4]; // this is HMSC Assembly
921 pars[0] = mGeometry->getHCALTowerSize() / 2;
922 pars[1] = mGeometry->getHCALTowerSize() / 2;
923 pars[2] = mGeometry->getECALSizeZ() + mGeometry->getHCALSizeZ() / 2; // ECAL sizeZ is already added to the HCAL materials CenterZ, so it is also treated as offset
924 pars[3] = 0;
925
926 float offset = pars[2];
927
928 TGeoVolumeAssembly* volTower = new TGeoVolumeAssembly("Tower");
929
930 int iCu(0), iScint(0);
931 for (auto& icomp : mGeoCompositions) {
932
933 pars[0] = icomp->sizeX() / 2;
934 pars[1] = icomp->sizeY() / 2;
935 pars[2] = icomp->sizeZ() / 2;
936 pars[3] = 0;
937
938 // HCal materials
939
940 if (icomp->material() == "Pb") {
941 iCu++;
942 const TGeoMedium* medium = gGeoManager->GetMedium(getMediumID(ID_PB));
943 const TGeoBBox* HPadBox = new TGeoBBox("HPadBox", pars[0], pars[1], pars[2]);
944 TGeoVolume* HPad = new TGeoVolume("HPad", HPadBox, medium);
945 HPad->SetLineColor(kGray);
946 // mSensitiveHCAL.push_back(HPad->GetName());
947 mSensitive.push_back(HPad->GetName());
948 TGeoTranslation* trans = new TGeoTranslation(icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset);
949 volTower->AddNode(HPad, iCu, trans);
950 }
951 if (icomp->material() == "Scint") {
952 iScint++;
953 const TGeoMedium* medium = gGeoManager->GetMedium(getMediumID(ID_SC));
954 const TGeoBBox* HScintBox = new TGeoBBox("HScintBox", pars[0], pars[1], pars[2]);
955 TGeoVolume* HScint = new TGeoVolume("HScint", HScintBox, medium);
956 HScint->SetLineColor(kBlue);
957 // mSensitiveHCAL.push_back(HScint->GetName());
958 mSensitive.push_back(HScint->GetName());
959 TGeoTranslation* trans = new TGeoTranslation(icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset);
960 volTower->AddNode(HScint, iScint, trans);
961 }
962 if (icomp->material() == "CuHCAL") {
963 iCu++;
964 const TGeoMedium* medium = gGeoManager->GetMedium(getMediumID(ID_COPPER));
965 const TGeoBBox* HPadBox = new TGeoBBox("HPadBox", pars[0], pars[1], pars[2]);
966 TGeoVolume* HPad = new TGeoVolume("HPad", HPadBox, medium);
967 HPad->SetLineColor(kRed);
968 // mSensitiveHCAL.push_back(HPad->GetName());
969 mSensitive.push_back(HPad->GetName());
970 TGeoTranslation* trans = new TGeoTranslation(icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset);
971 volTower->AddNode(HPad, iCu, trans);
972 }
973 }
974 double TowerSize = mGeometry->getHCALTowerSize();
975
976 // Define the distance from the beam pipe in which towers will ommitted
977 double BeamPipeRadius = 3.6; // in cm
978 double TowerHalfDiag = TMath::Sqrt2() * 0.5 * TowerSize; // tower half diagonal
979 double MinRadius = BeamPipeRadius + TowerHalfDiag;
980
981 float SizeXHCAL = mGeometry->getHCALTowersInX() * TowerSize;
982 float SizeYHCAL = mGeometry->getHCALTowersInY() * TowerSize;
983
984 int nTowersX = mGeometry->getHCALTowersInX();
985 int nTowersY = mGeometry->getHCALTowersInY();
986
987 int Rows = 0;
988 int Columns = 0;
989 double RowPos = 0.;
990 int NumTowers = 1;
991
992 // Arranging towers
993 for (Rows = 0; Rows < nTowersY; Rows++) {
994 Columns = 0;
995 float ColumnPos = 0.;
996 RowPos = Rows * TowerSize;
997 for (Columns = 0; Columns < nTowersX; Columns++) {
998 ColumnPos = Columns * TowerSize;
999
1000 TGeoTranslation* trans = new TGeoTranslation(ColumnPos - SizeXHCAL / 2 + TowerSize / 2, RowPos - SizeYHCAL / 2 + TowerSize / 2, 0.);
1001
1002 // Remove the Towers that overlaps with the beam pipe
1003 double RadialDistance = TMath::Power(ColumnPos - SizeXHCAL / 2 + TowerSize / 2, 2) + TMath::Power(RowPos - SizeYHCAL / 2 + TowerSize / 2, 2);
1004
1005 if (RadialDistance < MinRadius * MinRadius) {
1006 continue;
1007 }
1008
1009 // Adding the Tower to the HCAL
1010 volHCAL->AddNode(volTower, NumTowers, trans);
1011
1012 NumTowers++;
1013 }
1014 }
1015 LOG(info) << "Number of Towers is: " << (NumTowers - 1);
1016
1017 // Create an Aluminium plate at the back of HCal to simulate the electronics readout material
1018 // Hardcoded thickness of 1cm and placement at 2 cm behind HCAL
1019 TGeoBBox* alHcalBox = new TGeoBBox("AlHCalBox", SizeXHCAL / 2.0, SizeYHCAL / 2.0, 0.5 / 2.0);
1020 TGeoVolume* volumeAlHcalBox = new TGeoVolume("volAlHcalBox", alHcalBox, gGeoManager->GetMedium(getMediumID(ID_ALUMINIUM)));
1021 volumeAlHcalBox->SetLineColor(kOrange);
1022 if (mGeometry->getInsertHCalReadoutMaterial()) {
1023 TVirtualMC::GetMC()->Gspos("volAlHcalBox", 9999, "FOCAL", 0.0, 0.0, +1.0 * mGeometry->getFOCALSizeZ() / 2.0 + 1.0, 0, "ONLY");
1024 }
1025 TGeoBBox* alUnderBox = new TGeoBBox("AlUnderBox", SizeXHCAL / 2.0, 0.5, mGeometry->getFOCALSizeZ() / 2.0 + 1.5);
1026 TGeoVolume* volumeAlUnderBox = new TGeoVolume("volAlUnderBox", alUnderBox, gGeoManager->GetMedium(getMediumID(ID_ALUMINIUM)));
1027 volumeAlUnderBox->SetLineColor(kOrange);
1028 if (mGeometry->getInsertHCalReadoutMaterial()) {
1029 TVirtualMC::GetMC()->Gspos("volAlUnderBox", 9999, "FOCAL", 0.0, -1.0 * mGeometry->getFOCALSizeY() / 2 - 10.5, 0.0, 0, "ONLY");
1030 }
1031
1032 TGeoVolume* volFOCAL = gGeoManager->GetVolume("FOCAL");
1033 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
1034}
1035
1036//_____________________________________________________________________________
1038{
1039 // using boost::algorithm::contains; // only when string operations
1040 Geometry* geom = getGeometry();
1041
1042 // Int_t *idtmed = fIdtmed->GetArray() - 3599; //599 -> 3599
1043
1047
1049 double pars[4]; // this is EMSC Assembly
1050 pars[0] = geom->getTowerSizeX() / 2. + geom->getTowerGapSizeX() / 2.;
1051 pars[1] = geom->getTowerSizeY() / 2. + geom->getTowerGapSizeY() / 2.;
1052 // pars[2] = mGeometry->GetFOCALSizeZ() / 2;
1053 pars[2] = geom->getECALSizeZ() / 2;
1054 pars[3] = 0;
1055 // this shifts all the pixel layers to the center near the beampipe
1056 double pixshift = geom->getTowerSizeX() - (geom->getGlobalPixelWaferSizeX() * geom->getNumberOfPIXsInX());
1057
1058 bool splitDet = mGeometry->getDetectorOpeningRight() > 0.0 || mGeometry->getDetectorOpeningLeft() > 0.0;
1059
1060 float offset = pars[2];
1061 // gMC->Gsvolu("EMSC1", "BOX", idtmed[3698], pars, 4);//Left towers (pixels shifted right)
1062 // gMC->Gsvolu("EMSC2", "BOX", idtmed[3698], pars, 4);//Right towers (pixels shifted left)
1063
1064 TVirtualMC::GetMC()->Gsvolu("EMSC1", "BOX", getMediumID(ID_AIR), pars, 4); // Left towers (pixels shifted right)
1065 TVirtualMC::GetMC()->Gsvolu("EMSC2", "BOX", getMediumID(ID_AIR), pars, 4); // Right towers (pixels shifted left)
1066 // mSensitiveECALPad.push_back("EMSC1");
1067 // mSensitiveECALPad.push_back("EMSC2");
1068 mSensitive.push_back("EMSC1");
1069 mSensitive.push_back("EMSC2");
1070
1071 // const Composition *icomp = new Composition(); //to be removed
1072 // for(int i = 0; i < 20; i++){ // old
1073 // icomp = geom->getComposition(i, 0); // obsolete
1074
1075 // loop over geometry composition elements
1076 for (auto& icomp : mGeoCompositions) {
1077
1078 pars[0] = icomp->sizeX() / 2.;
1079 pars[1] = icomp->sizeY() / 2.;
1080 pars[2] = icomp->sizeZ() / 2.;
1081 pars[3] = 0;
1082
1083 if (icomp->material() == "PureW") {
1084 // TVirtualMC::GetMC()->Gsvolu("EW1", "BOX", idtmed[3599], pars, 4);
1085 TVirtualMC::GetMC()->Gsvolu("EW1", "BOX", getMediumID(ID_TUNGSTEN), pars, 4);
1086 // mSensitiveECALPad.push_back("EW1");
1087 mSensitive.push_back("EW1");
1088 gGeoManager->GetVolume("EW1")->SetLineColor(kBlue);
1089 TVirtualMC::GetMC()->Gspos("EW1", icomp->id() + 1, "EMSC1",
1090 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1091 TVirtualMC::GetMC()->Gspos("EW1", icomp->id() + 1, "EMSC2",
1092 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1093 }
1094 if (icomp->material() == "Alloy") {
1095 // TVirtualMC::GetMC()->Gsvolu("EW1", "BOX", idtmed[3604], pars, 4);
1096 TVirtualMC::GetMC()->Gsvolu("EW1", "BOX", getMediumID(ID_ALLOY), pars, 4);
1097 // mSensitiveECALPad.push_back("EW1");
1098 mSensitive.push_back("EW1");
1099 TVirtualMC::GetMC()->Gspos("EW1", icomp->id() + 1, "EMSC1",
1100 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1101 TVirtualMC::GetMC()->Gspos("EW1", icomp->id() + 1, "EMSC2",
1102 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1103 }
1104
1105 if (icomp->material() == "G10") {
1106 // TVirtualMC::GetMC()->Gsvolu("G10RO1", "BOX", idtmed[3601], pars, 4);
1107 TVirtualMC::GetMC()->Gsvolu("G10RO1", "BOX", getMediumID(ID_G10), pars, 4);
1108 // mSensitiveECALPad.push_back("G10RO1");
1109 mSensitive.push_back("G10RO1");
1110 gGeoManager->GetVolume("G10RO1")->SetLineColor(kGreen);
1111 TVirtualMC::GetMC()->Gspos("G10RO1", icomp->id() + 1, "EMSC1",
1112 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1113 TVirtualMC::GetMC()->Gspos("G10RO1", icomp->id() + 1, "EMSC2",
1114 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1115 }
1116
1117 if (icomp->material() == "Cu") {
1118 // TVirtualMC::GetMC()->Gsvolu("EWCU", "BOX", idtmed[3602], pars, 4);
1119 TVirtualMC::GetMC()->Gsvolu("EWCU", "BOX", getMediumID(ID_COPPER), pars, 4);
1120 // mSensitiveECALPad.push_back("EWCU");
1121 mSensitive.push_back("EWCU");
1122 gGeoManager->GetVolume("EWCU")->SetLineColor(kViolet);
1123 TVirtualMC::GetMC()->Gspos("EWCU", icomp->id() + 1, "EMSC1",
1124 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1125 TVirtualMC::GetMC()->Gspos("EWCU", icomp->id() + 1, "EMSC2",
1126 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1127 }
1128
1129 if (icomp->material() == "Air") {
1130 // TVirtualMC::GetMC()->Gsvolu("EWAIR1", "BOX", idtmed[3698], pars, 4);
1131 TVirtualMC::GetMC()->Gsvolu("EWAIR1", "BOX", getMediumID(ID_AIR), pars, 4);
1132 // mSensitiveECALPad.push_back("EWAIR1");
1133 mSensitive.push_back("EWAIR1");
1134 gGeoManager->GetVolume("EWAIR1")->SetLineColor(kGray);
1135 TVirtualMC::GetMC()->Gspos("EWAIR1", icomp->id() + 1, "EMSC1",
1136 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1137 TVirtualMC::GetMC()->Gspos("EWAIR1", icomp->id() + 1, "EMSC2",
1138 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1139 }
1140
1141 if (icomp->material() == "Ceramic") {
1142 // TVirtualMC::GetMC()->Gsvolu("EWAIR1", "BOX", idtmed[3607], pars, 4);
1143 TVirtualMC::GetMC()->Gsvolu("EWAIR1", "BOX", getMediumID(ID_CERAMIC), pars, 4);
1144 // mSensitiveECALPad.push_back("EWAIR1");
1145 mSensitive.push_back("EWAIR1");
1146 TVirtualMC::GetMC()->Gspos("EWAIR1", icomp->id() + 1, "EMSC1",
1147 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1148 TVirtualMC::GetMC()->Gspos("EWAIR1", icomp->id() + 1, "EMSC2",
1149 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1150 }
1151
1152 if (icomp->material() == "SiPad") {
1153 // TVirtualMC::GetMC()->Gsvolu("EWSIPAD1", "BOX", idtmed[3600], pars, 4);
1154 TVirtualMC::GetMC()->Gsvolu("EWSIPAD1", "BOX", getMediumID(ID_SIPAD), pars, 4);
1155 // mSensitiveECALPad.push_back("EWSIPAD1");
1156 mSensitive.push_back("EWSIPAD1");
1157 gGeoManager->GetVolume("EWSIPAD1")->SetLineColor(kOrange - 7);
1158 int number = (icomp->id()) + (icomp->stack() << 12) + (icomp->layer() << 16);
1159 // cout<<" pad : "<< icomp->material()<<" "<<number<<" x: "<< pars[0] << " y: " << pars[1] <<" Z coord: " << icomp->centerZ()-offset <<endl;
1160 TVirtualMC::GetMC()->Gspos("EWSIPAD1", number + 1, "EMSC1",
1161 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1162 TVirtualMC::GetMC()->Gspos("EWSIPAD1", number + 1, "EMSC2",
1163 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1164 }
1165
1166 // Pixels (sensitive layer)
1167 if (icomp->material() == "SiPix") {
1168 // TVirtualMC::GetMC()->Gsvolu("EWSIPIX1", "BOX", idtmed[3600], pars, 4);
1169 TVirtualMC::GetMC()->Gsvolu("EWSIPIX1", "BOX", getMediumID(ID_SIPIX), pars, 4);
1170 // mSensitiveECALPix.push_back("EWSIPIX1");
1171 mSensitive.push_back("EWSIPIX1");
1172 gGeoManager->GetVolume("EWSIPIX1")->SetLineColor(kPink);
1173
1174 int number = (icomp->id()) + (icomp->stack() << 12) + (icomp->layer() << 16);
1175 TVirtualMC::GetMC()->Gspos("EWSIPIX1", number + 1, "EMSC1",
1176 icomp->centerX() - geom->getGlobalPixelOffsetX() + pixshift, icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1177 TVirtualMC::GetMC()->Gspos("EWSIPIX1", number + 1, "EMSC2",
1178 icomp->centerX() + geom->getGlobalPixelOffsetX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1179 }
1180
1181 // Passive silicon
1182 if (icomp->material() == "Si") {
1183 // TVirtualMC::GetMC()->Gsvolu("EWSI1", "BOX", idtmed[3610], pars, 4);
1184 TVirtualMC::GetMC()->Gsvolu("EWSI1", "BOX", getMediumID(ID_SIINSENS), pars, 4);
1185 // mSensitiveECALPix.push_back("EWSI1");
1186 mSensitive.push_back("EWSI1");
1187 gGeoManager->GetVolume("EWSI1")->SetLineColor(kPink);
1188 TVirtualMC::GetMC()->Gspos("EWSI1", icomp->id() + 1, "EMSC1",
1189 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1190 TVirtualMC::GetMC()->Gspos("EWSI1", icomp->id() + 1, "EMSC2",
1191 icomp->centerX(), icomp->centerY(), icomp->centerZ() - offset, 0, "ONLY");
1192 }
1193 } // end of loop over composition elements
1194
1195 // Add the coldplates to each of the left and right towers
1196 TGeoBBox* coldPlateBox = new TGeoBBox("ColdPlateBox", geom->getTowerSizeX() / 2.0, geom->getTowerGapSizeY() / 2.0, geom->getECALSizeZ() / 2.0);
1197 TGeoVolume* volumeColdPlate = nullptr;
1198
1199 if (geom->getTowerGapMaterial() == "Cu") { // Copper
1200 // if (contains(geom->getTowerGapMaterial(), "Cu")) { // Copper
1201 volumeColdPlate = new TGeoVolume("volColdPlate", coldPlateBox, gGeoManager->GetMedium(getMediumID(ID_COPPER)));
1202 } else if (geom->getTowerGapMaterial() == "Al") { // Aluminium
1203 // else if (contains(geom->getTowerGapMaterial(), "Al")) { // Aluminium
1204 volumeColdPlate = new TGeoVolume("volColdPlate", coldPlateBox, gGeoManager->GetMedium(getMediumID(ID_ALUMINIUM)));
1205 } else {
1206 volumeColdPlate = new TGeoVolume("volColdPlate", coldPlateBox, gGeoManager->GetMedium(getMediumID(ID_AIR)));
1207 }
1208 // mSensitiveECALPad.push_back(volumeColdPlate->GetName());
1209 mSensitive.push_back(volumeColdPlate->GetName());
1210 volumeColdPlate->SetLineColor(kOrange);
1211 TVirtualMC::GetMC()->Gspos("volColdPlate", 1, "EMSC1", 0.0, geom->getTowerSizeY() / 2.0 + geom->getTowerGapSizeY() / 2.0, 0.0, 0, "ONLY");
1212 TVirtualMC::GetMC()->Gspos("volColdPlate", 1, "EMSC2", 0.0, geom->getTowerSizeY() / 2.0 + geom->getTowerGapSizeY() / 2.0, 0.0, 0, "ONLY");
1213
1214 // Place the towers in the ECAL
1215 // --- Place the ECAL in FOCAL
1216 float fcal_pars[4];
1217 fcal_pars[0] = (geom->getFOCALSizeX() + 2. * geom->getMiddleTowerOffset() + mGeometry->getDetectorOpeningRight() + mGeometry->getDetectorOpeningLeft()) / 2.;
1218 fcal_pars[1] = geom->getFOCALSizeY() / 2.;
1219 fcal_pars[2] = geom->getECALSizeZ() / 2.;
1220 fcal_pars[3] = 0.;
1221
1222 // TVirtualMC::GetMC()->Gsvolu("ECAL", "BOX", idtmed[3698], fcal_pars, 4);
1223 TVirtualMC::GetMC()->Gsvolu("ECAL", "BOX", getMediumID(ID_AIR), fcal_pars, 4);
1224 // mSensitiveECALPad.push_back("ECAL");
1225 mSensitive.push_back("ECAL");
1226
1227 // Create SiPad box for the two sensitive layers to be placed in front of ECAL
1228 TGeoBBox* siPadBox = new TGeoBBox("SiPadBox", geom->getTowerSizeX() / 2. + geom->getTowerGapSizeX() / 2.,
1229 geom->getTowerSizeY() / 2. + geom->getTowerGapSizeY() / 2., 0.03 / 2.0);
1230 TGeoVolume* volumeSiPad = new TGeoVolume("volSiPad", siPadBox, gGeoManager->GetMedium(getMediumID(ID_SIPAD)));
1231 volumeSiPad->SetLineColor(kOrange + 7);
1232 // mSensitiveECALPad.push_back(volumeSiPad->GetName());
1233 if (geom->getInsertFrontPadLayers()) {
1234 mSensitive.push_back(volumeSiPad->GetName());
1235 }
1236
1237 double xp, yp, zp;
1238 int itowerx, itowery;
1239 // int number = i + j * geom->getNumberOfTowersInX();
1240 for (int number = 0; number < geom->getNumberOfTowersInX() * geom->getNumberOfTowersInY(); number++) {
1241 itowerx = number % geom->getNumberOfTowersInX();
1242 itowery = number / geom->getNumberOfTowersInX();
1243 // const auto towerCenter = geom->getGeoTowerCenter(number); //only ECAL part, second parameter = -1 by default
1244 // xp = std::get<0>towerCenter;
1245 // std::tie(xp, yp, zp) = geom->getGeoTowerCenter(number);
1246 auto [xp, yp, zp] = geom->getGeoTowerCenter(number); // only ECAL part, second parameter = -1 by default
1247
1248 if (itowerx == 0) {
1249 if (splitDet) {
1250 xp -= geom->getDetectorOpeningLeft();
1251 }
1252
1253 TVirtualMC::GetMC()->Gspos("EMSC1", number + 1, "ECAL", xp, yp, 0, 0, "ONLY");
1254 // Add the SiPad front volumes directly under the FOCAL volume
1255 if (geom->getInsertFrontPadLayers()) {
1256 TVirtualMC::GetMC()->Gspos("volSiPad", -1 * (number + 1), "FOCAL", xp, yp, -1.0 * geom->getFOCALSizeZ() / 2.0, 0, "ONLY");
1257 // mSensitiveECALPad.push_back("volSiPad");
1258 mSensitive.push_back("volSiPad");
1259 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");
1260 // mSensitiveECALPad.push_back("volSiPad");
1261 mSensitive.push_back("volSiPad");
1262 }
1263 }
1264 if (itowerx == 1) {
1265 if (splitDet) {
1266 xp += geom->getDetectorOpeningRight();
1267 }
1268
1269 TVirtualMC::GetMC()->Gspos("EMSC2", number + 1, "ECAL", xp, yp, 0, 0, "ONLY");
1270 // Add the SiPad front volumes directly under the FOCAL volume
1271 if (geom->getInsertFrontPadLayers()) {
1272 TVirtualMC::GetMC()->Gspos("volSiPad", -1 * (number + 1), "FOCAL", xp, yp, -1.0 * geom->getFOCALSizeZ() / 2.0, 0, "ONLY");
1273 // mSensitiveECALPad.push_back("volSiPad");
1274 mSensitive.push_back("volSiPad");
1275 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");
1276 // mSensitiveECALPad.push_back("volSiPad");
1277 mSensitive.push_back("volSiPad");
1278 }
1279 }
1280 } // end of loop over ECAL towers (TowersInX x TowersInY)
1281
1282 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");
1283}
1284
1286{
1287 mCurrentPrimaryID = fMC->GetStack()->GetCurrentTrackNumber();
1288 LOG(debug) << "Starting primary " << mCurrentPrimaryID << " with energy " << fMC->GetStack()->GetCurrentTrack()->Energy();
1289}
1290
1292{
1293 LOG(debug) << "Finishing primary " << mCurrentPrimaryID;
1294 // Resetting primary and parent ID
1295 mCurrentPrimaryID = -1;
1296}
1297
1299{
1300 LOG(debug) << "We are in sensitive volume " << v->GetName() << ": " << TVirtualMC::GetMC()->CurrentVolPath();
1301
1302 double eloss = TVirtualMC::GetMC()->Edep() * 1e9; // energy in eV (GeV->eV)
1303 if (eloss < DBL_EPSILON) {
1304 return false; // only process hits which actually deposit some energy in the FOCAL
1305 }
1306
1307 // In case of new parent track create new track reference
1308 auto o2stack = static_cast<o2::data::Stack*>(TVirtualMC::GetMC()->GetStack());
1309 if (!mCurrentSuperparent->mHasTrackReference) {
1310 float x, y, z, px, py, pz, e;
1311 TVirtualMC::GetMC()->TrackPosition(x, y, z);
1312 TVirtualMC::GetMC()->TrackMomentum(px, py, pz, e);
1313 o2::TrackReference trackref(x, y, z, px, py, pz, TVirtualMC::GetMC()->TrackLength(), TVirtualMC::GetMC()->TrackTime(), mCurrentParentID, GetDetId());
1314 o2stack->addTrackReference(trackref);
1315 mCurrentSuperparent->mHasTrackReference = true;
1316 }
1317
1318 float posX, posY, posZ;
1319 TVirtualMC::GetMC()->TrackPosition(posX, posY, posZ);
1320
1321 auto [indetector, col, row, layer, segment] = mGeometry->getVirtualInfo(posX, posY, posZ);
1322
1323 if (!indetector) {
1324 // particle outside the detector
1325 return true;
1326 }
1327
1328 auto currenthit = FindHit(mCurrentParentID, col, row, layer);
1329 if (!currenthit) {
1330 // Condition for new hit:
1331 // - Processing different partent track (parent track must be produced outside FOCAL)
1332 // - Inside different cell
1333 // - First track of the event
1334 Double_t time = TVirtualMC::GetMC()->TrackTime() * 1e9; // time in ns
1335 LOG(debug3) << "Adding new hit for parent " << mCurrentParentID << " and cell Col: " << col << " Row: " << row << " segment: " << segment;
1336
1338 AddHit(mCurrentParentID, mCurrentPrimaryID, mCurrentSuperparent->mEnergy, row * col + col, o2::focal::Hit::Subsystem_t::EPADS, math_utils::Point3D<float>(posX, posY, posZ), time, eloss);
1339 o2stack->addHit(GetDetId());
1340 } else {
1341 LOG(debug3) << "Adding energy to the current hit";
1342 currenthit->SetEnergyLoss(currenthit->GetEnergyLoss() + eloss);
1343 o2stack->modifiesHit(GetDetId());
1344 }
1345 return true;
1346}
1347
1349{
1350 LOG(debug) << "We are in sensitive volume " << v->GetName() << ": " << fMC->CurrentVolPath();
1351
1352 double eloss = fMC->Edep() * 1e9; // energy in eV (GeV->eV)
1353 if (eloss < DBL_EPSILON) {
1354 return false; // only process hits which actually deposit some energy in the FOCAL
1355 }
1356
1357 // In case of new parent track create new track reference
1358 auto o2stack = static_cast<o2::data::Stack*>(fMC->GetStack());
1359 if (!mCurrentSuperparent->mHasTrackReference) {
1360 float x, y, z, px, py, pz, e;
1361 fMC->TrackPosition(x, y, z);
1362 fMC->TrackMomentum(px, py, pz, e);
1363 o2::TrackReference trackref(x, y, z, px, py, pz, fMC->TrackLength(), fMC->TrackTime(), mCurrentParentID, GetDetId());
1364 o2stack->addTrackReference(trackref);
1365 mCurrentSuperparent->mHasTrackReference = true;
1366 }
1367
1368 float posX, posY, posZ;
1369 fMC->TrackPosition(posX, posY, posZ);
1370
1371 auto [indetector, col, row, layer, segment] = mGeometry->getVirtualInfo(posX, posY, posZ);
1372
1373 if (!indetector) {
1374 // particle outside the detector
1375 return true;
1376 }
1377
1378 auto currenthit = FindHit(mCurrentParentID, col, row, layer);
1379 if (!currenthit) {
1380 // Condition for new hit:
1381 // - Processing different partent track (parent track must be produced outside FOCAL)
1382 // - Inside different cell
1383 // - First track of the event
1384 Double_t time = fMC->TrackTime() * 1e9; // time in ns
1385 LOG(debug3) << "Adding new hit for parent " << mCurrentParentID << " and cell Col: " << col << " Row: " << row << " segment: " << segment;
1386
1388 AddHit(mCurrentParentID, mCurrentPrimaryID, mCurrentSuperparent->mEnergy, row * col + col, o2::focal::Hit::Subsystem_t::HCAL, math_utils::Point3D<float>(posX, posY, posZ), time, eloss);
1389 o2stack->addHit(GetDetId());
1390 } else {
1391 LOG(debug3) << "Adding energy to the current hit";
1392 currenthit->SetEnergyLoss(currenthit->GetEnergyLoss() + eloss);
1393 o2stack->modifiesHit(GetDetId());
1394 }
1395 return true;
1396}
1397
1399{
1400 LOG(debug) << "We are in sensitive volume " << v->GetName() << ": " << fMC->CurrentVolPath();
1401
1402 double eloss = fMC->Edep() * 1e9; // energy in eV (GeV->eV)
1403 if (eloss < DBL_EPSILON) {
1404 return false; // only process hits which actually deposit some energy in the FOCAL
1405 }
1406
1407 // In case of new parent track create new track reference
1408 auto o2stack = static_cast<o2::data::Stack*>(fMC->GetStack());
1409 if (!mCurrentSuperparent->mHasTrackReference) {
1410 float x, y, z, px, py, pz, e;
1411 fMC->TrackPosition(x, y, z);
1412 fMC->TrackMomentum(px, py, pz, e);
1413 o2::TrackReference trackref(x, y, z, px, py, pz, fMC->TrackLength(), fMC->TrackTime(), mCurrentParentID, GetDetId());
1414 o2stack->addTrackReference(trackref);
1415 mCurrentSuperparent->mHasTrackReference = true;
1416 }
1417
1418 float posX, posY, posZ;
1419 fMC->TrackPosition(posX, posY, posZ);
1420
1421 auto [indetector, col, row, layer, segment] = mGeometry->getVirtualInfo(posX, posY, posZ);
1422
1423 if (!indetector) {
1424 // particle outside the detector
1425 return true;
1426 }
1427
1428 auto currenthit = FindHit(mCurrentParentID, col, row, layer);
1429 if (!currenthit) {
1430 // Condition for new hit:
1431 // - Processing different partent track (parent track must be produced outside FOCAL)
1432 // - Inside different cell
1433 // - First track of the event
1434 Double_t time = fMC->TrackTime() * 1e9; // time in ns
1435 LOG(debug3) << "Adding new hit for parent " << mCurrentParentID << " and cell Col: " << col << " Row: " << row << " segment: " << segment;
1436
1438 AddHit(mCurrentParentID, mCurrentPrimaryID, mCurrentSuperparent->mEnergy, row * col + col, o2::focal::Hit::Subsystem_t::EPIXELS, math_utils::Point3D<float>(posX, posY, posZ), time, eloss);
1439 o2stack->addHit(GetDetId());
1440 } else {
1441 LOG(debug3) << "Adding energy to the current hit";
1442 currenthit->SetEnergyLoss(currenthit->GetEnergyLoss() + eloss);
1443 o2stack->modifiesHit(GetDetId());
1444 }
1445 return true;
1446}
Definition of the Stack class.
std::ostringstream debug
int16_t time
Definition RawEventData.h:4
unsigned char uint8_t
int32_t i
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char e
char error[CURL_ERROR_SIZE]
uint16_t pos
Definition RawData.h:3
uint32_t col
Definition RawData.h:4
Int_t GetDetId()
TVirtualMC * fMC
flag for initialisation
Definition FairModule.h:160
void RegisterAny(const char *name, T *&obj, Bool_t toFile)
static FairRootManager * Instance()
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:136
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:151
FOCAL detector simulation.
Definition Detector.h:55
bool ProcessHitsEPad(FairVolume *v=nullptr)
Processing hit creation in the ECAL Pad sensitive volume.
TGeoVolumeAssembly * CreatePitchAssembly(double Lx=498.1, double Ly1=2.0, double Ly2=1.5, double Lz=1100.0, double hole_diameter=1.1, double hole_spacing=4.0, int nholes=124, double fiber_radius=0.5, std::string suffix="")
Definition Detector.cxx:702
void addAlignableVolumesHCAL() const
Definition Detector.cxx:412
~Detector() override
Destructor.
Definition Detector.cxx:70
void InitializeO2Detector() override
Initializing detector.
Definition Detector.cxx:86
bool ProcessHitsHCAL(FairVolume *v=nullptr)
Processing hit creation in the HCAL sensitive volume.
virtual void CreateHCALSandwich()
Definition Detector.cxx:915
void Register() override
register container with hits
Definition Detector.cxx:202
virtual void CreateHCALSheets()
Definition Detector.cxx:836
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:168
void FinishPrimary() override
Finish current primary.
virtual void CreateHCALSpaghetti()
Definition Detector.cxx:509
void ConstructGeometry() override
Definition Detector.cxx:433
void addAlignableVolumesECAL() const
Definition Detector.cxx:423
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:400
void CreateMaterials()
Creating detector materials for the FOCAL detector.
Definition Detector.cxx:221
Hit * FindHit(int parentID, int col, int row, int layer)
Try to find hit with same cell and parent track ID.
Definition Detector.cxx:181
Bool_t ProcessHits(FairVolume *v=nullptr) final
Processing hit creation in the FOCAL sensitive volume.
Definition Detector.cxx:113
void EndOfEvent() final
Steps to be carried out at the end of the event.
Definition Detector.cxx:200
void BeginPrimary() override
Begin primaray.
void CreateECALGeometry()
Generate ECAL geometry.
Detector()=default
Dummy constructor.
Parent * AddSuperparent(int trackID, int pdg, double energy)
Add new superparent to the container.
Definition Detector.cxx:193
void Reset() final
Clean point collection.
Definition Detector.cxx:207
Geometry * getGeometry(std::string name="")
Get the FOCAL geometry desciption.
Definition Detector.cxx:75
double getTowerGapSizeY() const
Definition Geometry.h:133
double getFOCALSizeY() const
Definition Geometry.cxx:860
float getDetectorOpeningRight() const
Definition Geometry.h:146
int getNumberOfTowersInX() const
Definition Geometry.h:129
bool getInsertFrontPadLayers() const
Definition Geometry.h:141
HCALDesgin getHCALDesign() const
Definition Geometry.h:169
bool getInsertHCalReadoutMaterial() const
Definition Geometry.h:142
double getTowerGapSizeX() const
Definition Geometry.h:132
double getHCALSizeZ() const
Definition Geometry.cxx:899
int getNumberOfTowersInY() const
Definition Geometry.h:130
float getDetectorOpeningLeft() const
Definition Geometry.h:147
double getECALSizeZ() const
Definition Geometry.cxx:878
int getHCALTowersInY() const
Definition Geometry.h:109
float getHCALPitchSize() const
Definition Geometry.h:143
std::tuple< bool, int, int, int, int > getVirtualInfo(double x, double y, double z) const
double getGlobalPixelWaferSizeX() const
Definition Geometry.h:135
double getFOCALSizeZ() const
Definition Geometry.cxx:866
float getHCALTowerSize() const
Definition Geometry.h:107
static Geometry * getInstance()
Definition Geometry.cxx:41
int getHCALTowersInX() const
Definition Geometry.h:108
double getHCALCenterZ() const
Definition Geometry.cxx:910
std::tuple< double, double, double > getGeoTowerCenter(int tower, int segment=-1) const
this gives global position of the center of tower
Definition Geometry.cxx:694
double getTowerSizeX() const
Definition Geometry.cxx:840
std::vector< const Composition * > getFOCALMicroModule(int layer) const
Definition Geometry.cxx:673
std::string_view getTowerGapMaterial() const
Definition Geometry.h:151
float getHCALBeamPipeHoleSize() const
Definition Geometry.h:144
double getFOCALZ0() const
Definition Geometry.h:128
float getMiddleTowerOffset() const
Definition Geometry.h:140
double getFOCALSizeX() const
Definition Geometry.cxx:854
double getTowerSizeY() const
Definition Geometry.cxx:847
int getNumberOfPIXsInX() const
Definition Geometry.h:105
double getECALCenterZ() const
Definition Geometry.cxx:890
double getGlobalPixelOffsetX() const
Definition Geometry.h:138
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:62
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint segment
Definition glcorearb.h:4945
const GLdouble * v
Definition glcorearb.h:832
GLuint const GLchar * name
Definition glcorearb.h:781
GLint y
Definition glcorearb.h:270
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:193
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:33
double mEnergy
Total energy.
Definition Detector.h:35
bool mHasTrackReference
Flag indicating whether parent has a track reference.
Definition Detector.h:36
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< int > row