ATLAS Offline Software
Loading...
Searching...
No Matches
CryostatCalibrationCalculator.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5// LArG4::BarrelCryostat::CalibrationCalculator
6// Prepared 06-Jul-2004 Bill Seligman
7
8// This class calculates the values needed for calibration hits in the
9// simulation.
10//
11//
12// G. Pospelov (8-Fev-2006) ==>
13// In 11.0.X geometry of barrel cryostat was changed:
14// "Many of the individual cylinders and cones which were separate logical
15// volumes have become one single piece." (c) J. Boudreau.
16// Names of volumes were changed also. So original code was changed to adopt
17// calculator to the new geometry. It's temporary solution, somedays db
18// oriented version will be written.
19//
20// This calculator is intended to apply to the following volumes
21// LArMgr::LAr::Barrel::Cryostat::Cylinder::*
22// LArMgr::LAr::Barrel::Cryostat::InnerWall
23// LArMgr::LAr::Barrel::Cryostat::Sector::*
24
25
26#define DEBUG_VOLUMES
27#undef DEBUG_HITS
28#undef DEBUG_MAPS
29
32
34
35#include "G4Step.hh"
36#include "G4StepPoint.hh"
37#include "G4VPhysicalVolume.hh"
38#include "G4ThreeVector.hh"
39#include "globals.hh"
40
41#include <map>
42#include <algorithm>
43#include <cmath>
44
45namespace LArG4 {
46
47 namespace BarrelCryostat {
48
50 // Tables
52
53 // There are two ways to implement a routine like this:
54
55 // 1) Lots and lots of "if" statements.
56
57 // 2) Try to encapsulate the decision-making process in tables.
58
59 // I chose the latter approach. The advantage of (2) is that it
60 // formalizes a lot of rules into a relatively small set of
61 // tables; the disadvantage is that the code can be complicated.
62 // (The class CryostatCalibrationLArCalculator demonstrates the
63 // type (1) approach.)
64
65 // One day, the following information may in some sort of
66 // database. For now, it's hard-coded into this routine.
67
68 // The information needed to determine the dead-material
69 // identifier is stored as a "map of a map". The structure looks
70 // something like this:
71
72 // Volume name -- the named defined in the barrel-cryostat
73 // detector-construction routine (make sure these names match the
74 // values in LArBarrelCryostatVisualConsultant)
75
76 // Copy number -- assigned in the barrel-cryostat
77 // detector-construction routine
78
79 // Identifier information record -- the values needed to
80 // construct the identifier for the volume.
81
82 // Region information record -- many large dead volumes
83 // span more than one region. This record gives the
84 // region-specific values.
85
86
87 typedef struct {
89 G4double etaMin;
90 G4double etaMax;
91 G4double deltaEta;
92 G4double deltaPhi;
94
95 typedef struct {
96 G4int detector;
97 G4int subdet;
98 G4int type;
99 G4int sampling;
103
109
110 typedef struct {
111 G4String volumeName;
114 } VolumeInfo_t;
115
116 // Please forgive the dull names, but it saves quite a lot on
117 // typing. Note how the structured hierarchy continues: there can
118 // be many regions associated with one sampling (equivalent to a
119 // range of copy numbers); there can be many ranges of copy
120 // numbers associated with the same volume name.
121
122 // Region definitions
123
124 // ========== Sampling 1 =============
125 static const RegionInfo_t region010[] =
126 // inner warm wall and solenoid
127 // region etamin etamax deta dphi
128 { { 0, 0.0, 1.5, 0.1, M_PI/32. },
129 { 4, 1.5, 1.6, 0.1, M_PI/32. },
130 { 5, 1.5, 1.8, 0.1, M_PI/32. },
131 { 6, 1.3, 3.2, 0.1, M_PI/32. } };
132
133#if 0
134 static const RegionInfo_t region011[] =
135 // inner cold wall
136 // region etamin etamax deta dphi
137 { { 1, 0.0, 1.5, 0.1, M_PI/32. },
138 { 4, 1.5, 1.6, 0.1, M_PI/32. },
139 { 5, 1.5, 1.8, 0.1, M_PI/32. } };
140#endif
141
142 static const RegionInfo_t region012[] =
143 // inner warm wall, cones, cables and services in front of EMEC
144 // region etamin etamax deta dphi
145 { { 4, 1.5, 1.6, 0.1, M_PI/32. },
146 { 5, 1.5, 1.8, 0.1, M_PI/32. },
147 { 6, 1.3, 3.2, 0.1, M_PI/32. } };
148
149 // ========== Sampling 2 =============
150 static const RegionInfo_t region020[] =
151 // outer warm and cold walls in front of Tile-barrel
152 // region etamin etamax deta dphi
153 { { 0, 0.0, 1.0, 0.1, M_PI/32. },
154 { 2, 1.0, 1.5, 0.1, M_PI/32. } };
155
156 static const RegionInfo_t region021[] =
157 // outer warm and cold walls behind of Tile-barrel but
158 // in front of Tile-extended-barrel, cables and services
159 // region etamin etamax deta dphi
160 { { 1, 0.0, 1.0, 0.1, M_PI/32. },
161 { 2, 1.0, 1.5, 0.1, M_PI/32. } };
162
163 // Region->Volume, based on a range of copy numbers. Note that
164 // some "ranges" of copy numbers contain only one volume.
165
166 static const CopyNumberInfo_t info1[] =
167 {
168 // ------------- region inner warm wall and solenoid ------------
169 // copy number range (low, high)
170 // { 1, 1,
171 // // Det Sub Typ Sam
172 // { 10, 4, 1, 1,
173 // sizeof(region010)/sizeof(RegionInfo_t),
174 // region010 }
175 // },
176 // copy number range (low, high)
177 { 56, 60,
178 // Det Sub Typ Sam
179 { 10, 4, 1, 1,
180 sizeof(region010)/sizeof(RegionInfo_t),
181 region010 }
182 },
183 // ------------------ region inner cold wall, Cyl -----------------
184 // copy number range (low, high)
185 // { 4, 5,
186 // // Det Sub Typ Sam
187 // { 10, 4, 1, 1,
188 // sizeof(region011)/sizeof(RegionInfo_t),
189 // region011 }
190 // },
191 // copy number range (low, high)
192 // { 55, 55,
193 // // Det Sub Typ Sam
194 // { 10, 4, 1, 1,
195 // sizeof(region011)/sizeof(RegionInfo_t),
196 // region011 }
197 // },
198 // copy number range (low, high)
199 // { 61, 61,
200 // // Det Sub Typ Sam
201 // { 10, 4, 1, 1,
202 // sizeof(region011)/sizeof(RegionInfo_t),
203 // region011 }
204 // // 84 bolts inside this cylinder have the same name
205 // // and the same copy#=61 => Edeposits in bolts are collected
206 //
207 // },
208 // --- region: inner warm walls, cables and services in front of EMEC
209 // copy number range (low, high)
210 // { 17, 19,
211 // // Det Sub Typ Sam
212 // { 10, 4, 1, 1,
213 // sizeof(region012)/sizeof(RegionInfo_t),
214 // region012 }
215 // },
216 // { 50, 52,
217 // // Det Sub Typ Sam
218 // { 10, 4, 1, 1,
219 // sizeof(region012)/sizeof(RegionInfo_t),
220 // region012 }
221 // },
222
223 // ---------------- outer warm and cold walls, cables and services
224 // copy number range (low, high)
225 // { 3, 3,
226 // // Det Sub Typ Sam
227 // { 10, 4, 1, 2,
228 // sizeof(region021)/sizeof(RegionInfo_t),
229 // region021 }
230 // },
231 { 6, 6,
232 // Det Sub Typ Sam
233 { 10, 4, 1, 2,
234 sizeof(region020)/sizeof(RegionInfo_t),
235 region020 }
236 },
237 { 7, 10,
238 // Det Sub Typ Sam
239 { 10, 4, 1, 2,
240 sizeof(region021)/sizeof(RegionInfo_t),
241 region021 }
242 },
243 { 11, 11,
244 // Det Sub Typ Sam
245 { 10, 4, 1, 2,
246 sizeof(region020)/sizeof(RegionInfo_t),
247 region020 }
248 },
249 { 12, 12,
250 // Det Sub Typ Sam
251 { 10, 4, 1, 2,
252 sizeof(region021)/sizeof(RegionInfo_t),
253 region021 }
254 },
255 { 14, 16,
256 // Det Sub Typ Sam
257 { 10, 4, 1, 2,
258 sizeof(region021)/sizeof(RegionInfo_t),
259 region021 }
260 },
261 // { 48, 48,
262 // // Det Sub Typ Sam
263 // { 10, 4, 1, 2,
264 // sizeof(region021)/sizeof(RegionInfo_t),
265 // region021 }
266 // },
267 // --------------- Half::Cylinder (Old name, info4 was moved to here)
268 // --- placed inside LAr of each Half Barrel ------
269 // copy number range (low, high)
270 { 20, 20, // outer of acco in the center
271 // Det Sub Typ Sam
272 { 10, 4, 1, 2,
273 sizeof(region020)/sizeof(RegionInfo_t),
274 region020 }
275 },
276 { 24, 44, // 24 - 44 outer support-rings
277 // Det Sub Typ Sam
278 { 10, 4, 1, 2,
279 sizeof(region020)/sizeof(RegionInfo_t),
280 region020 }
281 },
282 };
283
284 static const CopyNumberInfo_t info2[] =
285 {
286 //----region: inner wall ---------------------
287 { 1, 1,
288 // Det Sub Typ Sam
289 { 10, 4, 1, 1,
290 sizeof(region010)/sizeof(RegionInfo_t),
291 region010 }
292 },
293 };
294
295 static const CopyNumberInfo_t info3[] =
296 {
297 // ---------------Sectors -----------------
298 // copy number range (low, high)
299 { 12, 12, // legs
300 // Det Sub Typ Sam
301 { 10, 4, 1, 2,
302 sizeof(region021)/sizeof(RegionInfo_t),
303 region021 }
304 },
305 { 7, 7, // ears
306 // Det Sub Typ Sam
307 { 10, 4, 1, 2,
308 sizeof(region021)/sizeof(RegionInfo_t),
309 region021 }
310 },
311 { 1, 1, // Ti blocks 11 - 34 (copy number arbitrary)
312 // Det Sub Typ Sam
313 { 10, 4, 1, 1,
314 sizeof(region012)/sizeof(RegionInfo_t),
315 region012 }
316 },
317 };
318
319 // static const CopyNumberInfo_t info4[] =
320 // {
321 // // --------------- Half::Cylinder -----------------
322 // // --- placed inside LAr of each Half Barrel ------
323 // // copy number range (low, high)
324 // { 20, 20, // outer of acco in the center
325 // // Det Sub Typ Sam
326 // { 10, 4, 1, 2,
327 // sizeof(region020)/sizeof(RegionInfo_t),
328 // region020 }
329 // },
330 // { 24, 44, // 24 - 44 outer support-rings
331 // // Det Sub Typ Sam
332 // { 10, 4, 1, 2,
333 // sizeof(region020)/sizeof(RegionInfo_t),
334 // region020 }
335 // },
336 // };
337
338 // Copy number range->Volume, based on name
339
340 static const VolumeInfo_t volume1 =
341 { "LAr::Barrel::Cryostat::Cylinder",
342 sizeof(info1) / sizeof(CopyNumberInfo_t),
343 info1
344 };
345
346 // static const VolumeInfo_t volume2 =
347 // { "LAr::Barrel::Cryostat::Cone",
348 // sizeof(info2) / sizeof(CopyNumberInfo_t),
349 // info2
350 // };
351 static const VolumeInfo_t volume2 =
352 { "LAr::Barrel::Cryostat::InnerWall",
353 sizeof(info2) / sizeof(CopyNumberInfo_t),
354 info2
355 };
356
357 static const VolumeInfo_t volume3 =
358 { "LAr::Barrel::Cryostat::Sector",
359 sizeof(info3) / sizeof(CopyNumberInfo_t),
360 info3
361 };
362
363 // static const VolumeInfo_t volume4 =
364 // { "LAr::Barrel::Cryostat::Half::Cylinder",
365 // sizeof(info4) / sizeof(CopyNumberInfo_t),
366 // info4
367 // };
368
370 static const G4int numberOfVolumes = sizeof(volumes) / sizeof(VolumeInfo_t);
371
372 typedef std::map < G4int, const IdentifierInfo_t* > identifierMap_t;
373 typedef std::map < G4String, identifierMap_t > volumeMap_t;
374
375
380 {
381 static const volumeMap_t instance = []()
382 {
384 // For each volume managed by this calculator...
385 for (G4int v = 0; v != numberOfVolumes; v++)
386 {
387 const VolumeInfo_t& volume = volumes[v];
388
389#if defined (DEBUG_HITS) || defined (DEBUG_MAPS)
390 G4cout << "LArG4::BarrelCryostat::CalibrationCalculator::CalibrationCalculator - "
391 << " volume '"
392 << volume.volumeName
393 << "' has number of entries=" << volume.numberOfCopies
394 << G4endl;
395#endif
396
397 identifierMap_t identifierMap;
398 const CopyNumberInfo_t* copyInfo = volume.copyInfo;
399
400 // For each range copy numbers that can be found in a volume with this name...
401 for (G4int c = 0; c != volume.numberOfCopies; c++, copyInfo++)
402 {
403 // For each copy in the range of copy numbers
404 for (G4int copy = copyInfo->copyNumberLow;
405 copy <= copyInfo->copyNumberHigh;
406 copy++)
407 {
408#if defined (DEBUG_HITS) || defined (DEBUG_MAPS)
409 G4cout << "LArG4::BarrelCryostat::CalibrationCalculator::CalibrationCalculator - "
410 << " adding copy=" << copy
411 << " to identifierMap"
412 << G4endl;
413#endif
414 // Add to the map that's based on copy number.
415 identifierMap[copy] = &(copyInfo->identifierInfo);
416 }
417 }
418
419 // Add to the map that's based on volume name; it
420 // contains maps based on copy number.
421 volumeMap[volume.volumeName] = std::move(identifierMap);
422
423#if defined (DEBUG_HITS) || defined (DEBUG_MAPS)
424 G4cout << "LArG4::BarrelCryostat::CalibrationCalculator::CalibrationCalculator - "
425 << " volume '"
426 << volume.volumeName
427 << "' added to map."
428 << G4endl;
429#endif
430
431 }
432 return volumeMap;
433 }(); // end of lambda
434
435 return instance;
436 }
437
438
440 // Methods
442
443 CalibrationCalculator::CalibrationCalculator(const std::string& name, ISvcLocator *pSvcLocator)
444 : LArCalibCalculatorSvcImp(name, pSvcLocator)
445 {
446 }
447
449 // Get the "backup" calculator.
450 ATH_CHECK(m_backupCalculator.retrieve());
451
452#if defined (DEBUG_HITS) || defined (DEBUG_MAPS)
453 G4cout << "LArG4::BarrelCryostat::CalibrationCalculator::CalibrationCalculator - "
454 << " numberOfVolumes=" << numberOfVolumes
455 << ", sizeof(volumes)=" << sizeof(volumes)
456 << ", sizeof(VolumeInfo_t)=" << sizeof(VolumeInfo_t)
457 << G4endl;
458#endif
459
460 // Intialize the maps.
461 volumeMap();
462
463
464
465#if defined (DEBUG_HITS) || defined (DEBUG_MAPS)
466 G4cout << "LArG4::BarrelCryostat::CalibrationCalculator::CalibrationCalculator - "
467 << G4endl
468 << " initialization complete; map size="
469 << volumeMap().size()
470 << G4endl;
471#endif
472
473 return StatusCode::SUCCESS;
474 }
475
476 G4bool CalibrationCalculator::Process(const G4Step* step, LArG4Identifier & identifier,
477 std::vector<G4double> & energies,
478 const eCalculatorProcessing process) const
479 {
480 // Use the calculators to determine the energies and the
481 // identifier associated with this G4Step. Note that the
482 // default is to process both the energy and the ID.
483
484 if ( process == kEnergyAndID || process == kOnlyEnergy ) {
485 m_energyCalculator.Energies( step, energies );
486 }
487 else {
488 for (unsigned int i=0; i != 4; i++) energies.push_back( 0. );
489 }
490
491 identifier.clear();
492 if ( process == kEnergyAndID || process == kOnlyID )
493 {
494 // Calculate the identifier.
495
496 // First, find the physical volume copy number, and the
497 // logical volume name.
498
499 G4VPhysicalVolume* physical = step->GetPreStepPoint()->GetPhysicalVolume();
500 G4int copyNumber = physical->GetCopyNo();
501 G4String volumeName = physical->GetLogicalVolume()->GetName();
502
503#ifdef DEBUG_HITS
504 G4cout << "LArG4::BarrelCryostat::CalibrationCalculator::Process - "
505 << G4endl
506 << " searching for volume '"
507 << volumeName
508 << "' copyNumber="
509 << copyNumber
510 << G4endl;
511#endif
512
513 if(volumeName.find("LArMgr::") == 0) volumeName.erase(0,8);
514 if(volumeName.find("LAr::Barrel::Cryostat::Sector")==0) { // ears, legs, Ti blocks
515 volumeName = "LAr::Barrel::Cryostat::Sector";
516 if(copyNumber != 7 && copyNumber !=12) copyNumber=1; // assignment arbitrary copyNumber to Ti block
517 }else if(volumeName.find("LAr::Barrel::Cryostat::Cylinder")==0){
518 volumeName = "LAr::Barrel::Cryostat::Cylinder";
519 }else if(volumeName.find("LAr::Barrel::Cryostat::InnerWall")==0){
520 volumeName = "LAr::Barrel::Cryostat::InnerWall";
521 copyNumber = 1; // assignment arbitrary copyNumber
522 }
523
524 // Search the maps for this volume/copy number combination.
525 const auto v = volumeMap().find( volumeName );
526 if ( v != volumeMap().end() )
527 {
528
529 // Recall that maps are made from pair <key,value>, and
530 // you access a pair with the "first" and "second"
531 // members. In this case, "second" is a map. We don't
532 // need to copy the entire map; it's enough to get its
533 // reference.
534
535 const identifierMap_t& identifierMap = (*v).second;
536 const auto i = identifierMap.find( copyNumber );
537
538 if ( i != identifierMap.end() )
539 {
540 const IdentifierInfo_t* info = (*i).second;
541
542 // Find our (x,y,z) location from the G4Step.
543
544 G4StepPoint* pre_step_point = step->GetPreStepPoint();
545 G4StepPoint* post_step_point = step->GetPostStepPoint();
546 G4ThreeVector startPoint = pre_step_point->GetPosition();
547 G4ThreeVector endPoint = post_step_point->GetPosition();
548 G4ThreeVector p = (startPoint + endPoint) * 0.5;
549
550 // Determine the geometric eta and phi. Note that we do not
551 // adjust for any endcap shifts; the values are assigned to
552 // the volumes based on their design positions.
553
554 G4double eta = fabs( p.pseudoRapidity() );
555 G4double phi = p.phi();
556 // For this calculation, we need 0<phi<2*PI. (The
557 // official ATLAS standard of -PI<phi<PI is
558 // meaningless here.)
559 if ( phi < 0 ) phi += 2*M_PI;
560
561 // The region can depend on eta. Search through the
562 // list of regions within this IdentifierInfo record
563 // to find which one has etaMin<eta<etaMax.
564
565 G4int regions = info->numberOfRegions;
566 const RegionInfo_t* region = info->regionInfoArray;
567
568#ifdef DEBUG_HITS
569 G4cout << "LArG4::BarrelCryostat::CalibrationCalculator::Process - "
570 << G4endl
571 << " found volume, number of regions="
572 << regions
573 << " eta=" << eta << " phi=" << phi
574 << G4endl;
575#endif
576
577 G4int r;
578 for ( r = 0; r < regions; r++, region++ )
579 {
580 if ( eta > region->etaMin &&
581 eta < region->etaMax )
582 break;
583 }
584
585 // If the following statement is not true, we're in
586 // trouble. It means that the eta of our energy
587 // deposit is outside the assumed eta limits of the
588 // volume.
589
590 if ( r < regions )
591 {
592 // Convert eta and phi to their integer equivalents for the
593 // identifier.
594
595 G4int etaInteger = G4int( (eta - region->etaMin) / region->deltaEta );
596 G4int phiInteger = G4int( phi / region->deltaPhi );
597 // phiInteger should be less than 64
598 if (phiInteger > 63) phiInteger = 0;
599
600#ifdef DEBUG_HITS
601 G4cout << "LArG4::BarrelCryostat::CalibrationCalculator::Process - "
602 << G4endl
603 << " found region="
604 << region->regionNumber
605 << " eta bin=" << etaInteger << " phi bin=" << phiInteger
606 << G4endl;
607#endif
608
609 // The sign of subdet will depend on whether z is positive
610 // or negative.
611 G4int subDetSign = 1;
612 if ( p.z() < 0 ) subDetSign = -1;
613
614 // A quick check against a bad value of etaMin.
615 if ( etaInteger >= 0 )
616 {
617 // Build the full identifier.
618 identifier << info->detector
619 << info->subdet * subDetSign
620 << info->type
621 << info->sampling
622 << region->regionNumber
623 << etaInteger
624 << phiInteger;
625
626 } // etaInteger valid
627 } // eta valid
628 } // copy number valid
629 } // volume name valid
630
631 // If a volume is not found on one of the above tables, try
632 // the "backup identifier" calculator.
633
634 if ( identifier == LArG4Identifier() )
635 {
636#if defined (DEBUG_HITS) || defined (DEBUG_VOLUMES)
637 std::cout << "LArG4::BarrelCryostat::CalibrationCalculator::Process"
638 << std::endl
639 << " volume '"
640 << volumeName
641 << "' copy# "
642 << copyNumber
643 << " not found on tables, using backup calculator"
644 << std::endl;
645#endif
646 m_backupCalculator->Process(step, identifier, energies, process);
647 }
648 } // calculate identifier
649
650#ifdef DEBUG_HITS
651 //G4double energy = accumulate(energies.begin(),energies.end(),0.);
652 std::cout << "LArG4::BarrelCryostat::CalibrationCalculator::Process"
653 << " vName " << step->GetPreStepPoint()->GetPhysicalVolume()->GetName()
654 << " ID=" << std::string(identifier)
655 // << " energy=" << energy
656 << " energies=(" << energies[0]
657 << "," << energies[1]
658 << "," << energies[2]
659 << "," << energies[3] << ")"
660 << std::endl;
661#endif
662
663 // Check for bad result.
664 return ( identifier != LArG4Identifier() );
665 }
666
667 } // namespace BarrelCryostat
668
669} // namespace LArG4
#define M_PI
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
static const std::vector< std::string > regions
std::map< std::string, double > instance
LArCalibCalculatorSvcImp(const std::string &name, ISvcLocator *pSvcLocator)
virtual G4bool Process(const G4Step *step, LArG4Identifier &identifier, std::vector< G4double > &energies, const eCalculatorProcessing process=kEnergyAndID) const override final
CalibrationCalculator(const std::string &name, ISvcLocator *pSvcLocator)
const std::string process
int r
Definition globals.cxx:22
static const RegionInfo_t region021[]
static const CopyNumberInfo_t info3[]
static const RegionInfo_t region010[]
std::map< G4String, identifierMap_t > volumeMap_t
static const CopyNumberInfo_t info2[]
const volumeMap_t & volumeMap()
volumeMap singleton
static const RegionInfo_t region012[]
static const VolumeInfo_t volumes[]
static const CopyNumberInfo_t info1[]
static const RegionInfo_t region020[]
std::map< G4int, const IdentifierInfo_t * > identifierMap_t
eCalculatorProcessing
@ kOnlyEnergy
@ kEnergyAndID