ATLAS Offline Software
Loading...
Searching...
No Matches
LArBarrelCalculator.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// The Cell Identifier for the EM Barrel readout cells
6
7// Adapted from code written by Gaston Parrour
8// Adaptation by Sylvain Negroni
9// 17-11-2003: G.Unal cleanup
10// 18-03-2003: G.Unal major revision to use new current maps
11
12// #define DEBUGSTEP
13// #define DEBUGSTEP2
14
15#include "LArBarrelCalculator.h"
16#include "AccMap.h"
17#include "MapEta.h"
18
21
22#include "G4ThreeVector.hh"
23#include "G4StepPoint.hh"
24#include "G4Step.hh"
25#include "G4ios.hh"
26#include "G4AffineTransform.hh"
27#include "G4NavigationHistory.hh"
28#include "G4VTouchable.hh"
29#include "G4TouchableHistory.hh"
30
31#include <cmath>
32#include <iostream>
33
34#include "GaudiKernel/ISvcLocator.h"
35#include "GaudiKernel/Bootstrap.h"
37#include "AthenaKernel/Units.h"
38
39#include "LArHV/LArHVManager.h"
40#include "LArHV/EMBHVManager.h"
41#include "LArHV/EMBHVModule.h"
43
44namespace Units = Athena::Units;
45
46// ================================================================================
47LArBarrelCalculator::LArBarrelCalculator(const std::string& name, ISvcLocator* pSvcLocator)
48 : LArCalculatorSvcImp(name, pSvcLocator)
49{
50}
51
53{
54 ATH_MSG_DEBUG("LArBarrelCalculator: Beginning initialization ");
55 if (m_BirksLaw) {
56 const double Birks_LAr_density = 1.396;
57 ATH_MSG_INFO("Use Birks_LAr_density="<<Birks_LAr_density<<", Birksk="<<(double)m_Birksk);
58 m_birksLaw = new LArG4BirksLaw(Birks_LAr_density,m_Birksk);
59 }
60
61 // Access source of detector parameters.
63
64 // Get the out-of-time cut from the detector parameters routine.
65 m_OOTcut = parameters->GetValue("LArExpHallOutOfTimeCut"); //FIXME should be done via configurables
66 ATH_MSG_DEBUG("**** OutOfTime cut " << m_OOTcut);
67
68 // Main Barrel parameters
69 // All the UNITS are implicitly the GEANT4 ONES e.g. mm, rad, etc ...
70 m_etaMaxBarrel = parameters->GetValue("LArEMBMaxEtaAcceptance");
71 m_zMinBarrel = parameters->GetValue("LArEMBfiducialMothZmin");
72 m_zMaxBarrel = parameters->GetValue("LArEMBfiducialMothZmax");
73 m_NCellMax = (int) (parameters->GetValue("LArEMBnoOFPhysPhiCell"));
74 m_rMinAccordion = parameters->GetValue("LArEMBRadiusInnerAccordion");
75 m_rMaxAccordion = parameters->GetValue("LArEMBFiducialRmax");
76
77 // absorbers and electrodes thickness
78 m_ThickAbs = 0.5*( parameters->GetValue("LArEMBThickAbsGlue")
79 +parameters->GetValue("LArEMBThickAbsIron")
80 +parameters->GetValue("LArEMBThickAbsLead"));
81
82 G4double check = 0.5*( parameters->GetValue("LArEMBThinAbsGlue")
83 +parameters->GetValue("LArEMBThinAbsIron")
84 +parameters->GetValue("LArEMBThinAbsLead"));
85
86 if (fabs(check-m_ThickAbs)>0.001)
87 {
88 ATH_MSG_WARNING("Thin and Thick Abs have difference thickness!");
89 }
90
91 m_ThickEle= 0.5*( parameters->GetValue("LArEMBThickElecCopper")
92 +parameters->GetValue("LArEMBThickElecKapton"));
93
94 // === GU 11/06/2003 total number of cells in phi
95 // to distinguish 1 module (testbeam case) from full Atlas
96 m_NCellTot = (int) (parameters->GetValue("LArEMBnoOFPhysPhiCell"));
97 if (m_NCellTot != 1024)
98 {
99 m_NCellMax=1024;
100 m_testbeam=true;
101 }
102 // ===
103 // access geometry computation class
104 ATH_CHECK(m_geometry.retrieve());
105
106 // access current maps if required
107 if (m_IflCur)
108 {
109 ATH_MSG_DEBUG(" LArBarrelCalculator: start reading of current maps");
111 m_etamap1 = std::make_unique<MapEta>(1);
112 m_etamap2 = std::make_unique<MapEta>(2);
113 if (m_IflMapTrans) m_etamap3 = std::make_unique<MapEta>(3);
114 ATH_MSG_DEBUG(" LArBarrelCalculator: end of reading current maps");
115 }
116 // Initialize HV values
117 this->InitHV();
118
119 ATH_MSG_DEBUG(" LArBarrelCalculator: s_NCellMax " << m_NCellMax);
120 ATH_MSG_DEBUG(" LArBarrelCalculator: s_NCellTot " << m_NCellTot);
121 ATH_MSG_DEBUG(" LArBarrelCalculator: s_rMinAccordion " << m_rMinAccordion);
122 ATH_MSG_DEBUG(" LArBarrelCalculator: s_rMaxAccordion " << m_rMaxAccordion);
123 ATH_MSG_DEBUG(" LArBarrelCalculator: s_zMinBarrel " << m_zMinBarrel);
124 ATH_MSG_DEBUG(" LArBarrelCalculator: s_zMaxBarrel " << m_zMaxBarrel);
125 ATH_MSG_DEBUG(" LArBarrelCalculator: s_etaMaxBarrel " << m_etaMaxBarrel);
126 ATH_MSG_DEBUG(" LArBarrelCalculator: s_ThickAbs " << m_ThickAbs);
127 ATH_MSG_DEBUG(" LArBarrelCalculator: s_ThickEle " << m_ThickEle);
128 if(m_IflCur) ATH_MSG_DEBUG(" LArBarrelCalculator: Deposited Energy dE/dX Corrected ==> CURRENT Option ON");
129 else ATH_MSG_DEBUG(" LArBarrelCalculator: Crude Deposited Energy dE/dX NO CURRENT option");
130 if (m_IflCur && m_IflMapTrans) ATH_MSG_DEBUG(" LArBarrelCalculator: Compute effect of E field around eta=0.8 ");
131 else ATH_MSG_DEBUG(" LArBarrelCalculator: Ignore effect of E field around eta=0.8 ");
132 if(m_BirksLaw)
133 {
134 ATH_MSG_DEBUG(" LArBarrelCalculator: Birks' law ON ");
135 ATH_MSG_DEBUG(" LArBarrelCalculator: parameter k " << m_birksLaw->k());
136 }
137 else
138 {
139 ATH_MSG_DEBUG(" LArBarrelCalculator: Birks' law OFF");
140 }
141
142 return StatusCode::SUCCESS;
143}
144
145// ============================================================================
147{
148 if (m_BirksLaw) delete m_birksLaw;
149 return StatusCode::SUCCESS;
150}
151
152// =============================================================================
153G4bool LArBarrelCalculator::Process(const G4Step* step, std::vector<LArHitData>& hdata) const
154{
155
156 hdata.clear();
157
158 LArG4Identifier identifier2;
159 LArG4Identifier identifier_xt1;
160 LArG4Identifier identifier_xt2;
161
162 // check the Step content is non trivial
163 G4double thisStepEnergyDeposit = step->GetTotalEnergyDeposit() * step->GetTrack()->GetWeight();
164 G4double thisStepLength = step->GetStepLength() / Units::mm;
165
166#ifdef DEBUGSTEP
167 ATH_MSG_DEBUG("****** LArBarrelCalculator: Step energy,length "
168 << thisStepEnergyDeposit << " " << thisStepLength);
169#endif
170
171 if(thisStepEnergyDeposit <= 0. || thisStepLength <= 0.)
172 {
173#ifdef DEBUGSTEP2
174 ATH_MSG_DEBUG(" Invalid hit trivial content");
175#endif
176 return false;
177 }
178
179 // Get Step geometrical parameters (first and end)
180 G4StepPoint *thisStepPoint = step->GetPreStepPoint();
181 G4StepPoint *thisStepBackPoint = step->GetPostStepPoint();
182 G4ThreeVector startPoint = thisStepPoint->GetPosition();
183 G4ThreeVector endPoint = thisStepBackPoint->GetPosition();
184
185#ifdef DEBUGSTEP
186 ATH_MSG_DEBUG(" Beginning step position "
187 << startPoint.x() << " " << startPoint.y() << " " << startPoint.z());
188#endif
189
190 // find zside from volume name
191 G4int zSide = 1;
192 if (!m_testbeam) {
193 const G4NavigationHistory* g4navigation = thisStepPoint->GetTouchable()->GetHistory();
194 G4int ndep = g4navigation->GetDepth();
195 for (G4int ii=0;ii<=ndep;ii++) {
196 G4VPhysicalVolume* v1 = g4navigation->GetVolume(ii);
197 G4String vname = v1->GetName();
198 if ( vname.find("NegPhysical") != std::string::npos) zSide=-1;
199 }
200 }
201
202
203 // BACK directly into the LOCAL half_Barrel Z > 0. PART (mother "stac_phys1")
204
205 const G4AffineTransform transformation =
206 thisStepPoint->GetTouchable()->GetHistory()->GetTopTransform();
207
208 G4ThreeVector startPointinLocal =
209 transformation.TransformPoint(startPoint);
210 G4ThreeVector endPointinLocal =
211 transformation.TransformPoint (endPoint);
212
213#ifdef DEBUGSTEP
214 ATH_MSG_DEBUG(" Local beginning step position "
215 << startPointinLocal.x() << " " << startPointinLocal.y() << " "
216 << startPointinLocal.z());
217 ATH_MSG_DEBUG(" Local end step position "
218 << endPointinLocal.x() << " " << endPointinLocal.y() << " "
219 << endPointinLocal.z());
220#endif
221
222 G4double energy = step->GetTotalEnergyDeposit() * step->GetTrack()->GetWeight(); // Despite the name, this is only ionization.
223
224 if (m_BirksLaw) {
225 const double EField = 10.; // kV/cm, assume constant for now
226 const double wholeStepLengthCm = step->GetStepLength() / CLHEP::cm;
227 energy = (*m_birksLaw)(energy, wholeStepLengthCm, EField);
228 }
229
230
231 // compute number of sub steps
232 // = 1 if no charge collection
233 // otherwise 200 microns (dstep) division
234
235 G4int nsub_step=1;
236 if (m_IflCur) nsub_step=(int) (thisStepLength/m_dstep) + 1;
237 // delta is fraction of step between two sub steps
238 G4double delta=1./((double) nsub_step);
239#ifdef DEBUGSTEP
240 ATH_MSG_DEBUG(" nsub_step,delta " << nsub_step << " " << delta);
241#endif
242
243 energy /= ((float) (nsub_step)); // Divide into substeps.
244
245 // loop over sub steps
246
247 for (G4int i=0;i<nsub_step;i++) {
248
249 bool Xtalk = false;
250
251 G4double fraction=(((G4double) i)+0.5)*delta;
252 G4ThreeVector subinLocal=startPointinLocal*(1-fraction) + endPointinLocal*fraction;
253 G4double xloc = subinLocal.x();
254 G4double yloc = subinLocal.y();
255 G4double zloc = subinLocal.z();
256 G4double etaloc = subinLocal.pseudoRapidity();
257 G4double philoc = subinLocal.phi();
258 if(philoc<0.) philoc = philoc + 2.*M_PI;
259 G4double radloc = sqrt( xloc*xloc + yloc*yloc );
260#ifdef DEBUGSTEP
261 ATH_MSG_DEBUG(" local position sub_step "
262 << xloc << " " << yloc << " " << zloc);
263#endif
264
265 // apply fiducial cuts
266 if (!FiducialCuts(radloc,zloc,etaloc)) {
267#ifdef DEBUGSTEP
268 ATH_MSG_DEBUG("LArBarrelCalculator: outside fiducial cuts");
269#endif
270 continue;
271 }
272 LArG4::Barrel::CalcData currentCellData;
273 m_geometry->findCell(currentCellData,xloc,yloc,zloc,radloc,etaloc,philoc,m_IflCur);
274
275 if (currentCellData.cellID == 0)
276 {
277#ifdef DEBUGSTEP
278 ATH_MSG_DEBUG("LArBarrelCalculator: Invalid hit CELLID == 0 ");
279 ATH_MSG_DEBUG("x,y,z local " << xloc << " " << yloc << " " << zloc);
280 ATH_MSG_DEBUG("radius " << radloc <<" etaloc "<< etaloc << " philoc " << philoc);
281#endif
282 continue;
283 }
284 G4int region = currentCellData.region;
285 G4int etaBin = currentCellData.etaBin;
286 G4int phiBin = currentCellData.phiBin;
287 G4int sampling = currentCellData.sampling;
288
289 if( zSide == -1 )
290 {
291 // following code for an Y-axis rotation to define Z < 0. Barrel part
292 if( sampling == 1 && region ==0 )
293 {
294 phiBin = 31 - phiBin;
295 if(phiBin < 0 ) phiBin += 64;
296 }
297 if( sampling == 1 && region ==1 )
298 {
299 phiBin = 127 - phiBin;
300 if(phiBin < 0 ) phiBin += 256;
301 }
302 if( sampling >= 2 )
303 {
304 phiBin = 127 - phiBin;
305 if(phiBin < 0 ) phiBin += 256;
306 }
307 }
308#ifdef DEBUGSTEP
309 ATH_MSG_DEBUG(" region,side,sampling,eta,phi " << region << " " << zSide << " "
310 << sampling << " " << etaBin << " " << phiBin);
311 ATH_MSG_DEBUG(" distance to electrode,abs " << currentCellData.distElec << " "
312 << currentCellData.distAbs);
313 ATH_MSG_DEBUG(" local coordinates " << currentCellData.x0 << " " << currentCellData.y0);
314#endif
315
316 if (std::fabs(currentCellData.distElec)< m_ThickEle ||
317 std::fabs(currentCellData.distAbs) < m_ThickAbs) {
318#ifdef DEBUGSTEP
319 ATH_MSG_DEBUG(" hit in absorber or electrode radius:" << radloc);
320#endif
321 continue;
322 }
323
324 identifier2.clear();
325 identifier2 << 4 // LArCalorimeter
326 << 1 // LArEM
327 << zSide
328 << sampling
329 << region
330 << etaBin
331 << phiBin;
332
333 // time computation is not necessarily correct for test beam
334 // G4double time;
335 // if (m_testbeam)
336 // {
337 // time=0.;
338 // }
339 // else
340 // {
341 // const G4double tof = thisStepPoint->GetGlobalTime() / Units::ns;
342 // time = tof - ( thisStepPoint->GetPosition().mag()/CLHEP::c_light ) / Units::ns;
343 // }
344
345 const G4double time = (m_testbeam)? 0.0 :
346 ( thisStepPoint->GetGlobalTime() - ( thisStepPoint->GetPosition().mag()/CLHEP::c_light ) ) / Units::ns;
347
348#ifdef DEBUGSTEP
349 ATH_MSG_DEBUG(" Energy for sub step " << energy);
350#endif
351
352 G4double Current;
353 G4double Current_xt1,Current_xt2;
354 Current_xt1=0;
355 Current_xt2=0;
356 if (!m_IflCur) {
357 // no charge collection Current=E from Geant
358 Current=energy;
359 }
360 else {
361 // full charge collection
362 G4double xmap,ymap;
363 G4int nfold = currentCellData.nfold;
364 G4double x0=currentCellData.x0;
365 G4double y0=currentCellData.y0;
366 if (x0<1500 || x0>1960 || y0>30 || y0<-30) {
367 ATH_MSG_WARNING("weird x0,y0 " << x0 << " " << y0);
368 }
369#ifdef DEBUGSTEP
370 G4double rr = sqrt(x0*x0+y0*y0);
371 ATH_MSG_DEBUG(" radius,rad0 " << radloc << " " << rr);
372#endif
373 const CurrMap* mapOfCurrent(nullptr);
374 bool UseFold=false;
375 // Are we close to a fold ? (fold 0 has some pathology)
376 if ((x0 > m_accmap->GetXmin(nfold) || nfold==0) &&
377 x0 < m_accmap->GetXmax(nfold) &&
378 y0 > m_accmap->GetYmin(nfold) &&
379 y0 < m_accmap->GetYmax(nfold) &&
380 (nfold != 13 || x0 < 1957.5) &&
381 (nfold>0 || x0 < 1504.6) ) {
382 xmap=x0;
383 ymap=y0;
384#ifdef DEBUGSTEP
385 ATH_MSG_DEBUG(" Map for fold xmap,ymap " << nfold << " " << xmap << " " << ymap);
386#endif
387 UseFold=true;
388 G4int sampMap = currentCellData.sampMap;
389 G4int etaMap = currentCellData.etaMap;
390 mapOfCurrent = m_accmap->GetMap(nfold,region,sampMap,etaMap);
391 // catch problem to find map
392 if (!mapOfCurrent) {
393 ATH_MSG_WARNING(" Problem to access map fold = " << nfold);
394 ATH_MSG_WARNING(" region,sampling,eta,fold " << region << " " << sampMap << " "
395 << etaMap << " " << nfold);
396 return false;
397 }
398 }
399 else {
400 G4int n;
401 G4int nstraight = currentCellData.nstraight;
402 if (nstraight%2==0) n=22;
403 else n=21;
404 mapOfCurrent = m_accmap->GetMap(n,region,sampling,etaBin);
405 // catch problem to find map
406 if (!mapOfCurrent) {
407 ATH_MSG_WARNING(" Problem to access map straight = " << nstraight);
408 return false;
409 }
410 xmap = currentCellData.xl;
411 ymap = currentCellData.distElec;
412 // special case for first straight section, which is shorter
413 if (nstraight==0) xmap = 0.5*(xmap+1.);
414#ifdef DEBUGSTEP
415 ATH_MSG_DEBUG(" Map for straight xl,delec " << xmap << " " << ymap);
416#endif
417 } // fold or straight
418 double gap;
419 double current0,current1,current2;
420 // get current for elementary charge
421 mapOfCurrent->GetAll(xmap,ymap,&gap,&current0,&current1,&current2);
422 G4double gap2=std::fabs(currentCellData.distElec)+std::fabs(currentCellData.distAbs)
424
425 // in which HV cell are we ?
426 int ipm,ielec,ieta,iside;
427 if (zSide==1) ipm=1; // A side
428 else ipm=0; // C side
429 ielec=currentCellData.phiGap;
430 if (zSide==-1) {
431 ielec = 511 - ielec;
432 if(ielec < 0 ) ielec += 1024;
433 }
434 ieta=((int) (etaloc*(1./0.2)));
435 if (ieta>6) ieta=6; //part 1.4 to 1.475 is same HV as 1.2 to 1.4
436 iside=0; // phi lower than electrode 0, 1 for phi higher than electrode
437 if ((currentCellData.distElec>0 && zSide==1)
438 || (currentCellData.distElec<0 && zSide==-1) ) iside=1;
439
440 // HV extrapolation
441 double current;
442 double hv=m_hv[ipm][ielec][ieta][iside];
443 if (hv>1995.) current=current0;
444 else if (hv>5.) current=ScaleHV(hv,current0,current1,current2);
445 else current=0.;
446
447 // extrapolation for non nominal gap (allows to include sagging effect)
448 // i ~ (gap/gap2)**1.3
449 // gap = nominal gap from current map
450 // gap2 = real gap from geometry
451 // dgap = gap/gap2 -1
452 // at first order i ~ (1+1.3*dgap)
453 double dgap=0;
454 if (gap>1e-3 && gap2 >1e-3) dgap=gap/gap2-1;
455 current = current * (1. + 1.3*dgap);
456
457#ifdef DEBUGSTEP
458 ATH_MSG_DEBUG(" elementary current " << current0);
459 ATH_MSG_DEBUG(" Gap from Map/calculator " << gap << " " << gap2);
460#endif
461
462 Current = energy*current;
463
464 // check if pathology...
465 if (!UseFold && std::fabs(currentCellData.distElec)>2.1 && current0 < 0.1) {
466 ATH_MSG_WARNING(" xl,distEle " << currentCellData.xl << " "
467 << currentCellData.distElec
468 << " str number " << currentCellData.nstraight
469 << " sampling,eta " << sampling << " " << etaBin << " "
470 << " current/E " << current0);
471 }
472
473 // compute effect around transition at eta=0.8 from electric field
474 // read from map weighting factor ( E**1.3 = E*E**0.3)
475 // in x +-9mm around transition (assume symmetry around 0)
476 // in y distance from electrode in gap
477 bool InTrans=false;
478 //double Current_test=Current;
479 if (m_IflMapTrans) {
480 float etaTrans=0.8;
481 if (fabs(etaloc-etaTrans) < 0.025) {
482 double x=std::fabs(zloc-radloc*sinh(etaTrans))/cosh(etaTrans);
483 double y=std::fabs(currentCellData.distElec);
484 if ( x < m_etamap3->Xmax() ) {
485 double resp;
486 m_etamap3->GetData0(x,y,&resp);
487 Current = Current*resp;
488 InTrans=true;
489 }
490 } // eta = 0.8 +- 0.025
491 } // if m_IflMapTrans
492
493 // simulate cross-talk effects and transitions in eta between cells
494 // (only in region 0, samplings 1 and 2)
495
496 if (region==0) {
497
498 double resp,xt0,xt1,xt2,deta;
499 if (sampling==1) {
500 deta=etaloc-0.003125*((double)etaBin+0.5);
501 m_etamap1->GetData(std::fabs(deta),std::fabs(currentCellData.distElec),
502 &resp,&xt0,&xt1,&xt2);
503#ifdef DEBUGSTEP
504 ATH_MSG_DEBUG("hit in strip etaloc,etaBin,deta,delec,resp,xt0,xt1,xt2 "
505 << etaloc << " " << etaBin << " " << deta*1000 << " " << currentCellData.distElec
506 << " " << resp << " " << xt0 << " " << xt1 << " " << xt2);
507#endif
508 if (!InTrans) Current = Current*resp;
509 if (m_IflXtalk && etaBin > 1 && etaBin < 446) {
510 Xtalk=true;
511 if (deta>0) {
512 identifier_xt1.clear();
513 identifier_xt1 << 4 << 1 << zSide << sampling << region << (etaBin+1) << phiBin;
514 Current_xt1 = Current*xt1;
515 identifier_xt2.clear();
516 identifier_xt2 << 4 << 1 << zSide << sampling << region << (etaBin-1) << phiBin;
517 Current_xt2 = Current*xt2;
518 }
519 else {
520 identifier_xt1.clear();
521 identifier_xt1 << 4 << 1 << zSide << sampling << region << (etaBin-1) << phiBin;
522 Current_xt1 = Current*xt1;
523 identifier_xt2.clear();
524 identifier_xt2 << 4 << 1 << zSide << sampling << region << (etaBin+1) << phiBin;
525 Current_xt2 = Current*xt2;
526 }
527 Current = Current*xt0;
528 } // m_IflXtalk = true
529 }
530 else if (sampling==2 && !InTrans) {
531 deta=etaloc-0.025*((double)etaBin+0.5);
532 m_etamap2->GetData0(std::fabs(deta),std::fabs(currentCellData.distElec),
533 &resp);
534#ifdef DEBUGSTEP
535 ATH_MSG_DEBUG("hit in middle etaloc,etaBin,deta,delec,resp,xt0,xt1,xt2 "
536 << etaloc << " " << etaBin << " " << deta*1000 << " " << currentCellData.distElec
537 << " " << resp);
538#endif
539 Current = Current*resp;
540 } // sampling =1 or 2
541
542 } // region=0
543
544 } // switch for current simulation
545
546
547 // check if we have a new hit in a different cell, or if we add this substep
548 // to an already existing hit
549 G4bool found=false;
550 for (unsigned int i=0; i<hdata.size(); i++) {
551 if (hdata[i].id==identifier2) {
552 hdata[i].energy += Current;
553 hdata[i].time += time*Current;
554 found=true;
555 break;
556 }
557 } // loop over hits
558 if (!found) {
559 hdata.emplace_back(LArHitData{identifier2, time*Current, Current});
560 } // hit was not existing before
561
562 if (Xtalk) {
563 for (unsigned int i=0; i<hdata.size(); i++) {
564 if (hdata[i].id==identifier_xt1) {
565 hdata[i].energy += Current_xt1;
566 hdata[i].time += time*Current_xt1;
567 found=true;
568 break;
569 }
570 } // loop over hits
571 if (!found) {
572 hdata.emplace_back(LArHitData{identifier_xt1, time*Current_xt1, Current_xt1});
573 }
574 found=false;
575 for (unsigned int i=0; i<hdata.size(); i++) {
576 if (hdata[i].id==identifier_xt2) {
577 hdata[i].energy += Current_xt2;
578 hdata[i].time += time*Current_xt2;
579 found=true;
580 break;
581 }
582 } // loop over hits
583 if (!found) {
584 hdata.emplace_back(LArHitData{identifier_xt2, time*Current_xt2, Current_xt2});
585 }
586 } // Xtalk true
587
588
589 } // *** End of loop over sub steps
590
591#ifdef DEBUGSTEP
592 ATH_MSG_DEBUG("Number of hits for this step " << m_nhits << " "
593 << hdata.size());
594#endif
595
596 // finalise time computations
597 for (unsigned int i=0;i<hdata.size();i++) {
598 if (std::fabs(hdata[i].energy)>1e-6) hdata[i].time=hdata[i].time/hdata[i].energy;
599 else hdata[i].time=0.;
600#ifdef DEBUGSTEP
601 ATH_MSG_DEBUG("Hit Energy/Time "
602 << hdata[i].energy << " " << hdata[i].time);
603#endif
604 }
605
606 if (hdata.size()>0) return true;
607 return false;
608}
609
610// ===============================================================================
611// Cuts to define active region of accordion calorimeter
612// 1500.024 < r < 1960.00 mm
613// |eta| < 1.475
614// 4 < z < 3164 mm (in local half barrel coordinates)
615
616G4bool LArBarrelCalculator::FiducialCuts(G4double radloc,G4double zloc,G4double etaloc) const
617{
618 if (radloc < m_rMinAccordion ||
619 radloc > m_rMaxAccordion ||
620 etaloc > m_etaMaxBarrel ||
621 zloc < m_zMinBarrel ||
622 zloc > m_zMaxBarrel) return false;
623 else return true;
624}
625
626// ==========================================================================
627// HV values
628// set all to 2000V. This should be changed if one wants to simulate
629// some HV imperfections
631{
632 ATH_MSG_DEBUG(" **** in LArBarrelCalculator::InitHV() ");
633
634
635
636
637 float defaultHvVal=2000.;
638 ATH_MSG_DEBUG(" defaultHvVal " << defaultHvVal);
639 for (int ipm=0;ipm<2;ipm++) {
640 for (int ielec=0;ielec<1024;ielec++) {
641 for (int ieta=0;ieta<7;ieta++) {
642 for (int iside=0;iside<2;iside++) {
643 m_hv[ipm][ielec][ieta][iside] = defaultHvVal;
644 }
645 }
646 }
647 }
648
649 if (m_doHV) {
650 // initialize services
651 SmartIF<StoreGateSvc> pDetStore{Gaudi::svcLocator()->service("DetectorStore")};
652 if (!pDetStore) {
653 ATH_MSG_WARNING("LArBarrelCalculator::InitHV() unable to get Detector Store! Use default HV values.");
654 return;
655 }
656
657 // get EMBHV Manager
658 const LArHVManager *manager = nullptr;
659 if (pDetStore->retrieve(manager)==StatusCode::SUCCESS) {
660 const EMBHVManager& hvManager=manager->getEMBHVManager();
661 const EMBHVManager::EMBHVData hvdata = hvManager.getDataSim();
662 ATH_MSG_DEBUG(" got HV Manager ");
663 // loop over HV modules
664 for (unsigned int iSide=0;iSide<2;iSide++) {
665 for (unsigned int iPhi=0;iPhi<16;iPhi++) {
666 for (unsigned int iSector=0;iSector<2;iSector++) {
667 for (unsigned int iEta=0;iEta<7;iEta++) {
668 const EMBHVModule& hvMod = hvManager.getHVModule(iSide,iEta+1,iPhi,iSector);
669 for (unsigned int ielec=0;ielec<32;ielec++) {
670 const EMBHVElectrode& electrode = hvMod.getElectrode(ielec);
671 unsigned jElec = ielec+32*iSector+64*iPhi;
672 for (unsigned int iGap=0;iGap<2;iGap++) {
673 double hv = hvdata.voltage (electrode, iGap);
674 ATH_MSG_DEBUG(" iSide,jElec,iEta,iGap,hv " << iSide << " " << jElec << " " << iEta << " " << iGap << " " << hv);
675 if (hv>-999.) m_hv[iSide][jElec][iEta][iGap] = hv;
676 }
677 }
678 }
679 }
680 }
681 }
682 }
683 else {
684 ATH_MSG_WARNING(" Unable to find HV Manager ");
685 }
686 }
687
688 return;
689}
690
691//==========================================================================
692// extrapolate response with HV
693// hv = actual HV
694// curr0 = response for 2000V, curr1 = for 1000V, curr2 for 400V
695// assumes resp = a* HV*b between 1000-2000 and 400-1000V
696// (fixes b=0.57 for HV smaller than 400V)
697
698double LArBarrelCalculator::ScaleHV(double hv, double curr0, double curr1, double curr2) const
699{
700 double b;
701 double resp=0.;
702 if (hv>1000.) {
703 if (std::fabs(curr1)>1e-6) {
704 double x=curr0/curr1;
705 if (x>1e-6) {
706 b=log(x)*(1./(log(2000.)-log(1000.)));
707 resp = curr0*exp(b*(log(hv)-log(2000.)));
708 }
709 }
710 }
711 else if (hv>400.) {
712 if (std::fabs(curr2)>1e-6) {
713 double x=curr1/curr2;
714 if (x>1e-6) {
715 b=log(x)*(1./(log(1000.)-log(400.)));
716 resp = curr1*exp(b*(log(hv)-log(1000.)));
717 }
718 }
719 }
720 else {
721 if (std::fabs(curr2)>1e-6) {
722 b=0.57;
723 resp = curr2*exp(b*(log(hv)-log(400.)));
724 }
725 }
726 return resp;
727}
const boost::regex rr(r_r)
#define M_PI
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
LArGeo::VDetectorParameters LArVG4DetectorParameters
Wrapper to avoid constant divisions when using units.
#define y
#define x
static const AccMap * GetAccMap()
Definition AccMap.cxx:72
void GetAll(double x, double y, double *gap, double *curr0, double *curr1, double *curr2) const
Definition CurrMap.cxx:93
double voltage(const EMBHVElectrode &electrode, const int &iGap) const
This class provides direct access to information on the HV electrodes within the barrels.
const EMBHVModule & getHVModule(unsigned int iSide, unsigned int iEta, unsigned int iPhi, unsigned int iSector) const
EMBHVData getDataSim() const
Describes one HV Module within the EMB.
Definition EMBHVModule.h:20
const EMBHVElectrode & getElectrode(unsigned int iElectrode) const
const LArG4BirksLaw * m_birksLaw
Gaudi::Property< bool > m_IflXtalk
virtual StatusCode finalize() override final
Gaudi::Property< bool > m_doHV
virtual G4bool Process(const G4Step *a_step, std::vector< LArHitData > &hdata) const override final
Gaudi::Property< bool > m_IflCur
ServiceHandle< ILArBarrelGeometry > m_geometry
double ScaleHV(double, double, double, double) const
std::unique_ptr< MapEta > m_etamap1
double m_hv[2][1024][7][2]
virtual StatusCode initialize() override final
G4bool FiducialCuts(G4double, G4double, G4double) const
Gaudi::Property< double > m_dstep
std::unique_ptr< MapEta > m_etamap2
LArBarrelCalculator(const std::string &name, ISvcLocator *pSvcLocator)
std::unique_ptr< MapEta > m_etamap3
Gaudi::Property< bool > m_IflMapTrans
Gaudi::Property< bool > m_BirksLaw
LArCalculatorSvcImp(const std::string &name, ISvcLocator *pSvcLocator)
Gaudi::Property< double > m_OOTcut
Gaudi::Property< double > m_Birksk
static const VDetectorParameters * GetInstance()
This class provides access to the High Voltage throughout the LAr.