ATLAS Offline Software
LArHVScaleCorrTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #include "LArHVScaleCorrTool.h"
6 #include "CaloDetDescr/CaloDetDescrElement.h"
8 #include "CLHEP/Units/SystemOfUnits.h"
9 
10 #include <cmath>
11 
12 using CLHEP::microsecond;
13 using CLHEP::second;
14 
15 LArHVScaleCorrTool::LArHVScaleCorrTool(const CaloCell_ID* calocell_id, MsgStream& msg,
16  const std::vector<std::string>& fixHVStrings) :
17  m_larem_id(calocell_id->em_idHelper()),
18  m_larhec_id(calocell_id->hec_idHelper()),
19  m_larfcal_id(calocell_id->fcal_idHelper()),
20  m_T0(90.371)
21 {
22  buildFixHVList(fixHVStrings, msg);
23 }
24 
25 
27  MsgStream& msg) const {
28 
29  double d=.2; // nominal gap in cm
30  double nominal=2000.; // nominal HV in Volts
31  double T=88.; // temperature in Kelvin
32 
33  bool isbarrelEM=false;
34  bool isFCAL1=false;
35 
36  unsigned int subdet=99;
37  unsigned int layer=99;
38 
39  const Identifier offid=calodde->identify();
40  const float eta_raw = calodde->eta_raw();
41  const float phi_raw = calodde->phi_raw();
42 
43 
44  // EM calorimeter
45  if (m_larem_id->is_lar_em(offid)) {
46  // barrel
47  if (abs(m_larem_id->barrel_ec(offid))==1) {
48  subdet=0;
49  layer = m_larem_id->sampling(offid);
50  // EMB
51  if (m_larem_id->sampling(offid)>0) {
52  d=0.209;
53  nominal=2000.;
54  T=88.37;
55  isbarrelEM=true;
56  }
57  // EMBPS
58  else {
59  nominal = 2000.;
60  T = 88.37;
61  const int ieta=m_larem_id->eta(offid);
62  if (ieta>=0 && ieta<16) d = 0.196; //cm
63  else if (ieta>=16 && ieta<32) d = 0.193; //cm
64  else if (ieta>=32 && ieta<48) d = 0.2; //cm
65  else d = 0.190; //cm
66  }
67  }
68  // endcap
69  else {
70  subdet=1;
71  layer = m_larem_id->sampling(offid);
72  // End-Cap pre-sampler
73  if (abs(m_larem_id->barrel_ec(offid))==2 && m_larem_id->sampling(offid)==0){
74  T = 88.65; // temperature remainder Calorimeter
75  nominal = -2000.;
76  d = 0.2;
77  }
78  //EMEC
79  else {
80  T = 88.65;
81  float aeta_raw = std::abs(eta_raw);
82  double Zsamp;
83  if ( m_larem_id->sampling(offid)==1 && m_larem_id->region(offid)>=0 ) Zsamp = 3760.; //mm
84  else if ( m_larem_id->sampling(offid)==2 && m_larem_id->region(offid)<=1 ) Zsamp = 3880.; //mm
85  else if(aeta_raw< 2.) Zsamp=4200.-40.*(aeta_raw-1.5);
86  else Zsamp = 4180. - 160.*(aeta_raw-2.);
87  nominal = EMEC_nominal(aeta_raw);
88  d = EMEC_gap(aeta_raw, Zsamp)*0.1; //cm
89  }//end EMEC
90  }//end endcap
91  }//end is-em
92  // Forward Calorimeter
93  else if ( m_larfcal_id->is_lar_fcal(offid)) {
94  subdet=3;
95  layer = m_larfcal_id->module(offid);
96  T = 88.65;
97  if (m_larfcal_id->module(offid)==1){
98  d =0.0269; //cm
99  nominal = 250.;
100  isFCAL1=true;
101  }
102  else if (m_larfcal_id->module(offid)==2){
103  d =0.0376;//cm
104  nominal = 375.;
105  }
106  else {
107  d =0.0508;//cm
108  nominal = 500.;
109  }
110  }
111  // Hadronic Calorimeter
112  else if ( m_larhec_id->is_lar_hec(offid)) {
113  subdet=2;
114  layer = m_larhec_id->sampling(offid);
115  T = 88.65;
116  nominal = 1800.;
117  d = 0.196;//cm
118  }
119  T = T - m_T0;
120 
121  const double E_nominal = champ_e(nominal,d);
122 
123  // dump values
124  bool notfound=false;
125  for (unsigned int i=0;i<hvlist.size();i++) {
126  if (hvlist[i].hv<-10000) notfound=true;
127  }
128 
129  if (notfound) {
130  msg << MSG::WARNING << " At least one HV value not found in database for cell " << m_larem_id->show_to_string(offid) << endmsg;
131  }
132 
133  double mycorr=0.;
134  double mynorm=0.;
135  for (unsigned int i=0;i<hvlist.size();i++) {
136  double E = champ_e(hvlist[i].hv,d);
137 
138  // dont correct if E is very close to E nominal to avoid small glitches
139  if (std::abs(E_nominal)>1e-3) {
140  const double deviation = std::abs((E-E_nominal)/E_nominal);
141  if (deviation<1e-3) E = E_nominal;
142  }
143 
144  // barrel accordion
145  if (isbarrelEM) {
146  const double corr = this->Scale_barrel(hvlist[i].hv)*hvlist[i].weight;
147  mycorr += corr;
148  }
149  //FCAL module 1
150  else if (isFCAL1) {
151  const double corr = this->Scale_FCAL1(hvlist[i].hv) * hvlist[i].weight;
152  mycorr+=corr;
153  }
154  // other subdetectors
155  else {
156  const double corr = Respo(E,E_nominal,T)*hvlist[i].weight;
157  mycorr+= corr;
158  }
159  mynorm += hvlist[i].weight;
160  }//end loop over hvlist
161 
162 
163  if (mycorr>1e-2) mycorr = mynorm/mycorr;
164  else mycorr=1.;
165 
166  // Add protection against correction factor > 10
167  if (mycorr>10.) {
168  msg << MSG::DEBUG << "Correction factor > 10, ignore it... for cell " << m_larem_id->show_to_string(offid) << " " << mycorr << endmsg;;
169  mycorr=1.;
170  }
171 
172  //Overwrite with hardcoded jobOption numbers if requested
173  for (unsigned int ii=0;ii<m_HVfix.size();ii++) {
174  if (subdet == m_HVfix[ii].subdet && layer >= m_HVfix[ii].layer_min && layer <= m_HVfix[ii].layer_max &&
175  eta_raw >= m_HVfix[ii].eta_min && eta_raw < m_HVfix[ii].eta_max &&
176  phi_raw >= m_HVfix[ii].phi_min && phi_raw < m_HVfix[ii].phi_max ) {
177  msg << MSG::DEBUG << "Overwrite correction for cell " << m_larem_id->show_to_string(offid) << " " << m_HVfix[ii].corr << endmsg;;
178  mycorr = m_HVfix[ii].corr;
179  }
180  }
181 
182  return mycorr;
183 }
184 
185 float LArHVScaleCorrTool::champ_e(float hv, float d) const
186 {
187  float e1;
188  if (hv < -3000.){
189  return -1000.;
190  }
191  else
192  e1 = std::abs(hv)/(d*1e3);
193  if ( e1 < 0.01 ) e1 = 0.01;
194  return e1;
195 }
196 
197 float LArHVScaleCorrTool::vdrift(float e, float tempe) const
198 {
199  const float T = tempe;
200  static const float P[6] = {-0.01481,-0.0075,0.141,12.4,1.627,0.317};
201  if ( e < -999.) return 0.;
202  float vd = (P[0]*T+1)*( P[2]*e*std::log(1+ (P[3]/e)) + P[4]*std::pow(e,P[5])) + P[1]*T; // vdrift formula walcowialk mm/micro_s
203  return vd;
204 }
205 
207 // returns 1/charge from recombination effect
208 {
209  float q = 1.;
210  if ( e > 2.) q=(1.+0.36/e);
211  else if (e>1e-6) q =(1.04+0.25/e);
212  return q;
213 }
214 
215 float LArHVScaleCorrTool::Respo(float e, float e_nominal,float tempe) const
216 {
217  if (e < -999.) return 1.;
218  if (e < 0.01) return 0;
219  if ( e > e_nominal ) return 1;
220  float resp = (InvCharge(e_nominal)*vdrift(e,tempe))/(InvCharge(e)*vdrift(e_nominal,tempe));
221  return resp;
222 }
223 
224 float LArHVScaleCorrTool::t_drift(float e, float e_nominal, float d, float tempe) const
225 {
226  if ( e < -999.) return (d*1e4)/vdrift(e_nominal, tempe) ;
227  if (e > e_nominal ) e = e_nominal;
228  return (d*1e4)/vdrift(e, tempe); // ns
229 }
230 
231 float LArHVScaleCorrTool::EMEC_nominal(const float aeta) const
232 {
233  if ( aeta<1.5 ) return 2500.;
234  else if (aeta<1.6) return 2300.;
235  else if (aeta<1.8 ) return 2100.;
236  else if (aeta < 2.0 ) return 1700.;
237  else if (aeta < 2.1 ) return 1500.;
238  else if (aeta < 2.3 ) return 1250.;
239  else if (aeta < 2.5 ) return 1000.;
240  else if (aeta < 2.8 ) return 2300.;
241  else return 1800.;
242 }
243 
244 float LArHVScaleCorrTool::EMEC_gap(const float aeta, float Zeta) const
245 {
246  float EMECg;
247  if (aeta<=2.5 ) EMECg = 0.9 +1.9*( ( Zeta - 40. )/(10*std::sinh(aeta)) - 60.)/140.;
248  else EMECg = 1.8 + 1.3*( ( Zeta - 40. )/(10*std::sinh(aeta)) - 30.)/40.;
249  return EMECg;
250 }
251 
252 float LArHVScaleCorrTool::Scale_FCAL1(const float hv) const
253 {
254  if (hv<5.0) return 0;
255  const float R0=-2.612;
256  const float alpha=2.336;
257  const float beta=0.079;
258  const float scale=R0+alpha*std::pow(hv,beta);
259  return scale;
260 }
261 
262 
263 
264 float LArHVScaleCorrTool::Scale_barrel(const float hv) const
265 {
266  const float hvref[18]={1.,50.,100.,150.,200.,300.,400.,500.,600.,700.,800.,900.,1000.,1200.,1400.,1600.,1800.,2000.};
267  const float hvmax = 1998.;
268  const float facteur[18]={0.,0.1209,0.2135,0.2829,0.3390,0.4270,0.4961,0.5556,0.6065,0.6527,0.6906,
269  0.7290,0.7626,0.8224,0.8754,0.9190,0.9606,1.};
270 
271 // 0 HV, returns 0 response
272  if (hv<-999.) {
273  return 0;
274  }
275  else if (hv<hvref[0]) {
276  float resp=facteur[0];
277  return resp;
278  }
279 // 2000 HV, returns response=1
280  if (hv>hvmax) {
281  float resp=facteur[17];
282  return resp;
283  }
284 
285 // intermediate HV, find values between which to extrapolate
286  int i1,i2;
287  i1=1;
288  for (int i=0;i<18;i++) {
289  if (hv<hvref[i]) {
290  i1=i-1;
291  break;
292  }
293  }
294  i2=i1+1;
295  float resp=0.;
296 
297 // if lowHV>=50 V, logarithmic extrapolation
298  if (i1>0) {
299  const float b=(std::log(facteur[i2])-std::log(facteur[i1]))/(std::log(hvref[i2])-std::log(hvref[i1]));
300  const float a=std::log(facteur[i2])-b*std::log(hvref[i2]);
301  resp = std::exp(a+b*std::log(hv));
302  }
303 // if between 0 and 50 V, scales linearly
304  else {
305  resp=facteur[0]*(hv/hvref[0]);
306  }
307  //std::cout << " hv,i1,i2,resp " << hv << " " << i1 << " " << i2 << " " << resp << std::endl;
308  return resp;
309 }
310 
311 // *** Build list of correction to hardcode by jobOptions
313  const std::vector<std::string>& fixHVStrings, MsgStream& msg) {
314 
315  m_HVfix.clear();
316  for (const std::string& theString : fixHVStrings) {
317  std::stringstream is;
318  is << theString << std::endl;
319 
320  unsigned int iDetector, ilayer_min, ilayer_max;
321  float eta_min, eta_max, phi_min, phi_max, corr;
322  is >> iDetector >> ilayer_min >> ilayer_max >> eta_min >> eta_max >>
323  phi_min >> phi_max >> corr;
324 
325  m_HVfix.push_back({.subdet = iDetector,
326  .layer_min = ilayer_min,
327  .layer_max = ilayer_max,
328  .eta_min = eta_min,
329  .eta_max = eta_max,
330  .phi_min = phi_min,
331  .phi_max = phi_max,
332  .corr = corr});
333  }
334 
335  msg << MSG::INFO
336  << " Number of regions with overwritten HV corrections from jobOptions "
337  << m_HVfix.size() << endmsg;
338 
339  return;
340 }
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
python.SystemOfUnits.second
int second
Definition: SystemOfUnits.py:120
LArHVScaleCorrTool::m_larem_id
const LArEM_ID * m_larem_id
Definition: LArHVScaleCorrTool.h:45
AtlasDetectorID::is_lar_fcal
bool is_lar_fcal(Identifier id) const
Definition: AtlasDetectorID.h:839
LArHVScaleCorrTool::Scale_barrel
float Scale_barrel(const float hv) const
Definition: LArHVScaleCorrTool.cxx:264
egammaEnergyPositionAllSamples::e1
double e1(const xAOD::CaloCluster &cluster)
return the uncorrected cluster energy in 1st sampling
LArHVScaleCorrTool::champ_e
float champ_e(float hv, float d) const
Definition: LArHVScaleCorrTool.cxx:185
hist_file_dump.d
d
Definition: hist_file_dump.py:137
DMTest::P
P_v1 P
Definition: P.h:23
CaloDetDescrElement
This class groups all DetDescr information related to a CaloCell. Provides a generic interface for al...
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:66
LArHVScaleCorrTool::m_T0
const float m_T0
Definition: LArHVScaleCorrTool.h:48
python.SystemOfUnits.microsecond
int microsecond
Definition: SystemOfUnits.py:122
LArFCAL_Base_ID::module
int module(const Identifier id) const
module [1,3]
LArEM_Base_ID::region
int region(const Identifier id) const
return region according to :
LArEM_Base_ID::sampling
int sampling(const Identifier id) const
return sampling according to :
LArHVScaleCorrTool::Respo
float Respo(float e, float e_nominal, float tempe) const
Definition: LArHVScaleCorrTool.cxx:215
CheckTagAssociation.notfound
notfound
Definition: CheckTagAssociation.py:105
drawFromPickle.exp
exp
Definition: drawFromPickle.py:36
yodamerge_tmp.scale
scale
Definition: yodamerge_tmp.py:138
LArHVScaleCorrTool::vdrift
float vdrift(float e, float tempe) const
Definition: LArHVScaleCorrTool.cxx:197
LArEM_Base_ID::eta
int eta(const Identifier id) const
return eta according to :
CaloDetDescrElement::eta_raw
float eta_raw() const
cell eta_raw
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:350
CaloCell_ID.h
LArHVScaleCorrTool::getHVScale
float getHVScale(const CaloDetDescrElement *calodde, const voltageCell_t &hvlist, MsgStream &msg) const
Definition: LArHVScaleCorrTool.cxx:26
CaloDetDescrElement::identify
Identifier identify() const override final
cell identifier
Definition: CaloDetDescrElement.cxx:64
LArHVScaleCorrTool::m_HVfix
std::vector< HVfix_t > m_HVfix
Definition: LArHVScaleCorrTool.h:94
LArHVScaleCorrTool::m_larhec_id
const LArHEC_ID * m_larhec_id
Definition: LArHVScaleCorrTool.h:46
LArHVScaleCorrTool::voltageCell_t
std::vector< HV_t > voltageCell_t
Definition: LArHVScaleCorrTool.h:30
CheckAppliedSFs.e3
e3
Definition: CheckAppliedSFs.py:264
lumiFormat.i
int i
Definition: lumiFormat.py:85
PixelAthClusterMonAlgCfg.e4
e4
Definition: PixelAthClusterMonAlgCfg.py:332
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
LArHVScaleCorrTool::m_larfcal_id
const LArFCAL_ID * m_larfcal_id
Definition: LArHVScaleCorrTool.h:47
TRT::Hit::layer
@ layer
Definition: HitInfo.h:79
LArHVScaleCorrTool::buildFixHVList
void buildFixHVList(const std::vector< std::string > &fixHVStrings, MsgStream &msg)
Definition: LArHVScaleCorrTool.cxx:312
AtlasDetectorID::is_lar_hec
bool is_lar_hec(Identifier id) const
Definition: AtlasDetectorID.h:829
CaloCell_ID
Helper class for offline cell identifiers.
Definition: CaloCell_ID.h:34
LArHVScaleCorrTool::EMEC_nominal
float EMEC_nominal(const float eta_r) const
Definition: LArHVScaleCorrTool.cxx:231
LArHVScaleCorrTool::LArHVScaleCorrTool
LArHVScaleCorrTool()=delete
LArHVScaleCorrTool::InvCharge
float InvCharge(float e) const
Definition: LArHVScaleCorrTool.cxx:206
VP1PartSpect::E
@ E
Definition: VP1PartSpectFlags.h:21
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
LArEM_Base_ID::barrel_ec
int barrel_ec(const Identifier id) const
return barrel_ec according to :
LArHVScaleCorrTool::EMEC_gap
float EMEC_gap(const float eta_r, float Zeta) const
Definition: LArHVScaleCorrTool.cxx:244
LArHVScaleCorrTool::Scale_FCAL1
float Scale_FCAL1(const float hv) const
Definition: LArHVScaleCorrTool.cxx:252
a
TList * a
Definition: liststreamerinfos.cxx:10
AtlasDetectorID::show_to_string
std::string show_to_string(Identifier id, const IdContext *context=0, char sep='.') const
or provide the printout in string form
Definition: AtlasDetectorID.cxx:574
DEBUG
#define DEBUG
Definition: page_access.h:11
LArHEC_Base_ID::sampling
int sampling(const Identifier id) const
return sampling [0,3] (only 0 for supercells)
python.CaloCondTools.log
log
Definition: CaloCondTools.py:20
extractSporadic.q
list q
Definition: extractSporadic.py:98
MuonParameters::beta
@ beta
Definition: MuonParamDefs.h:144
pow
constexpr int pow(int base, int exp) noexcept
Definition: ap_fixedTest.cxx:15
AtlasDetectorID::is_lar_em
bool is_lar_em(Identifier id) const
Definition: AtlasDetectorID.h:818
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
LArHVScaleCorrTool::t_drift
float t_drift(float e, float e_nominal, float d, float tempe) const
Definition: LArHVScaleCorrTool.cxx:224
LArHVScaleCorrTool.h
TSU::T
unsigned long long T
Definition: L1TopoDataTypes.h:35
CaloDetDescrElement::phi_raw
float phi_raw() const
cell phi_raw
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:352
Identifier
Definition: IdentifierFieldParser.cxx:14