ATLAS Offline Software
Loading...
Searching...
No Matches
LArBarrelGeometry.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5/********************************************************************
6
7NAME: LArBarrelGeometry.cxx
8PACKAGE: offline/LArCalorimeter/LArG4/LArG4Barrel
9
10AUTHORS: G. Unal, L. Carminati
11CREATED: September, 2004
12
13PURPOSE: 'geometrical' methods used by the LArBarrelCalculator.
14 These methods (previously in LArBarrelCalculator) were written
15 by Gaston Parrour and adapted by Sylvain Negroni.
16
17UPDATES: - Calculate identifier method used by CalibrationCalculator.
18 (sept 2004)
19 - Cleanup (GU March-April 2005)
20
21********************************************************************/
22
23// #define DEBUGHITS
24
25#include <cmath>
26#include <iostream>
27#include <vector>
28#include "LArBarrelGeometry.h"
29
32#include "LArCoudeElectrodes.h"
33#include "LArCoudeAbsorbers.h"
34
35// values of the radial separations between samplings
36#include "LArBarrelSampling.h" // Rmax1, Rmax2
37
38
39namespace LArG4 {
40
41 namespace Barrel {
42
43 Geometry::Geometry(const std::string& name, ISvcLocator *pSvcLocator)
44 : base_class(name, pSvcLocator)
45 {
46 }
47
48 // ====================================================================================
49
51 {
52 // initialize the geometry.
53 // Access source of detector parameters.
54
56
57 // number of straight sections (should be 14)
58 m_Nbrt = (int) (parameters->GetValue("LArEMBnoOFAccZigs"));
59 // Number of ZIGs + 1 i.e. 15 = number of folds
60 m_Nbrt1 = m_Nbrt + 1;
61 // phi of first absorber
62 m_gam0 = parameters->GetValue("LArEMBAbsPhiFirst");
63 // radius of curvature of neutral fiber in the folds
64 m_rint_eleFib = parameters->GetValue("LArEMBNeutFiberRadius");
65
66 m_rc = new double[m_Nbrt1];
67 m_phic = new double[m_Nbrt1];
68 m_delta = new double[m_Nbrt1];
69 m_xc = new double[m_Nbrt1];
70 m_yc = new double[m_Nbrt1];
71
72 // r,phi positions of the centre of the folds (nominal geometry)
73 for (G4int idat = 0; idat < m_Nbrt1 ; idat++) {
74 m_rc[idat] = (double) parameters->GetValue("LArEMBRadiusAtCurvature",idat);
75 m_phic[idat] = (double) parameters->GetValue("LArEMBPhiAtCurvature",idat);
76 m_delta[idat] = (double) parameters->GetValue("LArEMBDeltaZigAngle",idat);
77 m_xc[idat] = m_rc[idat]*cos(m_phic[idat]);
78 m_yc[idat] = m_rc[idat]*sin(m_phic[idat]);
79 }
80 // define parity of accordion waves: =0 if first wave goes up, 1 if first wave goes down in the local frame
81 m_parity=0;
82 if (m_phic[0]<0.) { m_parity=1; }
83 //
84 m_rMinAccordion = parameters->GetValue("LArEMBRadiusInnerAccordion");
85 m_rMaxAccordion = parameters->GetValue("LArEMBFiducialRmax");
86 m_etaMaxBarrel = parameters->GetValue("LArEMBMaxEtaAcceptance");
87 m_zMinBarrel = parameters->GetValue("LArEMBfiducialMothZmin");
88 m_zMaxBarrel = parameters->GetValue("LArEMBfiducialMothZmax");
89 m_zMaxBarrelDMMargin = 10.0; // 10 mm margin
90 // === GU 11/06/2003 total number of cells in phi
91 // to distinguish 1 module (testbeam case) from full Atlas
92 m_NCellTot = (int) (parameters->GetValue("LArEMBnoOFPhysPhiCell"));
93 // total number of cells in phi to distinguish 1 module (testbeam case) from full Atlas
94 m_testbeam=false;
95 if (m_NCellTot != 1024) {
96 m_testbeam=true;
97 }
98 m_NCellMax=1024;
99 // ===
100
101 // Initialize r-phi reference map
102 this->GetRphi();
103
104 if (m_detectorName.empty()) m_ecamName = "LAr::EMB::ECAM";
105 else m_ecamName = m_detectorName+"::LAr::EMB::ECAM";
106
107 // Validate SR granularity properties against bit-packing constraints
109 ATH_MSG_ERROR("nBinsEtaSR must be in range [1, 64], got " << m_nBinsEtaSR);
110 return StatusCode::FAILURE;
111 }
113 ATH_MSG_ERROR("nBinsPhiSR must be in range [1, 64], got " << m_nBinsPhiSR);
114 return StatusCode::FAILURE;
115 }
117 ATH_MSG_ERROR("nBinsRadiusSR must be in range [1, 8], got " << m_nBinsRadiusSR);
118 return StatusCode::FAILURE;
119 }
120
121 return StatusCode::SUCCESS;
122 }
123
124 // ====================================================================================
125
134
135 // ====================================================================================
136
138 {
139 if (m_rc) delete [] m_rc;
140 if (m_phic) delete [] m_phic;
141 if (m_delta) delete [] m_delta;
142 if (m_xc) delete [] m_xc;
143 if (m_yc) delete [] m_yc;
144
145 return StatusCode::SUCCESS;
146 }
147
148 //======================================================================================
149 //
150 // Here INTRINSIC Distance_to_electrode determination (G.P.)
151 //
152 // This retuns an ALGEBRICDistEle value, the distance from electrode
153 //neutral fiber TOWARDS the Sub_Step in LAr (measured on a local perpendicular
154 //vector unit oriented upwards i.e. following increasing Phi values).
155 //
156 // This is done in THE INTRINSIC LOCAL Z > 0. half_barrel part ("stac_phys1")
157 //
158 // inputs: xhit,yhit = x,y positions in local half barrel
159 // PhiCell = electrode number in phi (0 to 1023 for Atlas case)
160 // Num_Straight = number (0 to 13) of the straight section
161 // Num_Coude = number (0 to 14) of closest fold
162 //
163 // output: Function value = algebric distance to electrode
164 // xl = normalized lenght along electrode straight section (between +-1)
165
166 double Geometry::Distance_Ele(const double & xhit,
167 const double &yhit, const int &PhiCell, int &Num_Straight,
168 const int &Num_Coude, double &xl) const
169 {
170 //
171 // FrameWork is consistent with the one used to PhiCell determination
172 // e.g. it assumes HERE to be the LOCAL one of "stac_phys1",
173 // (mother of ACCordion volumes) from which Z> 0. and Z < 0. half_barrel
174 // parts are then defined.
175 //
176 // One needs POINTERS to Electrode neutral fibers
177 // either for straight parts or for folds
178 //
179 // Fold Center ccoordinates
180 const G4double Xc[2] = { m_coudeelec->XCentCoude(Num_Coude, PhiCell), m_coudeelec->YCentCoude(Num_Coude, PhiCell) };
181 const G4double radfold = sqrt(Xc[0]*Xc[0]+Xc[1]*Xc[1]);
182 const G4double radhit = sqrt(xhit*xhit+yhit*yhit);
183
184 // check if the assumed straight number is the correct one
185 // (this can be wrong when we are close to a fold and there is sagging)
186 if (Num_Coude == Num_Straight && radhit <radfold) {
187 if (Num_Straight>0) { Num_Straight = Num_Straight-1; }
188 // ATH_MSG_VERBOSE("radhit,radfold " << radhit << " " << radfold << " change straight by +1");
189 }
190 if (Num_Coude == (Num_Straight+1) && radhit > radfold) {
191 if (Num_Straight<12) { Num_Straight = Num_Straight+1; }
192 // ATH_MSG_VERBOSE("radhit,radfold " << radhit << " " << radfold << " change straight by -1");
193 }
194
195 // u unit 2D_Vector along straight part of the electrode neutral fiber
196 const double u[2] = { m_electrode->Cosu(Num_Straight, PhiCell), m_electrode->Sinu(Num_Straight, PhiCell) };
197 // Middle m_coordinates of this straight part of the electrode neutral fiber
198 const double Xm[2] = { m_electrode->XCentEle(Num_Straight, PhiCell), m_electrode->YCentEle(Num_Straight, PhiCell) };
199 // m_Hit Vector components
200 double dx = xhit - Xm[0];
201 double dy = yhit - Xm[1];
202
203 // First compute algebric distance m_hit (2D) the 2D_projection of the
204 // m_Hit Vector on this electrode neutral fiber.
205 const double hit = dx*u[0] + dy*u[1];
206
207 //
208 // Flat of Fold Region ?
209 //
210 const G4double Half_Elec(m_electrode->HalfLength(Num_Straight,PhiCell));
211
212 if(std::fabs(hit) < Half_Elec) {
213 // Flat Region
214 xl=hit/Half_Elec;
215 return u[0]*dy - u[1]*dx;
216 }
217 else {
218 // Fold region
219 // c_Hit Vector components and its length
220 dx = xhit - Xc[0];
221 dy = yhit - Xc[1];
222 const double dr = sqrt( dx*dx + dy*dy);
223 if (Num_Coude==Num_Straight) { xl=-1.; }
224 else xl=+1;
225 return (Num_Coude%2 == m_parity) ? (m_rint_eleFib-dr) : (dr - m_rint_eleFib);
226 } // end of Fold Regions
227 } // end of the function Distance_Ele
228
229
230 //======================================================================================
231 // Algebric distance to absorber
232 //
233 // inputs: xhit,yhit = x,y positions in local half barrel
234 // PhiCell = absorber number in phi (0 to 1023 for Atlas case)
235 // Num_Straight = number (0 to 13) of the straight section
236 // Num_Coude = number (0 to 14) of closest fold
237 //
238 // output: Function value = algebric distance to electrode
239
240 double Geometry::Distance_Abs(const double & xhit,
241 const double &yhit, const int &PhiCell, const int &Num_Straight,
242 const int &Num_Coude) const
243 {
244 //
245 // FrameWork is consistent with the one used to PhiCell determination
246 // e.g. it assumes HERE to be the LOCAL one of "stac_phys1",
247 // (mother of ACCordion volumes) from which Z> 0. and Z < 0. half_barrel
248 // parts are then defined.
249 //
250 // One needs POINTERS to Electrode neutral fibers
251 // either for straight parts or for folds
252 //
253 // u unit 2D_Vector along straight part of the electrode neutral fiber
254 const G4double u[2] = { m_absorber->Cosu(Num_Straight, PhiCell), m_absorber->Sinu(Num_Straight, PhiCell) };
255 // Middle m_coordinates of this straight part of the electrode neutral fiber
256 const G4double Xm[2] = { m_absorber->XCentAbs(Num_Straight, PhiCell), m_absorber->YCentAbs(Num_Straight, PhiCell) };
257 // m_Hit Vector components
258 double dx = xhit - Xm[0]; double dy = yhit - Xm[1];
259
260 // First compute algebric distance hit (2D) the 2D_projection of the
261 // m_Hit Vector on this electrode neutral fiber.
262 const double hit = dx*u[0] + dy*u[1];
263
264 //
265 // Flat of Fold Region ?
266 //
267 if(std::fabs(hit) < m_absorber->HalfLength(Num_Straight,PhiCell)) {
268 // Flat Region
269 return u[0]*dy - u[1]*dx;
270 }
271 else {
272 // Fold Center c_coordinates
273 const G4double Xc[2] = { m_coudeabs->XCentCoude(Num_Coude, PhiCell), m_coudeabs->YCentCoude(Num_Coude, PhiCell) };
274 // c_Hit Vector components and its length
275 dx = xhit - Xc[0];
276 dy = yhit - Xc[1];
277 const double dr = sqrt( dx*dx + dy*dy);
278 return (Num_Coude%2 == m_parity) ? (m_rint_eleFib-dr) : (dr - m_rint_eleFib);
279 } // end of Fold Regions
280 } // end of the function Distance_Abs
281
282
283 //=============================================================================
284 // Function SampSeg
285 //
286 // eta-sampling segmentation of barrel calorimeter GU, January 2005
287 // input values: eta,radius in half-barrel frame
288 //
289 // return value of function: true=active area, false=inactive area
290 // return arguments: iregion,isampling,ieta
291 // take into account detailed electrode drawing
292 // with readout strips
293 // isamp2,ieta2 do not take into account
294 // readout strips and can be used to access current
295 // maps.
296 //
297 // iregion=0 (eta<1.4) or 1 (eta=1.4-1.475)
298 // for region 0: isampling = 1 (strips), 2 (middle), 3 (back)
299 // for region 1: isampling = 1 or isampling = 2
300 // ieta= eta cell number
301 // region0,samp1: ieta=1->448 (strip 0 does not exist)
302 // region0,samp2: ieta=0->55
303 // region0,samp3: ieta=0->26 (max eta 1.325)
304 // region1,samp1: ieta=0->2 (deta=0.025)
305 // region1,samp2: ieta=0 (only 1 cell)
306
307 G4int Geometry::SampSeg(G4double eta, G4double radius, G4double z,
308 G4int& iregion, G4int& isampling, G4int& ieta,
309 G4int& isamp2, G4int& ieta2) const
310 {
311 // Helper struct to hold pre-calculated geometry information
312 struct Geo {
313 G4double Eta_max,R_max_acc,Z_max_acc,R_min_acc,Z_max_lowr,dzdr;
314 G4double zmax1,zmax2,zmax3,zmax4,zmax5,zmax6,zmax7,rmax1,rmax2,rmax3,rmax4;
315 };
316
317 // Fill it once
318 static const Geo g = []() {
320 Geo g{};
321
322 // maximum eta barrel 1.475 (at r=1500.024)
323 g.Eta_max = parameters->GetValue("LArEMBMaxEtaAcceptance");
324 // minimum active radius 1500.024
325 g.R_min_acc= parameters->GetValue("LArEMBRadiusInnerAccordion");
326 // maximum active radius 1960.
327 g.R_max_acc = parameters->GetValue("LArEMBFiducialRmax");
328 // maximum active z (before subtracting edge for signal readout)
329 // currently 3150, should be changed in database to become 3164
330 g.Z_max_acc = parameters->GetValue("LArEMBfiducialMothZmax");
331 // minimum radius at z max for active region
332 const G4double R_min_highz=1548.; //FIXME should be taken from database
333
334 // compute z edge taken by readout strips on the edge
335 const G4double deltaz=7.; // this include copper 6mm + 2*0.5mm empty space on each side
336 g.zmax1=g.Z_max_acc-deltaz;
337 g.zmax2=g.Z_max_acc-2.*deltaz;
338 g.zmax3=g.Z_max_acc-3.*deltaz;
339 g.zmax4=g.Z_max_acc-4.*deltaz;
340 g.zmax5=g.Z_max_acc-5.*deltaz;
341 g.zmax6=g.Z_max_acc-6.*deltaz;
342 g.zmax7=g.Z_max_acc-7.*deltaz;
343 g.rmax1=g.R_max_acc-deltaz;
344 g.rmax2=g.R_max_acc-2.*deltaz;
345 g.rmax3=g.R_max_acc-3.*deltaz;
346 g.rmax4=g.R_max_acc-4.*deltaz;
347
348 // maximum z at r=1500.024
349 g.Z_max_lowr = sinh(g.Eta_max)*g.R_min_acc;
350 // slope of z vs r edge (which is not projective in eta...)
351 g.dzdr = (g.Z_max_acc-g.Z_max_lowr)/(R_min_highz-g.R_min_acc);
352
353 // ATH_MSG_VERBOSE("Initialization of SampSet ");
354 // ATH_MSG_VERBOSE(" Rmin/Rmax " << g.R_min_acc << " " << g.R_max_acc);
355 // ATH_MSG_VERBOSE(" Zmax/Zmax_lowR " << g.Z_max_acc << " " << g.Z_max_lowr);
356 // ATH_MSG_VERBOSE(" Rmin_highz " << R_min_highz);
357 // ATH_MSG_VERBOSE(" dzdr " << g.dzdr);
358 return g;
359 }();
360
361 // inactive thickness between S1 and S2 FIXME should be taken from database
362 const G4double Dr_s12=1.1;
363 const G4double Eta_max_s1=1.4; // maximum eta region 0
364 const G4double Eta_max_s3=1.325; // maximum eta for S3 in region 0
365 const G4double deta=0.025; // basic granularity
366
367
368 // iactive = 1 if active region, 0 if region considered as inactive
369 G4int iactive = 1;
370
371 const G4double aeta=std::fabs(eta);
372
373 G4double r12=-1.;
374 G4double r23=-1.;
375
376 // Not used: G4double rmax=Z_max_acc/sinh(aeta);
377
378 G4int istrip,imid;
379
380 // eta < 1.4
381
382 if (aeta<Eta_max_s1) {
383
384 // get radius for end of strips
385 istrip=(int) (aeta/deta*8.);
386 if (istrip<0 || istrip >=448) {
387 ATH_MSG_ERROR(" Problem aeta,istrip " << aeta << " " << istrip);
388 return 0;
389 }
390 r12=Rmax1[istrip];
391
392 // get radius for end of middle
393 imid = (int) (aeta/deta);
394 if (imid <0 || imid >=56) {
395 ATH_MSG_ERROR(" Problem aeta,imid " << aeta << " " << imid);
396 return 0;
397 }
398 r23=Rmax2[imid];
399
400 iregion=0;
401
402 // strips
403 if (radius <= r12) {
404 isampling=1;
405 ieta=istrip;
406 if (ieta==0) iactive=0;
407 isamp2=1;
408 ieta2=istrip;
409 }
410
411 // region between strips and middle => not active, same identifier as strips
412 else if (radius < (r12+Dr_s12)) {
413 isampling=1;
414 ieta=istrip;
415 iactive=0;
416 isamp2=1;
417 ieta2=istrip;
418 }
419
420 else {
421
422 // eta<1.325, we can be in the back
423 if (aeta<Eta_max_s3) {
424 // radius<r23 we are in the middle
425 if (radius <= r23) {
426 isampling=2;
427 ieta=imid;
428 isamp2=2;
429 ieta2=imid;
430 }
431 // for radius >r23 we have to take care of the readout strips at high z
432 // and attribute some of the energy to other cells
433 else { // radius>r23
434 if (z>g.zmax1) {
435 isampling=2;
436 ieta=55;
437 }
438 else if (z>g.zmax2) {
439 isampling=2;
440 ieta=54;
441 }
442 else if (z>g.zmax3) {
443 isampling=2;
444 ieta=53;
445 }
446 else if (z>g.zmax4) {
447 isampling=3;
448 ieta=26;
449 }
450 else if (aeta<1.3 && z>g.zmax5) {
451 isampling=2;
452 ieta=52;
453 }
454 else if (aeta<1.3 && z>g.zmax6) {
455 isampling=2;
456 ieta=51;
457 }
458 else if (radius>g.rmax4 && z<g.zmax5 && aeta>1.2) {
459 if (radius>g.rmax1) {
460 isampling=2;
461 ieta=51;
462 }
463 else if(radius>g.rmax2) {
464 isampling=3;
465 ieta=25;
466 }
467 else if (radius>g.rmax3) {
468 if (z<g.zmax7) {
469 isampling=2;
470 ieta=50;
471 }
472 else {
473 isampling=3;
474 ieta=25;
475 }
476 }
477 else {
478 if (aeta<1.25) {
479 isampling=2;
480 ieta=49;
481 }
482 else {
483 isampling=3;
484 ieta=25;
485 }
486 }
487 }
488 // normal back cell
489 else {
490 isampling=3;
491 ieta=imid/2;
492 isamp2=3;
493 ieta2=ieta;
494 }
495 isamp2=3;
496 ieta2=imid/2;
497 } // end radius>r23
498 // put into middle energy deposited along readout strips across the back
499 if (isampling==3 && z<g.zmax4 && (radius<g.rmax4 || aeta<1.2) ) {
500 const double etastr = (imid%2==0) ? 0.025*imid : 0.025*(imid+1);
501 const double delta=radius*(sinh(etastr)-sinh(aeta))/cosh(etastr);
502 double deltastr;
503 if (aeta<0.475) { deltastr=1.5;}
504 else if (aeta<0.80) { deltastr=2.75;}
505 else if (aeta<0.85) { deltastr=1.5;}
506 else if (aeta<1.1) { deltastr=2.75;}
507 else { deltastr=3.25;}
508
509 if (std::fabs(delta)<deltastr) {
510 isampling=2;
511 ieta=imid;
512 }
513 } // end if sampling==3
514 } // end if eta<1.325
515 else {
516 isampling=2;
517 ieta=imid;
518 if (z>g.zmax1) {
519 ieta=55;
520 }
521 else if (z>g.zmax2 && aeta<1.375) {
522 ieta=54;
523 }
524 isamp2=2;
525 ieta2=imid;
526 } // end eta>1.352
527 } // end radius selection
528 } // end eta1.4
529
530 // eta between 1.4 and 1.475
531
532 if (aeta>=Eta_max_s1 && aeta<g.Eta_max) {
533 r12 = Rmax1[447]; // radius for end of sampling 1
534 r23=g.Z_max_acc/sinh(aeta); // radius of end of sampling 2, bounded by high z end
535
536 const double zmax = g.Z_max_lowr + g.dzdr*(radius-g.R_min_acc);
537
538 iregion=1;
539 if (radius <=r12) {
540 isampling=1;
541 ieta=int((aeta-Eta_max_s1)/deta);
542 if (z>zmax) { iactive=0; }
543 }
544 else if (radius < (r12+Dr_s12)) {
545 isampling=1;
546 ieta=int((aeta-Eta_max_s1)/deta);
547 iactive=0;
548 }
549 else if (radius <= r23) {
550 isampling=2;
551 ieta=0;
552 if (z>zmax) { iactive=0; }
553 }
554 else {
555 isampling=2;
556 ieta=0;
557 iactive=0;
558 }
559 isamp2=isampling;
560 ieta2=ieta;
561 }
562 // eta above 1.475, not fiducial region, but still returns something
563 // for calibration hits
564 if (aeta>g.Eta_max) {
565 iregion=1;
566 r12 = Rmax1[447];
567 if (radius <=r12) {
568 isampling=1;
569 ieta=2;
570 }
571 else {
572 isampling=2;
573 ieta=0;
574 }
575 isamp2=isampling;
576 ieta2=ieta;
577 iactive=0;
578 }
579
580 // cross-check of active region
581 if (z>g.Z_max_acc || radius>g.R_max_acc || radius<g.R_min_acc || aeta > g.Eta_max) iactive=0;
582
583 return iactive;
584 }
585 // =======================================================================
586 // function findCell
587 //
588 // compute cell in EM accordion for hit at position x,y,z,radius,eta,phi
589 // given in LOCAL half barrel coordinate system (Stac Geant volume)
590 // It has already been checked that the hit is in the accordion sensitive volume
591 //
592
593 void Geometry::findCell(CalcData & currentCellData,
594 const double &xPosition,
595 const double &yPosition,
596 const double &zPosition,
597 const double &aRadius,
598 const double &anEta,
599 const double &/*aPhi*/,
600 const bool MapDetail) const
601 {
602
603 currentCellData.cellID = 0;
604
605 if (aRadius < m_rc[0] || aRadius >= m_rc[m_Nbrt1-1]) {
606#ifdef DEBUGHITS
607 ATH_MSG_VERBOSE(" Outside Accordion " << aRadius << " " << m_rc[0] << " " << m_rc[m_Nbrt1-1]);
608#endif
609 return; // outside accordion
610 }
611
612 // set the straight section number
613 currentCellData.nstraight=0;
614 for (int i=1;i<m_Nbrt1;i++) {
615 if (m_rc[i] > aRadius) { break; }
616 currentCellData.nstraight++;
617 }
618 if (currentCellData.nstraight <0 || currentCellData.nstraight >= m_Nbrt) {
619 ATH_MSG_ERROR("Invalid straight number " << currentCellData.nstraight << " " << aRadius);
620 return;
621 }
622
623 // get the closest fold number
624 currentCellData.nfold=currentCellData.nstraight;
625 if (std::fabs(aRadius-m_rc[currentCellData.nfold]) > std::fabs(aRadius-m_rc[currentCellData.nfold+1]) ) {
626 currentCellData.nfold +=1;
627 }
628 if (currentCellData.nfold <0 || currentCellData.nfold >= m_Nbrt1) {
629 ATH_MSG_ERROR("Invalid fold number " << currentCellData.nfold);
630 return;
631 }
632
633
634#ifdef DEBUGHITS
635 ATH_MSG_VERBOSE(" BarrelGeometry: radius,eta,phi " << aRadius << " " << anEta << " ");
636 ATH_MSG_VERBOSE(" Straight/Fold numbers " << currentCellData.nstraight << " " << currentCellData.nfold);
637#endif
638
639 // eta and longitudinal segmentations
640 G4int ireg,isamp,ieta,isamp2,ieta2;
641 currentCellData.cellID = this->SampSeg(anEta,aRadius,zPosition,ireg,isamp,ieta,isamp2,ieta2);
642
643 currentCellData.etaBin = ieta;
644 currentCellData.sampling = isamp;
645 currentCellData.region = ireg;
646 currentCellData.etaMap = ieta2;
647 currentCellData.sampMap = isamp2;
648
649 // compute electrode number in phi
650 int phicell = this->PhiGap(aRadius,xPosition,yPosition);
651 if (phicell<0) phicell=0;
652 // for test beam, some protection
653 if (m_NCellTot !=1024) {
654 if (phicell>=m_NCellTot) {
655 if (phicell<512) { phicell=m_NCellTot-1; }
656 else { phicell=0; }
657 currentCellData.cellID=0;
658 }
659 }
660
661#ifdef DEBUGHITS
662 ATH_MSG_VERBOSE(" phigap " << phicell);
663#endif
664
665 // compute readout cell number
666 int sampling_phi_nGaps=4;
667 if (currentCellData.region==0 && currentCellData.sampling==1) { sampling_phi_nGaps=16; }
668
669 if (currentCellData.cellID==0) {
670 currentCellData.phiBin = (G4int) ( phicell/sampling_phi_nGaps );
671 currentCellData.distElec=9999.;
672 return;
673 }
674
675 // compute distance to electrode
676 G4double xl;
677 G4int nstr = currentCellData.nstraight;
678 const G4double distElec = this->Distance_Ele(xPosition,yPosition,phicell,nstr,currentCellData.nfold,xl);
679
680#ifdef DEBUGHITS
681 ATH_MSG_VERBOSE(" distElec " << distElec);
682#endif
683
684 // if distance is < 2.5mm we are sure to be in the correct gap
685 if (std::fabs(distElec) > 2.5) {
686 // try +-2 electrode in phi to get minimum distance
687 double dElecMin=distElec;
688 double xlmin=xl;
689 int phicellmin=phicell;
690 for (int ii=-2;ii<3;ii++) {
691 if (ii==0) { continue; }
692 int phicellnew = phicell+ii;
693 // for test beam no phi wrapping
694 if (m_NCellTot != 1024 && ( phicellnew<0 || phicellnew >= m_NCellTot)) { continue; }
695 if (phicellnew < 0) { phicellnew += m_NCellTot; }
696 if (phicellnew >= m_NCellTot) { phicellnew -= m_NCellTot; }
697 double xln;
698 int nstr2=currentCellData.nstraight;
699 double dElec = Distance_Ele(xPosition,yPosition,phicellnew,nstr2,currentCellData.nfold,xln);
700 if (std::fabs(dElec)<std::fabs(dElecMin)) {
701 phicellmin=phicellnew;
702 xlmin=xln;
703 dElecMin = dElec;
704 nstr=nstr2;
705 }
706 }
707 currentCellData.phiGap = phicellmin;
708 currentCellData.distElec = dElecMin;
709 currentCellData.xl = xlmin;
710 currentCellData.nstraight = nstr;
711 } // end distance >2.5mm
712 else {
713 currentCellData.phiGap=phicell;
714 currentCellData.distElec=distElec;
715 currentCellData.xl=xl;
716 currentCellData.nstraight=nstr;
717 }
718
719#ifdef DEBUGHITS
720 ATH_MSG_VERBOSE(" final phiGap,distElec,xl " << currentCellData.phiGap << " " << currentCellData.distElec << " "
721 << currentCellData.xl);
722#endif
723
724 // compute distance to absorber
725
726 G4int nabs;
727 if (currentCellData.distElec<0) nabs=currentCellData.phiGap;
728 else nabs=currentCellData.phiGap+1;
729 if (nabs >= m_NCellMax) nabs -= m_NCellMax;
730 currentCellData.distAbs = Distance_Abs(xPosition,yPosition,nabs,currentCellData.nstraight,currentCellData.nfold);
731#ifdef DEBUGHITS
732 ATH_MSG_VERBOSE(" nabs,distAbs " << nabs << " " << currentCellData.distAbs);
733#endif
734
735 // in some rare cases near fold, the closest distance could give the wrong gap
736 // in such case, the signs of distAbs and distElec are not opposite as they should
737 if ((currentCellData.distAbs>0. && currentCellData.distElec>0) ||
738 (currentCellData.distAbs<0. && currentCellData.distElec<0) ) {
739 // ATH_MSG_VERBOSE("distElec and distAbs same sign " << currentCellData.distElec << " " << currentCellData.distAbs);
740 // ATH_MSG_VERBOSE(" currentCellData.phiGap " << currentCellData.phiGap);
741 if (std::fabs(currentCellData.distElec)>std::fabs(currentCellData.distAbs)) {
742 if (currentCellData.distAbs>0) { currentCellData.phiGap += 1; }
743 if (currentCellData.distAbs<0) { currentCellData.phiGap -= 1; }
744 if (m_NCellTot != 1024) {
745 if (currentCellData.phiGap <0) { currentCellData.phiGap=0; }
746 if (currentCellData.phiGap >= m_NCellTot) { currentCellData.phiGap = m_NCellTot-1; }
747 }
748 else {
749 if (currentCellData.phiGap < 0) { currentCellData.phiGap += m_NCellTot; }
750 if (currentCellData.phiGap >= m_NCellTot) { currentCellData.phiGap -= m_NCellTot; }
751 }
752 currentCellData.distElec = Distance_Ele(xPosition,yPosition,currentCellData.phiGap,currentCellData.nstraight,currentCellData.nfold,currentCellData.xl);
753 // ATH_MSG_VERBOSE(" new phiGap,distElec " << currentCellData.phiGap << " " << currentCellData.distElec);
754 }
755 }
756
757 currentCellData.phiBin = (G4int) ( currentCellData.phiGap/sampling_phi_nGaps );
758
759 if (MapDetail) {
760 // compute x0,y0 coordinates in local electrode frame, using closest fold
761 // as reference
762 const G4double alpha = m_coudeelec->PhiRot(currentCellData.nfold,currentCellData.phiGap);
763 const G4double dx=xPosition-m_coudeelec->XCentCoude(currentCellData.nfold,currentCellData.phiGap);
764 const G4double dy=yPosition-m_coudeelec->YCentCoude(currentCellData.nfold,currentCellData.phiGap);
765 const G4double dx1=dx*cos(alpha)-dy*sin(alpha);
766 const G4double dy1=dx*sin(alpha)+dy*cos(alpha);
767 currentCellData.x0 = dx1 + m_xc[currentCellData.nfold];
768 currentCellData.y0 = dy1 + m_yc[currentCellData.nfold];
769 if (m_parity==1) { currentCellData.y0 = -1*currentCellData.y0; }
770 }
771
772
773 } // end of findCell method
774
775 // =============================================================================
776 // initialize phi0 vs radius of first absorber (for gam=0)
778 {
779 const G4double dl=0.001;
780 const G4double inv_dl = 1. / dl;
781 G4double cenx[15],ceny[15];
782 //G4double xl,xl2;
783 std::vector<G4double> sum1(5000);
784 std::vector<G4double> sumx(5000);
785 //xl=0;
786 //xl2=0.;
787 m_NRphi=5000;
788 m_Rmin=1500.;
789 m_dR=0.10;
790 m_Rmax=0.;
791
792 const G4double rint= m_rint_eleFib;
793 const G4double inv_rint = 1. / rint;
794 const G4double dt=dl * inv_rint;
795 const G4double inv_dt = 1. / dt;
796
797 for (G4int i=0;i<m_NRphi;i++) {
798 sum1[i]=0.;
799 sumx[i]=0.;
800 }
801 for (G4int i=0;i<15;i++) {
802 cenx[i]=m_rc[i]*cos(m_phic[i]);
803 ceny[i]=m_rc[i]*sin(m_phic[i]);
804 }
805
806 for (G4int i=0; i<15; i++) {
807
808 // fold
809 G4double phi0,phi1;
810 if (i==0) {
811 // first fold goes up
812 if (m_parity==0) {
813 phi0=-CLHEP::pi/2.;
814 phi1=-m_delta[0];
815 }
816 // first fold goes down
817 else {
818 phi0=m_delta[0];
819 phi1=CLHEP::pi/2;
820 }
821 }
822 else if (i==14) {
823 if (m_parity==0) {
824 phi0=-CLHEP::pi+m_delta[13];
825 phi1=-CLHEP::pi/2.;
826 }
827 else {
828 phi0=CLHEP::pi/2;
829 phi1=CLHEP::pi - m_delta[13];
830 }
831 }
832 else {
833 if (i%2==(1-m_parity)) {
834 phi0=m_delta[i];
835 phi1=CLHEP::pi-m_delta[i-1];
836 }
837 else {
838 phi0=-CLHEP::pi+m_delta[i-1];
839 phi1=-m_delta[i];
840 }
841 }
842 //xl2+=rint*std::fabs(phi1-phi0);
843 const G4int nstep=int((phi1-phi0)*inv_dt)+1;
844 for (int ii=0;ii<nstep;ii++) {
845 //xl+=dl;
846 const G4double phi=phi0+dt*((G4double)ii);
847 const G4double x=cenx[i]+rint*cos(phi);
848 const G4double y=ceny[i]+rint*sin(phi);
849 const G4double radius=sqrt(x*x+y*y);
850 if (radius>m_Rmax) { m_Rmax=radius; }
851 const G4double phid=atan(y/x);
852 const G4int ir=((int) ((radius-m_Rmin)/m_dR) );
853 if (ir>=0 && ir < m_NRphi) {
854 sum1[ir]+=1.;
855 sumx[ir]+=phid;
856 }
857 }
858
859 // straight section
860 if (i<14) {
861 const G4double dx=cenx[i+1]-cenx[i];
862 const G4double dy=ceny[i+1]-ceny[i];
863 const G4double along=std::sqrt(dx*dx+dy*dy-4.*rint*rint);
864 const G4double x0=0.5*(cenx[i+1]+cenx[i]);
865 const G4double y0=0.5*(ceny[i+1]+ceny[i]);
866 const G4double phi = (i%2==m_parity) ? CLHEP::pi/2-m_delta[i] : -CLHEP::pi/2.+m_delta[i];
867 const G4double x1=x0-0.5*along*cos(phi);
868 const G4double y1=y0-0.5*along*sin(phi);
869 //xl2+=along;
870 const int nstep=int(along*inv_dl)+1;
871 for (int ii=0;ii<nstep;ii++) {
872 //xl+=dl;
873 const G4double x=x1+dl*((G4double)ii)*cos(phi);
874 const G4double y=y1+dl*((G4double)ii)*sin(phi);
875 const G4double radius=sqrt(x*x+y*y);
876 if (radius>m_Rmax) { m_Rmax=radius; }
877 const G4double phid=atan(y/x);
878 const G4int ir=((int) ((radius-m_Rmin)/m_dR) );
879 if (ir>=0 && ir < m_NRphi) {
880 sum1[ir]+=1.;
881 sumx[ir]+=phid;
882 }
883 }
884 }
885 }
886 // ATH_MSG_VERBOSE("total electrode length " << xl << " " << xl2);
887 // ATH_MSG_VERBOSE("rmax in accordion " << m_Rmax);
888 for (int i=0; i<m_NRphi; i++) {
889 if (sum1[i]>0) {
890 m_Rphi[i]=sumx[i]/sum1[i];
891 // Not used:
892 //G4double radius = m_Rmin + ((G4double(i))+0.5)*m_dR;
893 //ATH_MSG_VERBOSE(" GUTEST r,phi0 " << radius << " " << m_Rphi[i]);
894 }
895 else { m_Rphi[i]=0.; }
896 }
897 }
898
899 // ======================================================================================
900 // phi of first absorber as function of radius for nominal accordion geometry
901 // (before sagging)
902 G4double Geometry::Phi0(G4double radius) const
903 {
904 // TODO This function could be simplified.
905 G4int ir;
906 if (radius < m_Rmin) { ir=0; }
907 else {
908 if (radius > m_Rmax) radius=m_Rmax-0.0001;
909 ir=((int) ((radius-m_Rmin)/m_dR) );
910 }
911 return m_Rphi[ir];
912 }
913
914 // ======================================================================================
915 // compute number (0 to 1023) of closest electrode according to nominal
916 // accordion geometry
917 G4int Geometry::PhiGap(const double & radius, const double & xhit, const double &yhit) const
918 {
919 const G4double phi0=Phi0(radius)+m_gam0; // from -pi to pi
920 const G4double phi_hit=atan2(yhit,xhit); // from -pi to pi
921 G4double dphi=phi_hit-phi0;
922 // bring back to 0-2pi
923 if (dphi<0) dphi=dphi+2*M_PI;
924 if (dphi>=2*M_PI) dphi=dphi-2*M_PI;
925 dphi=dphi/(2*M_PI)*1024;
926 const G4int ngap=((int) dphi);
927#ifdef DEBUGHITS
928 ATH_MSG_VERBOSE(" phi0 " << phi0 << " dphi, ngap " << dphi << " " << ngap);
929#endif
930 return ngap;
931 }
932
933 //===================================================================================
934 // full cell id computation starting from an arbitrary G4 step
935
937 {
938
939 // The default result is a blank identifier.
941
942 // Get all the required information from the current step
943 const G4NavigationHistory* g4navigation = a_step->GetPreStepPoint()->GetTouchable()->GetHistory();
944 const G4int ndep = g4navigation->GetDepth();
945 bool inSTAC = false;
946 int zside=1;
947 G4int indECAM = -999;
948
949 // Now navigate through the volumes hierarchy
950 for (G4int ii=0;ii<=ndep;ii++) {
951 const G4String& vname = g4navigation->GetVolume(ii)->GetName();
952 // FIXME Need to find a way to avoid these string-comparisons
953 if ( indECAM<0 && vname == m_ecamName ) indECAM=ii;
954 if ( !inSTAC && vname.find("STAC") !=std::string::npos) inSTAC=true;
955 if ( vname.find("NegPhysical") != std::string::npos) zside=-1;
956 }
957 if (indECAM>=0)
958 result = this->CalculateECAMIdentifier( a_step , indECAM, inSTAC, zside) ;
959 else
960 ATH_MSG_ERROR("LArBarrel::Geometry::CalculateIdentifier ECAM volume not found in hierarchy");
961
962 return result;
963 }
964
966
967 LArG4Identifier result;
968
969 // Convert step to local half-barrel coordinates
970 const G4StepPoint *preStep = a_step->GetPreStepPoint();
971 const G4StepPoint *postStep = a_step->GetPostStepPoint();
972 G4ThreeVector midGlobal = (preStep->GetPosition() + postStep->GetPosition()) * 0.5;
973
974 const G4NavigationHistory* g4nav = preStep->GetTouchable()->GetHistory();
975
976 G4int indECAM = -1;
977 const G4int ndep = g4nav->GetDepth();
978
979 for (G4int ii = 0; ii <= ndep; ++ii) {
980 if (g4nav->GetVolume(ii)->GetName() == m_ecamName) {
981 indECAM = ii;
982 break;
983 }
984 }
985
986 if (indECAM == -1) {
987 ATH_MSG_ERROR("ECAM volume not found!");
988 return result;
989 }
990
991 G4AffineTransform localTrans = g4nav->GetTransform(indECAM);
992 G4ThreeVector midLocal = localTrans.TransformPoint(midGlobal);
993
994 double x = midLocal.x(), y = midLocal.y(), z = midLocal.z();
995 double radius = sqrt(x*x + y*y);
996 double eta = midLocal.pseudoRapidity();
997 double phi = midLocal.phi() < 0 ? midLocal.phi() + 2*M_PI : midLocal.phi();
998
999 // --- Find the standard (low-resolution) cell ---
1000 CalcData currentCellData;
1001 bool MapDetail = false;
1002 findCell(currentCellData, x, y, z, radius, eta, phi, MapDetail);
1003
1004 int etaBin = currentCellData.etaBin;
1005 int phiBin = currentCellData.phiBin;
1006 int sampling = currentCellData.sampling;
1007 int region = currentCellData.region;
1008
1009 // --- Compute minimum boundaries (low resolution cell) ---
1010 double eta_min = 0.0;
1011 double delta_eta = 0.025; // default
1012 if (sampling == 1) {
1013 if (region == 0) {
1014 delta_eta = 0.003125;
1015 eta_min = etaBin * delta_eta;
1016 } else {
1017 delta_eta = 0.025;
1018 eta_min = 1.4 + etaBin * delta_eta;
1019 }
1020 } else if (sampling == 2) {
1021 delta_eta = 0.025;
1022 eta_min = etaBin * delta_eta;
1023 } else if (sampling == 3) {
1024 delta_eta = 0.05;
1025 eta_min = etaBin * delta_eta;
1026 }
1027
1028 double phiGranularity = (sampling == 1 && region == 0) ? (2*M_PI/64) : (2*M_PI/256);
1029 double phi_min = phiBin * phiGranularity;
1030
1031 double radius_min = 0.0;
1032 double radius_max = 0.0;
1033
1034 if (sampling == 1) {
1035 radius_min = (etaBin == 0) ? m_rMinAccordion : Rmax1[etaBin - 1];
1036 radius_max = Rmax1[etaBin];
1037 } else if (sampling == 2) {
1038 radius_min = Rmax1[etaBin];
1039 radius_max = Rmax2[etaBin];
1040 } else if (sampling == 3) {
1041 radius_min = Rmax2[etaBin];
1042 radius_max = m_rMaxAccordion;
1043 }
1044
1045 // --- Super-Resolution granularity (bins within cell) ---
1046 const int nBinsEtaSR = m_nBinsEtaSR;
1047 const int nBinsPhiSR = m_nBinsPhiSR;
1048 const int nBinsRadiusSR = m_nBinsRadiusSR;
1049
1050 double delta_eta_SR = delta_eta / nBinsEtaSR;
1051 double delta_phi_SR = phiGranularity / nBinsPhiSR;
1052 double delta_r_SR = (radius_max - radius_min) / nBinsRadiusSR;
1053
1054 auto computeBin = [](double val, double min_lr, double delta_sr, int maxBins) {
1055 const int overflow = maxBins - 1;
1056 if (delta_sr == 0.0) return overflow;
1057 int bin = int((val - min_lr) / delta_sr);
1058 return std::clamp(bin, 0, overflow);;
1059 };
1060
1061 // --- Compute SR bin numbers (local within the cell) ---
1062 int etaBinSR = computeBin(eta, eta_min, delta_eta_SR, nBinsEtaSR);
1063 int phiBinSR = computeBin(phi, phi_min, delta_phi_SR, nBinsPhiSR);
1064 int rBinSR = computeBin(radius, radius_min, delta_r_SR, nBinsRadiusSR);
1065
1066 // Packing (16 bits):
1067 // Bit 15: Marker bit (always 1)
1068 // Bits 9-14 (6 bits): etaBinSR (shifted by 1)
1069 // Bits 3-8 (6 bits): phiBinSR (shifted by 1)
1070 // Bits 0-2 (3 bits): rBinSR (reduced by 1 bit)
1071
1072 unsigned short int packedID = ( 0x8000 ) // Marker bit always set (bit 15)
1073 | ( (etaBinSR & 0x3F) << 9 ) // 6 bits for eta (bits 9-14)
1074 | ( (phiBinSR & 0x3F) << 3 ) // 6 bits for phi (bits 3-8)
1075 | ( rBinSR & 0x07 ); // 3 bits for r (bits 0-2)
1076
1077 // --- Store packedID into LArG4Identifier ---
1078 result << packedID;
1079
1080 return result;
1081 }
1082 //======================================================================================
1083 //
1084 // The following method computes the identifiers in the ECAM volume:
1085 // (including dead material identifier)
1086 //
1087 // 1) Tranformation into LOCAL half barrel frame
1088 //
1089 // 2) Check if the hit is in the fiducial region (EM accordion, no presampler)
1090 // fiducial range: 1500.24 < r < 1960.00 mm
1091 // |eta| < 1.475
1092 // 4 < z < 3164 mm (in local half barrel coordinates)
1093 //
1094 // 3) If the hit is in the fiducial region standard identifier are filled
1095 //
1096 // 4) If the hit is outside the fiduacial region calibration hits are filled
1097 //
1098 // CaloDM_ID identifier for the barrel:
1099 //
1100 // detector_system/subdet/type/sampling/region/eta/phi
1101 //
1102 // * For hits with radius < 1500.24
1103 // ******************************
1104 //
1105 // detector system = 10 -> Calorimeters
1106 // subdet = +/-4 -> LAr dead materials
1107 // type = 1 -> dead materials outside accordion and active presampler layers
1108 // sampling = 1 -> dead materials in front and in active LAr calorimeters (starting from front warm
1109 // cryostat walls)
1110 // regions: = 3 -> all materials from the active layer of the barrel presampler to the active layer
1111 // of accordion, 0 < |eta| < 1.5
1112 //
1113 // ---> Granularity : deta 0.1 granularity within region
1114 // dphi pi/32 ~ 0.1 granularity within region
1115 //
1116 // * For hits with radius > 1960.00
1117 // ******************************
1118 //
1119 // detector system = 10 -> Calorimeters
1120 // subdet = +/-4 -> LAr dead materials
1121 // type = 1 -> dead materials outside accordion and active presampler layers
1122 // sampling = 2 -> dead materials between active LAr calorimeters and Tile calorimeters or HEC-2 wheels
1123 // regions: = 0 -> all materials behind the active layer of accordion in front the Tile barrel
1124 // for |eta| < 1.0
1125 // =2 -> all materials in front of the scintillator and behind the active layer of accordion
1126 // for 1.0 < |eta| < 1.5
1127 //
1128 // ---> Granularity : deta 0.1 granularity within region
1129 // dphi pi/32 ~ 0.1 granularity within region
1130 //
1131 //======================================================================================
1132
1133 LArG4Identifier Geometry::CalculateECAMIdentifier(const G4Step* a_step, const G4int indECAM, const bool inSTAC, int zside) const
1134 {
1135
1137
1138 // Get all the information about the step
1139
1140 const G4StepPoint *thisStepPoint = a_step->GetPreStepPoint();
1141 const G4StepPoint *thisStepBackPoint = a_step->GetPostStepPoint();
1142 const G4ThreeVector startPoint = thisStepPoint->GetPosition();
1143 const G4ThreeVector endPoint = thisStepBackPoint->GetPosition();
1144 const G4ThreeVector p = (thisStepPoint->GetPosition() + thisStepBackPoint->GetPosition()) * 0.5;
1145
1146#ifdef DEBUGHITS
1147 ATH_MSG_VERBOSE("Position of the step in the ATLAS frame (x,y,z) --> " << p.x() << " " << p.y() << " " << p.z());
1148 ATH_MSG_VERBOSE("Eta and Phi in the ATLAS frame --> " << p.eta() << " " << p.phi());
1149#endif
1150
1151 // BACK directly into the LOCAL half_Barrel. All the variables in this LOCAL framework get the SUFFIX Zpos
1152
1153 const G4NavigationHistory* g4navigation = thisStepPoint->GetTouchable()->GetHistory();
1154 const G4AffineTransform transformation = g4navigation->GetTransform(indECAM);
1155 const G4ThreeVector startPointinLocal = transformation.TransformPoint(startPoint);
1156 const G4ThreeVector endPointinLocal = transformation.TransformPoint (endPoint);
1157 const G4ThreeVector midinLocal = (startPointinLocal+endPointinLocal)*0.5;
1158
1159#ifdef DEBUGHITS
1160 ATH_MSG_VERBOSE("Position of the step in the LOCAL frame (x,y,z) --> " << midinLocal.x() << " " << midinLocal.y() << " " << midinLocal.z());
1161 ATH_MSG_VERBOSE("Eta and Phi of the step in LOCAL frame --> " << midinLocal.eta() << " " << midinLocal.phi());
1162#endif
1163
1164 // coordinates in the local frame
1165
1166 const G4double xZpos = midinLocal.x();
1167 const G4double yZpos = midinLocal.y();
1168 const G4double zZpos = midinLocal.z();
1169 const G4double etaZpos = midinLocal.pseudoRapidity();
1170 const G4double phiZpos = (midinLocal.phi()<0.) ? midinLocal.phi() + 2.*M_PI : midinLocal.phi();
1171 const G4double radius2Zpos = xZpos*xZpos + yZpos*yZpos;
1172 const G4double radiusZpos = sqrt(radius2Zpos);
1173
1174 CalcData currentCellData;
1175 if (m_testbeam) {
1176 currentCellData.zSide = 1;
1177 }
1178 else {
1179 currentCellData.zSide = zside;
1180 }
1181
1182 // Check if the hit is in the fiducial range and in the STAC volume
1183 // if yes this is active or inactive material
1184
1185 if (inSTAC && radiusZpos >=m_rMinAccordion && radiusZpos <= m_rMaxAccordion &&
1186 zZpos <= m_zMaxBarrel && zZpos >= m_zMinBarrel && etaZpos <= m_etaMaxBarrel) {
1187
1188#ifdef DEBUGHITS
1189 ATH_MSG_VERBOSE("This hit is in the STAC volume !!!!! ");
1190#endif
1191
1192 // DETERMINATION of currentCellData.cellID,
1193 // currentCellData.zSide, currentCellData.sampling,
1194 // currentCellData.phiBin, currentCellData.etaBin,
1195 // m_stackNumID
1196 const bool MapDetail(false);
1197 this->findCell( currentCellData, xZpos, yZpos, zZpos, radiusZpos, etaZpos, phiZpos, MapDetail );
1198
1199 // adjust phi in the negative half barrel frame
1200
1201 if( currentCellData.zSide == -1 )
1202 {
1203 if( currentCellData.sampling == 1 && currentCellData.region ==0 )
1204 {
1205 currentCellData.phiBin = 31 - currentCellData.phiBin;
1206 if(currentCellData.phiBin < 0 ) currentCellData.phiBin += 64;
1207 }
1208 if( currentCellData.sampling == 1 && currentCellData.region ==1 )
1209 {
1210 currentCellData.phiBin = 127 - currentCellData.phiBin;
1211 if(currentCellData.phiBin < 0 ) currentCellData.phiBin += 256;
1212 }
1213 if( currentCellData.sampling >= 2 )
1214 {
1215 currentCellData.phiBin = 127 - currentCellData.phiBin;
1216 if(currentCellData.phiBin < 0 ) currentCellData.phiBin += 256;
1217 }
1218 }
1219
1220 // there are few hundred microns between the 4mm nominal beginning of the active region
1221 // and the real beginning of the first strip at eta=0.025/8
1222 // to avoid inactive energy with strip=0 assign this to strip=1
1223 if (currentCellData.sampling==1 && currentCellData.region==0 && currentCellData.etaBin==0) {
1224 currentCellData.etaBin=1;
1225 }
1226
1227 result << 4 // LArCalorimeter
1228 << 1 // LArEM
1229 << currentCellData.zSide
1230 << currentCellData.sampling
1231 << currentCellData.region
1232 << currentCellData.etaBin
1233 << currentCellData.phiBin;
1234
1235#ifdef DEBUGHITS
1236 ATH_MSG_VERBOSE("Here the identifier for the barrel ACTIVE ----> ");
1237 ATH_MSG_VERBOSE("eta in local frame --> " << etaZpos);
1238 ATH_MSG_VERBOSE("currentCellData.zSide ----> " << currentCellData.zSide);
1239 ATH_MSG_VERBOSE("currentCellData.sampling ----> " << currentCellData.sampling);
1240 ATH_MSG_VERBOSE("currentCellData.region ----> " << currentCellData.region);
1241 ATH_MSG_VERBOSE("currentCellData.etaBin ----> " << currentCellData.etaBin);
1242 ATH_MSG_VERBOSE("currentCellData.phiBin ----> " << currentCellData.phiBin);
1243 ATH_MSG_VERBOSE("And also etafirst ----> " << thisStepPoint->GetPosition().pseudoRapidity());
1244#endif
1245
1246 // if (!Geometry::CheckLArIdentifier(currentCellData.sampling,currentCellData.region,currentCellData.etaBin,currentCellData.phiBin)) {
1247 // ATH_MSG_ERROR(" ** Bad LAr identifier " << currentCellData.sampling << " " << currentCellData.region << " "
1248 // << currentCellData.etaBin << " " << currentCellData.phiBin);
1249 // ATH_MSG_ERROR(" x,y,z,eta,phi " << xZpos << " " << yZpos << " " << zZpos
1250 // << " " << radiusZpos << " " << etaZpos << " " << phiZpos);
1251 // }
1252
1253
1254 }
1255 // hits in dead material part
1256 else {
1257
1258 G4int sampling=0;
1259 G4int region=0;
1260 const G4int numDeadPhiBins = 64;
1261 double abs_eta = std::fabs(etaZpos);
1262 const double DM1EtaWidth = 0.1 ;
1263 const double DM1PhiWidth = 2.*M_PI / numDeadPhiBins ;
1264 currentCellData.etaBin = (G4int) ( abs_eta * (1./DM1EtaWidth) ) ;
1265 currentCellData.phiBin = (G4int) (phiZpos/ DM1PhiWidth );
1266 G4int type=1;
1267 // protect against rounding error for phi ~2pi
1268 if (currentCellData.phiBin==numDeadPhiBins) currentCellData.phiBin=currentCellData.phiBin-1;
1269
1270 // adjust phi for negative half barrel
1271
1272 if ( currentCellData.zSide == -1 ) {
1273 currentCellData.phiBin = 31 - currentCellData.phiBin;
1274 if (currentCellData.phiBin < 0 ) currentCellData.phiBin +=64 ;
1275 }
1276
1277 // material in front of the active accordion
1278 if ( radiusZpos < m_rMinAccordion ) {
1279 sampling =1 ;
1280 region = 3 ;
1281 if (currentCellData.etaBin > 14) currentCellData.etaBin=14;
1282
1283#ifdef DEBUGHITS
1284 ATH_MSG_VERBOSE("This hit is in the ECAM volume in front of the accordion (DEAD MATERIAL) !!!!! ");
1285#endif
1286
1287 } else if (radiusZpos >= m_rMaxAccordion){ // material behind the active accordion
1288 sampling = 2;
1289
1290 if (abs_eta < 1.0 ) {
1291 region = 0 ;
1292#ifdef DEBUGHITS
1293 ATH_MSG_VERBOSE("This hit is in the ECAM volume behind accordion (DEAD MATERIAL 0) !!!!! ");
1294#endif
1295 } else if ( abs_eta >= 1.0 && abs_eta < 1.5) {
1296 region = 2;
1297 currentCellData.etaBin = currentCellData.etaBin - 10; // to have etabin between 0 and 4
1298#ifdef DEBUGHITS
1299 ATH_MSG_VERBOSE("This hit is in the ECAM volume behind accordion (DEAD MATERIAL 2) !!!!! ");
1300#endif
1301 } else {
1302 ATH_MSG_ERROR(" LArBarrelGeometry: hit behind accordion at eta>1.5 !!! ");
1303 region = 2;
1304 currentCellData.etaBin = 4;
1305 }
1306
1307 } else if (zZpos <= m_zMinBarrel) { // inactive matter between two EMB halves
1308 type=2;
1309 region=0;
1310 const G4int phisave=currentCellData.phiBin;
1311 const G4bool MapDetail(false);
1312 this->findCell( currentCellData, xZpos, yZpos, zZpos, radiusZpos, etaZpos, phiZpos, MapDetail );
1313 sampling = currentCellData.sampling; // sampling as in normal definition
1314 currentCellData.etaBin=0;
1315 currentCellData.phiBin=phisave;
1316
1317 } else if (zZpos >= m_zMaxBarrel - m_zMaxBarrelDMMargin || abs_eta >= 1.40) { // inactive matter between EMB and scintillator including some margin for error
1318 if (abs_eta >1.0 && abs_eta < 1.5) {
1319 sampling=2;
1320 region=2;
1321 currentCellData.etaBin = currentCellData.etaBin - 10; // to have etabin between 0 and 4
1322 } else if (abs_eta < 1.6) {
1323 sampling=1;
1324 region=4;
1325 currentCellData.etaBin=0;
1326 } else {
1327 ATH_MSG_ERROR(" LArBarrelGeometry: hit at eta>1.6 !!! ");
1328 sampling=1;
1329 region=4;
1330 currentCellData.etaBin=0;
1331 }
1332 } else {
1333 if (!m_testbeam) {
1334 const G4double thisStepEnergyDeposit = a_step->GetTotalEnergyDeposit() * a_step->GetTrack()->GetWeight();
1335 std::ostringstream dmLog;
1336 dmLog << "LArBarrelGeometry: cannot find region for DM hit..." << std::endl;
1337 dmLog << "LArBarrelGeometry: cannot find region for DM hit..." << std::endl;
1338 dmLog << "m_zMinBarrel: " << m_zMinBarrel << std::endl;
1339 dmLog << "m_zMaxBarrel: " << m_zMaxBarrel << std::endl;
1340 dmLog << "m_rMinAccordion: " << m_rMinAccordion << std::endl;
1341 dmLog << "m_rMaxAccordion: " << m_rMaxAccordion << std::endl;
1342 dmLog << "r,z,eta,phi " << radiusZpos << " " << zZpos << " " << etaZpos << " " << phiZpos << std::endl;
1343 dmLog << "x,y,z (Atlas) " << p.x() << " " << p.y() << " " << p.z() << std::endl;
1344 dmLog << " inSTAC " << inSTAC << std::endl;
1345 dmLog << " eDeposited " << thisStepEnergyDeposit << std::endl;
1346 const G4VPhysicalVolume* vol = thisStepPoint->GetPhysicalVolume();
1347 const G4String volName = vol->GetName();
1348 dmLog << " volName " << volName << std::endl;
1349 const G4int ndep = g4navigation->GetDepth();
1350 for (G4int ii=0;ii<=ndep;ii++) {
1351 const G4VPhysicalVolume* v1 = g4navigation->GetVolume(ii);
1352 const G4String vname = v1->GetName();
1353 dmLog << "vname " << vname << std::endl;
1354 }
1355 if (thisStepEnergyDeposit > 1.*CLHEP::MeV) {
1356 ATH_MSG_ERROR(dmLog.str());
1357 } else {
1358 ATH_MSG_WARNING(dmLog.str());
1359 }
1360 }
1361 // in test beam case, we can get there for leakage on the side (in phi) of the module
1362 // in this case, we attribute an identifier like inactive material
1363 else
1364 {
1365 G4bool MapDetail=false;
1366 this->findCell( currentCellData, xZpos, yZpos, zZpos, radiusZpos, etaZpos, phiZpos, MapDetail );
1367 // ATH_MSG_ERROR(" Lateral lakage r,eta,phi " << radiusZpos << " " << etaZpos << " "
1368 // << phiZpos << " sampling/region/eta/phi " << currentCellData.sampling << " " <<
1369 // currentCellData.region << " " << currentCellData.etaBin << " " << currentCellData.phiBin);
1370 // protect against small space between z=4m and real beginning of ieta=1 in strips
1371 if (currentCellData.sampling==1 && currentCellData.region==0 && currentCellData.etaBin==0) {
1372 currentCellData.etaBin=1;
1373 // ATH_MSG_ERROR("S1R0 etabin 0 found r,z,phi local " << radiusZpos << " "
1374 // << " " << zZpos << " " << phiZpos);
1375 }
1376 result << 4 // LArCalorimeter
1377 << 1 // LArEM
1378 << currentCellData.zSide
1379 << currentCellData.sampling
1380 << currentCellData.region
1381 << currentCellData.etaBin
1382 << currentCellData.phiBin;
1383 return result;
1384 }
1385 }
1386
1387 result << 10 // LArCalorimeter
1388 << currentCellData.zSide * 4 // LArBarrel
1389 << type
1390 << sampling
1391 << region
1392 << currentCellData.etaBin
1393 << currentCellData.phiBin;
1394
1395#ifdef DEBUGHITS
1396 ATH_MSG_VERBOSE("Here the identifier for the barrel DEAD materials ---->");
1397 ATH_MSG_VERBOSE("Type ----> " << type);
1398 ATH_MSG_VERBOSE("Sampling ----> " << sampling);
1399 ATH_MSG_VERBOSE("Region ----> " << region);
1400 ATH_MSG_VERBOSE("zSide ----> " << currentCellData.zSide*4);
1401 ATH_MSG_VERBOSE("etaBin ----> " << currentCellData.etaBin);
1402 ATH_MSG_VERBOSE("phiBin ----> " << currentCellData.phiBin);
1403#endif
1404
1405 // if (!Geometry::CheckDMIdentifier(type,sampling,region,currentCellData.etaBin,currentCellData.phiBin)) {
1406 // ATH_MSG_ERROR(" ** Bad DM identifier " << type << " " << sampling << " " << region << " "
1407 // << currentCellData.etaBin << " " << currentCellData.phiBin);
1408 // ATH_MSG_ERROR("x,y,z,r,eta,phi" << xZpos << " " << yZpos << " " << zZpos <<
1409 // " " << radiusZpos << " " << etaZpos << " " << phiZpos);
1410 // }
1411
1412 }
1413
1414 return result;
1415
1416 }
1417
1418 bool Geometry::CheckDMIdentifier(int type, int sampling, int region, int eta, int phi) const
1419 {
1420
1421 if (type <1 || type > 2) return false;
1422 if (type==1) {
1423 if (sampling<1 || sampling>2) return false;
1424 if (sampling==1) {
1425 if (region!=3 && region !=4) return false;
1426 if (phi<0 || phi>63) return false;
1427 if (region==3) {
1428 if (eta<0 || eta>14) return false;
1429 }
1430 if (region==4) {
1431 if (eta !=0) return false;
1432 }
1433 }
1434 if (sampling==2) {
1435 if (region !=0 && region !=2) return false;
1436 if (phi<0 || phi>63) return false;
1437 if (region==0){
1438 if (eta<0 || eta>9) return false;
1439 }
1440 if (region==2) {
1441 if (eta<0 || eta>4) return false;
1442 }
1443 }
1444 }
1445 if (type==2) {
1446 if (sampling<1 || sampling >3) return false;
1447 if (region !=0) return false;
1448 if (eta!=0) return false;
1449 if (phi<0 || phi>63) return false;
1450 }
1451 return true;
1452 }
1453
1454
1455 bool Geometry::CheckLArIdentifier(int sampling, int region, int eta, int phi) const
1456 {
1457 if (sampling<0 || sampling >3) return false;
1458 if (sampling==0) {
1459 if (region!=0) return false;
1460 if (eta<0 || eta>60) return false;
1461 if (phi<0 || phi>63) return false;
1462 }
1463 if (sampling==1) {
1464 if (region<0 || region >1) return false;
1465 if (region==0) {
1466 if (eta<1 || eta>447) return false;
1467 if (phi<0 || phi>63) return false;
1468 }
1469 if (region==1) {
1470 if (eta<0 || eta>2) return false;
1471 if (phi<0 || phi>255) return false;
1472 }
1473 }
1474 if (sampling==2) {
1475 if (region<0 || region >1) return false;
1476 if (region==0) {
1477 if (eta<0 || eta>55) return false;
1478 if (phi<0 || phi>255) return false;
1479 }
1480 if (region==1) {
1481 if (eta!=0) return false;
1482 if (phi<0 || phi>255) return false;
1483 }
1484 }
1485 if (sampling==3) {
1486 if (region !=0) return false;
1487 if (eta<0 || eta>26) return false;
1488 if (phi<0 || phi>255) return false;
1489 }
1490 return true;
1491 }
1492
1493 } //end of Barrel namespace
1494
1495} // end of LArG4 namespace
#define M_PI
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
LArGeo::VDetectorParameters LArVG4DetectorParameters
#define y
#define x
#define z
static const LArCoudeAbsorbers * GetInstance(const std::string &strDetector="")
static const LArCoudeElectrodes * GetInstance(const std::string &strDetector="")
virtual LArG4Identifier CalculateIdentifier(const G4Step *) const override final
bool CheckDMIdentifier(int type, int sampling, int region, int eta, int phi) const
Gaudi::Property< std::string > m_detectorName
const LArCoudeAbsorbers * m_coudeabs
Gaudi::Property< int > m_nBinsEtaSR
const LArStraightAbsorbers * m_absorber
Gaudi::Property< int > m_nBinsPhiSR
bool CheckLArIdentifier(int sampling, int region, int eta, int phi) const
G4double Phi0(G4double) const
virtual void initializeForSDCreation() override final
void GetRphi()
phi vs r of first absorber in nominal geometry
double Distance_Ele(const double &x, const double &y, const int &PhiC, int &Num_Straight, const int &Num_Coude, double &xl) const
Gaudi::Property< bool > m_testbeam
Gaudi::Property< int > m_nBinsRadiusSR
const LArCoudeElectrodes * m_coudeelec
const LArStraightElectrodes * m_electrode
virtual StatusCode initialize() override final
G4int PhiGap(const double &, const double &, const double &) const
LArG4Identifier CalculateECAMIdentifier(const G4Step *, const G4int indEcam, const bool inSTAC=true, int zside=1) const
virtual LArG4Identifier CalculateSuperResolutionIdentifier(const G4Step *a_step) const override final
G4int SampSeg(G4double, G4double, G4double, G4int &, G4int &, G4int &, G4int &, G4int &) const
double Distance_Abs(const double &x, const double &y, const int &nabs, const int &Num_Straight, const int &Num_Coude) const
virtual void findCell(CalcData &currentCellData, const double &x, const double &y, const double &z, const double &r, const double &eta, const double &phi, const bool detail) const override final
virtual StatusCode finalize() override final
static const VDetectorParameters * GetInstance()
static const LArStraightAbsorbers * GetInstance(const std::string &strDetector="")
static const LArStraightElectrodes * GetInstance(const std::string &strDetector="")
int ir
counter of the current depth
Definition fastadd.cxx:49
static const G4double Rmax2[56]
maximum values of active S2 region from electrode drawing
static const G4double Rmax1[448]
maximum values of active S1 region from electrode drawing (first eta value checked by D....