ATLAS Offline Software
Loading...
Searching...
No Matches
LArHVScaleCorrTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6#include "CaloDetDescr/CaloDetDescrElement.h"
8#include "CLHEP/Units/SystemOfUnits.h"
9
10#include <cmath>
11
12using CLHEP::microsecond;
13using CLHEP::second;
14
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
185float 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
197float 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
215float 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 den = InvCharge(e)*vdrift(e_nominal,tempe);
221 float resp = den==0 ? 0 : (InvCharge(e_nominal)*vdrift(e,tempe))/den;
222 return resp;
223}
224
225float LArHVScaleCorrTool::t_drift(float e, float e_nominal, float d, float tempe) const
226{
227 if ( e < -999.) {
228 float den = vdrift(e_nominal, tempe);
229 return den==0 ? 0 : (d*1e4)/den;
230 }
231 if (e > e_nominal ) e = e_nominal;
232 float den = vdrift(e, tempe);
233 return den==0 ? 0 : (d*1e4)/den; // ns
234}
235
236float LArHVScaleCorrTool::EMEC_nominal(const float aeta) const
237{
238 if ( aeta<1.5 ) return 2500.;
239 else if (aeta<1.6) return 2300.;
240 else if (aeta<1.8 ) return 2100.;
241 else if (aeta < 2.0 ) return 1700.;
242 else if (aeta < 2.1 ) return 1500.;
243 else if (aeta < 2.3 ) return 1250.;
244 else if (aeta < 2.5 ) return 1000.;
245 else if (aeta < 2.8 ) return 2300.;
246 else return 1800.;
247}
248
249float LArHVScaleCorrTool::EMEC_gap(const float aeta, float Zeta) const
250{
251 float EMECg;
252 if (aeta<=2.5 ) EMECg = 0.9 +1.9*( ( Zeta - 40. )/(10*std::sinh(aeta)) - 60.)/140.;
253 else EMECg = 1.8 + 1.3*( ( Zeta - 40. )/(10*std::sinh(aeta)) - 30.)/40.;
254 return EMECg;
255}
256
257float LArHVScaleCorrTool::Scale_FCAL1(const float hv) const
258{
259 if (hv<5.0) return 0;
260 const float R0=-2.612;
261 const float alpha=2.336;
262 const float beta=0.079;
263 const float scale=R0+alpha*std::pow(hv,beta);
264 return scale;
265}
266
267
268
269float LArHVScaleCorrTool::Scale_barrel(const float hv) const
270{
271 const float hvref[18]={1.,50.,100.,150.,200.,300.,400.,500.,600.,700.,800.,900.,1000.,1200.,1400.,1600.,1800.,2000.};
272 const float hvmax = 1998.;
273 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,
274 0.7290,0.7626,0.8224,0.8754,0.9190,0.9606,1.};
275
276// 0 HV, returns 0 response
277 if (hv<-999.) {
278 return 0;
279 }
280 else if (hv<hvref[0]) {
281 float resp=facteur[0];
282 return resp;
283 }
284// 2000 HV, returns response=1
285 if (hv>hvmax) {
286 float resp=facteur[17];
287 return resp;
288 }
289
290// intermediate HV, find values between which to extrapolate
291 int i1,i2;
292 i1=1;
293 for (int i=0;i<18;i++) {
294 if (hv<hvref[i]) {
295 i1=i-1;
296 break;
297 }
298 }
299 i2=i1+1;
300 float resp=0.;
301
302// if lowHV>=50 V, logarithmic extrapolation
303 if (i1>0) {
304 const float b=(std::log(facteur[i2])-std::log(facteur[i1]))/(std::log(hvref[i2])-std::log(hvref[i1]));
305 const float a=std::log(facteur[i2])-b*std::log(hvref[i2]);
306 resp = std::exp(a+b*std::log(hv));
307 }
308// if between 0 and 50 V, scales linearly
309 else {
310 resp=facteur[0]*(hv/hvref[0]);
311 }
312 //std::cout << " hv,i1,i2,resp " << hv << " " << i1 << " " << i2 << " " << resp << std::endl;
313 return resp;
314}
315
316// *** Build list of correction to hardcode by jobOptions
318 const std::vector<std::string>& fixHVStrings, MsgStream& msg) {
319
320 m_HVfix.clear();
321 for (const std::string& theString : fixHVStrings) {
322 std::stringstream is;
323 is << theString << std::endl;
324
325 unsigned int iDetector, ilayer_min, ilayer_max;
326 float eta_min, eta_max, phi_min, phi_max, corr;
327 is >> iDetector >> ilayer_min >> ilayer_max >> eta_min >> eta_max >>
328 phi_min >> phi_max >> corr;
329
330 m_HVfix.push_back({.subdet = iDetector,
331 .layer_min = ilayer_min,
332 .layer_max = ilayer_max,
333 .eta_min = eta_min,
334 .eta_max = eta_max,
335 .phi_min = phi_min,
336 .phi_max = phi_max,
337 .corr = corr});
338 }
339
340 msg << MSG::INFO
341 << " Number of regions with overwritten HV corrections from jobOptions "
342 << m_HVfix.size() << endmsg;
343
344 return;
345}
#define endmsg
static Double_t a
static Double_t P(Double_t *tt, Double_t *par)
Helper class for offline cell identifiers.
Definition CaloCell_ID.h:34
This class groups all DetDescr information related to a CaloCell.
Identifier identify() const override final
cell identifier
std::vector< HVfix_t > m_HVfix
LArHVScaleCorrTool()=delete
float InvCharge(float e) const
void buildFixHVList(const std::vector< std::string > &fixHVStrings, MsgStream &msg)
const LArHEC_ID * m_larhec_id
float getHVScale(const CaloDetDescrElement *calodde, const voltageCell_t &hvlist, MsgStream &msg) const
float EMEC_nominal(const float eta_r) const
float Respo(float e, float e_nominal, float tempe) const
float EMEC_gap(const float eta_r, float Zeta) const
const LArEM_ID * m_larem_id
const LArFCAL_ID * m_larfcal_id
float vdrift(float e, float tempe) const
float Scale_FCAL1(const float hv) const
std::vector< HV_t > voltageCell_t
float Scale_barrel(const float hv) const
float t_drift(float e, float e_nominal, float d, float tempe) const
float champ_e(float hv, float d) const
MsgStream & msg
Definition testRead.cxx:32