ATLAS Offline Software
Loading...
Searching...
No Matches
CSC_Digitizer.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5// Author: Ketevi A. Assamagan
6// BNL, February 19 2004 : move to MuonGeoModel
7// Digitization routine for the CSC hits
9
11#include "CLHEP/Random/RandFlat.h"
12#include "CLHEP/Random/RandGamma.h"
13#include "CLHEP/Random/RandPoisson.h"
14#include "CLHEP/Random/RandomEngine.h"
15#include "GaudiKernel/ISvcLocator.h"
16#include "GaudiKernel/MsgStream.h"
19
20using namespace MuonGM;
21
22// Constructors
24 m_cscHitHelper{cscHitHelper}, m_muonMgr{muonMgr}, m_cscIdHelper{m_muonMgr->cscIdHelper()}, m_pcalib{pcalib} {
26 m_stationDict['S'] = m_cscIdHelper->stationNameIndex("CSS");
27 m_stationDict['L'] = m_cscIdHelper->stationNameIndex("CSL");
28}
29
30// Public methods
32 // initialize random number generators
33 // then initialize the CSC identifier helper
34 // This method must be called before looping over the hits
35 // to digitize them using the method digitize_hit below
36 m_bunchTime = 0.0;
37
38 // calculate the probability densities
39 static constexpr std::array<double, s_maxElectron> prob{79.4, 12., 3.4, 1.6, 0.95, 0.6, 0.44, 0.34, 0.27, 0.21, 0.17,
40 0.13, 0.1, 0.08, 0.06, 0.05, 0.042, 0.037, 0.033, 0.029, 0.};
41
42 double sump = 0;
43 for (int i = 0; i < s_maxElectron; ++i) {
44 sump += prob[i];
45 m_sprob[i] = sump;
46 }
47
48 return StatusCode::SUCCESS;
49}
50
52 const int hitId = cscHit->CSCid();
53 const std::string st_str = m_cscHitHelper->GetStationName(hitId);
54 std::map<char, int>::const_iterator itr = m_stationDict.find(st_str[2]);
55 if (itr == m_stationDict.end()) {
56 throw std::runtime_error(Form("%s:%d Failed to convert station name %s to an valid offline identifier", __FILE__, __LINE__,
57 st_str.c_str()));
58 }
59 const int stationName = itr->second;
60 const int eta = m_cscHitHelper->GetZSector(hitId);
61 const int phi = m_cscHitHelper->GetPhiSector(hitId);
62 const int chamberLayer = m_cscHitHelper->GetChamberLayer(hitId);
63 const int wireLayer = m_cscHitHelper->GetWireLayer(hitId);
64 return m_cscIdHelper->channelID(stationName, eta, phi, chamberLayer, wireLayer, 0, 1);
65}
66
67StatusCode CSC_Digitizer::digitize_hit(const CSCSimHit* cscHit, std::vector<IdentifierHash>& hashVec,
68 std::map<IdentifierHash, std::vector<float>>& data_SampleMap,
69 std::map<IdentifierHash, std::vector<float>>& data_SampleMapOddPhase,
70 CLHEP::HepRandomEngine* rndmEngine) {
71 // method to digitize a single hit. Must be called in a loop over hits
72 // after a call to the method "StatusCode CSC_Digitize::initialize()"
73 // get the step vector from the begining and end vectors of the G4 step
74
75 Amg::Vector3D startHit = cscHit->getHitStart();
76 Amg::Vector3D endHit = cscHit->getHitEnd();
77
78 // decode the hit ID
79 const Identifier HitId = to_identifier(cscHit);
80 const int chamberLayer = m_cscHitHelper->GetChamberLayer(cscHit->CSCid());
81
82 // find the detector descriptor
83 const CscReadoutElement* descriptor = m_muonMgr->getCscReadoutElement(HitId);
84 if (!descriptor) {
85 std::cout << "CSC_Digitizer::ERROR : Cannot get descriptor for GeoModel = " << std::endl;
86 return StatusCode::FAILURE;
87 }
88
89 // particle ID
90 int ipart = cscHit->particleID();
91
92 Amg::Vector3D stepHit = endHit - startHit;
93 double step = stepHit.mag(); // path length in a layer
94
95 if (step == 0) return StatusCode::SUCCESS;
96
97 // get average number of interaction::one interaction for photons
98 int nInter = 0;
99 if (ipart == 1)
100 nInter = 1;
101 else {
103 double energyLoss = cscHit->energyDeposit(); // MeV peaking at 0.001MeV for on time track (25ns from IP)
104 double elecEnergy = m_electronEnergy *
105 0.000001; // each ionized electron has 66eV (66 is from 0.001MeV/15 (average interaction per layer 0.5cm)
106 nInter = energyLoss / elecEnergy;
107 } else {
108 double average_int = 30; // average interactions per cm
109 double pois = CLHEP::RandPoisson::shoot(rndmEngine, average_int);
110 nInter = int(step * pois / 10.0 + 0.5); // number of interaction according to Poisson
111 if (m_debug)
112 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] nInter info from random number pois:step:nInter " << pois << " " << step
113 << " " << nInter << std::endl;
114 }
115 }
116
117 if (nInter <= 0) return StatusCode::SUCCESS;
118
119 double wireCharge{0.};
120 int nElectrons{0};
121
122 // loop over number of interactions and do digitization
123 for (int i = 0; i < nInter; ++i) {
124 double t = 0.0;
125 if (ipart == 1 || ipart == 999)
126 t = step * 0.50; // one interaction for photons & geantinos
127 else
128 t = CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0); // for other particles
129
130 const Amg::Vector3D pos_vec = startHit + t * stepHit;
131
132 // pileup - check if within time window
133 double preDriftTime = getDriftTime(descriptor, pos_vec); // before geant hit time addition.
134 double driftTime = m_bunchTime + cscHit->meanTime() + preDriftTime;
135
136 if (m_debug) {
137 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] totTime:driftTime:hitTime:bunchTime (ns) = " << driftTime << " "
138 << cscHit->meanTime() << " " << preDriftTime << " " << m_bunchTime << std::endl;
139 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] start hit coordinates (xc,yc,zc) / step hit and t / the hit are " << startHit
140 << " " << stepHit << " " << t << " " << pos_vec << std::endl;
141 }
142
143 // Prompt muon case::
144 // CSL 25.02ns CSS 26.3ns :: Dec03 2009 geant hit time was not added but it's added now.
145 // so previous +- 50ns time window may not work. We need to tune it. Temporally, I put -inf +inf.
146
147 // it should be decided by bunchtime. -400 to +200
148 if (outsideWindow(m_bunchTime)) continue;
149
150 // number of electrons in this interaction
151 double flat = CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0);
152 double p = m_sprob[s_maxElectron - 1] * flat;
153 for (int k = 0; k < s_maxElectron; ++k) {
154 if (p <= m_sprob[k]) {
155 nElectrons = k + 1;
156 break;
157 }
158 }
159
160 // find the charge on the wire in electron-equivalent charge
161
162 m_Polia = 0.38; // parmeter for charge loss:: random gamma function
163 double gammaDist = CLHEP::RandGamma::shoot(rndmEngine, (1.0 + m_Polia), 1.0);
164 wireCharge = qWire(nElectrons, gammaDist);
165
166 if (m_debug) {
167 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] flat:p:maxEle:nEle:gammaDist:wireCharge " << flat << " " << p << " "
168 << s_maxElectron << " " << nElectrons << " " << gammaDist << " " << wireCharge << std::endl;
169 }
170
171 // now digitize hits for R- and phi-strips
172 for (int measuresPhi = 0; measuresPhi <= 1; ++measuresPhi) {
173 float stripWidth = descriptor->cathodeReadoutPitch(chamberLayer, measuresPhi);
174 const int maxStrip = descriptor->maxNumberOfStrips(measuresPhi, stripWidth);
175
176 if (m_debug) {
177 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] CSC_Digitizer::digitize_hit: Chamber Parameters"
178 << " measuresPhi= " << measuresPhi << " stripWidth= " << stripWidth << " maxStrip= " << maxStrip << std::endl;
179 }
180
181 // now digitize hits for R-strips/phi-strips
182
183 if (measuresPhi == 0) { // R-strips :: find the charge+noise
184 double zz = pos_vec.z() + maxStrip * stripWidth * 0.50; // assuming zero offset
185 int strip = int(zz / stripWidth) + 1;
186 // find the charges induced on the phi strips
187 for (int j = strip - 4; j <= strip + 4; ++j) {
188 double zpos = stripWidth * j - stripWidth * 0.50;
189 if (j > 0 && j <= maxStrip) {
190 double stripCharge = wireCharge * qStripR((zpos - zz) / stripWidth, HitId) * 0.50;
191 // if (stripCharge < 0) stripCharge = 0.0;
192
193 if (m_debug)
194 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] zpos = " << zpos << " zz = " << zz
195 << " diff = " << std::abs(zz - zpos) << " strip = " << j << " charge = " << stripCharge << std::endl;
196
197 IdentifierHash hashId = getHashId(HitId, j, measuresPhi);
198 fillSampleMaps(hashId, driftTime, stripCharge, hashVec, data_SampleMap);
199 fillSampleMaps(hashId, driftTime, stripCharge, hashVec, data_SampleMapOddPhase, 1);
200 if (m_debug)
201 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] DriftTimeVSstripCharge " << driftTime << " " << stripCharge
202 << std::endl;
203 }
204 }
205 } else { // Phi-strips :: find the charge+noise
206 double yy = 0.0;
207 int strip = 0;
208
209 yy = pos_vec.y() + maxStrip * stripWidth * 0.5; // non-pointing phi-strips :: assuming zero offset
210 if (m_cscHitHelper->GetZSector(cscHit->CSCid()) > 0)
211 yy = -pos_vec.y() + maxStrip * stripWidth * 0.5; // non-pointing phi-strips :: assuming zero offset
212 strip = int(yy / stripWidth) + 1;
213
214 // find the charges induced on the phi strips
215 for (int j = strip - 1; j <= strip + 1; ++j) {
216 if (j > 0 && j <= maxStrip) {
217 double ypos = stripWidth * (j - 0.5);
218 double stripCharge = wireCharge * qStripPhi(ypos - yy, HitId) * 0.50;
219 if (m_debug)
220 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] ypos = " << ypos << " yy = " << yy
221 << " diff = " << std::abs(yy - ypos) << " strip = " << j << " charge = " << stripCharge << std::endl;
222
223 IdentifierHash hashId = getHashId(HitId, j, measuresPhi);
224 fillSampleMaps(hashId, driftTime, stripCharge, hashVec, data_SampleMap);
225 fillSampleMaps(hashId, driftTime, stripCharge, hashVec, data_SampleMapOddPhase, 1);
226 }
227 }
228 }
229 }
230 }
231
232 return StatusCode::SUCCESS;
233}
234
235StatusCode CSC_Digitizer::digitize_hit(const CSCSimHit* cscHit, std::vector<IdentifierHash>& hashVec,
236 std::map<IdentifierHash, std::vector<float>>& data_SampleMap, CLHEP::HepRandomEngine* rndmEngine) {
237 // method to digitize a single hit. Must be called in a loop over hits
238 // after a call to the method "StatusCode CSC_Digitize::initialize()"
239 // get the step vector from the begining and end vectors of the G4 step
240 Amg::Vector3D startHit = cscHit->getHitStart();
241 Amg::Vector3D endHit = cscHit->getHitEnd();
242
243 // decode the hit ID
244 const Identifier HitId = to_identifier(cscHit);
245 const int chamberLayer = m_cscHitHelper->GetChamberLayer(cscHit->CSCid());
246
247 // find the detector descriptor
248 const CscReadoutElement* descriptor = m_muonMgr->getCscReadoutElement(HitId);
249 if (!descriptor) {
250 std::cout << "CSC_Digitizer::ERROR : Cannot get descriptor for GeoModel = " << std::endl;
251 return StatusCode::FAILURE;
252 }
253
254 // particle ID
255 int ipart = cscHit->particleID();
256
257 Amg::Vector3D stepHit = endHit - startHit;
258 double step = stepHit.mag();
259
260 if (step == 0) return StatusCode::SUCCESS;
261
262 // get average number of interaction::one interaction for photons
263 // std::cout << "The particle ID = " << ipart << std::endl;
264
265 int nInter = 0;
266 if (ipart == 1)
267 nInter = 1;
268 else {
269 double average_int = 30; // average interactions per cm
270 double pois = CLHEP::RandPoisson::shoot(rndmEngine, average_int);
271 nInter = int(step * pois / 10.0 + 0.5); // number of interaction according to Poisson
272 if (m_debug)
273 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] nInter info from random number pois:step:nInter " << pois << " " << step
274 << " " << nInter << std::endl;
275 }
276
277 if (nInter <= 0) return StatusCode::SUCCESS;
278
279 double wireCharge{0};
280 int nElectrons = 0;
281
282 // loop over number of interactions and do digitization
283 for (int i = 0; i < nInter; ++i) {
284 double t = 0.0;
285 if (ipart == 1 || ipart == 999)
286 t = step * 0.50; // one interaction for photons & geantinos
287 else
288 t = CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0); // for other particles
289
290 Amg::Vector3D pos_vec = startHit + t * stepHit;
291
292 // pileup - check if within time window
293 double preDriftTime = getDriftTime(descriptor, pos_vec); // before geant hit time addition.
294 double driftTime = m_bunchTime + cscHit->meanTime() + preDriftTime;
295
296 if (m_debug) {
297 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] totTime:driftTime:hitTime:bunchTime (ns) = " << driftTime << " "
298 << cscHit->meanTime() << " " << preDriftTime << " " << m_bunchTime << std::endl;
299 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] start hit coordinates (xc,yc,zc) / step hit and t / the hit are " << startHit
300 << " " << stepHit << " " << t << " " << pos_vec << std::endl;
301 }
302
303 // Prompt muon case::
304 // CSL 25.02ns CSS 26.3ns :: Dec03 2009 geant hit time was not added but it's added now.
305 // so previous +- 50ns time window may not work. We need to tune it. Temporally, I put -inf +inf.
306
307 // it should be decided by bunchtime. -400 to +200
308 if (outsideWindow(m_bunchTime)) continue;
309
310 // number of electrons in this interaction
311 double flat = CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0);
312 double p = m_sprob[s_maxElectron - 1] * flat;
313 for (int k = 0; k < s_maxElectron; ++k) {
314 if (p <= m_sprob[k]) {
315 nElectrons = k + 1;
316 break;
317 }
318 }
319
320 // find the charge on the wire in electron-equivalent charge
321
322 m_Polia = 0.38; // parmeter for charge loss:: random gamma function
323 double gammaDist = CLHEP::RandGamma::shoot(rndmEngine, (1.0 + m_Polia), 1.0);
324 wireCharge = qWire(nElectrons, gammaDist);
325
326 if (m_debug) {
327 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] flat:p:maxEle:nEle:gammaDist:wireCharge " << flat << " " << p << " "
328 << s_maxElectron << " " << nElectrons << " " << gammaDist << " " << wireCharge << std::endl;
329 }
330
331 // now digitize hits for R- and phi-strips
332 for (int measuresPhi = 0; measuresPhi <= 1; ++measuresPhi) {
333 float stripWidth = descriptor->cathodeReadoutPitch(chamberLayer, measuresPhi);
334 const int maxStrip = descriptor->maxNumberOfStrips(measuresPhi, stripWidth);
335
336 if (m_debug) {
337 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] CSC_Digitizer::digitize_hit: Chamber Parameters"
338 << " measuresPhi= " << measuresPhi << " stripWidth= " << stripWidth << " maxStrip= " << maxStrip << std::endl;
339 }
340
341 // now digitize hits for R-strips/phi-strips
342
343 if (measuresPhi == 0) { // R-strips :: find the charge+noise
344 double zz = pos_vec.z() + maxStrip * stripWidth * 0.50; // assuming zero offset
345 int strip = int(zz / stripWidth) + 1;
346 // find the charges induced on the phi strips
347 for (int j = strip - 4; j <= strip + 4; ++j) {
348 double zpos = stripWidth * j - stripWidth * 0.50;
349 if (j > 0 && j <= maxStrip) {
350 double stripCharge = wireCharge * qStripR((zpos - zz) / stripWidth, HitId) * 0.50;
351
352 if (m_debug)
353 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] zpos = " << zpos << " zz = " << zz
354 << " diff = " << std::abs(zz - zpos) << " strip = " << j << " charge = " << stripCharge << std::endl;
355
356 IdentifierHash hashId = getHashId(HitId, j, measuresPhi);
357 fillSampleMaps(hashId, driftTime, stripCharge, hashVec, data_SampleMap);
358
359 if (m_debug)
360 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] DriftTimeVSstripCharge " << driftTime << " " << stripCharge
361 << std::endl;
362 }
363 }
364 } else { // Phi-strips :: find the charge+noise
365 double yy = 0.0;
366 int strip = 0;
367
368 yy = pos_vec.y() + maxStrip * stripWidth * 0.5; // non-pointing phi-strips :: assuming zero offset
369 if (m_cscHitHelper->GetZSector(cscHit->CSCid()) > 0)
370 yy = -pos_vec.y() + maxStrip * stripWidth * 0.5; // non-pointing phi-strips :: assuming zero offset
371 strip = int(yy / stripWidth) + 1;
372
373 // find the charges induced on the phi strips
374 for (int j = strip - 1; j <= strip + 1; j++) {
375 if (j > 0 && j <= maxStrip) {
376 double ypos = stripWidth * (j - 0.5);
377 double stripCharge = wireCharge * qStripPhi(ypos - yy, HitId) * 0.50;
378 if (m_debug)
379 std::cout << "[CSC_Digitizer::digitize_hit(NEW)] ypos = " << ypos << " yy = " << yy
380 << " diff = " << std::abs(yy - ypos) << " strip = " << j << " charge = " << stripCharge << std::endl;
381
382 IdentifierHash hashId = getHashId(HitId, j, measuresPhi);
383 fillSampleMaps(hashId, driftTime, stripCharge, hashVec, data_SampleMap);
384 }
385 }
386 }
387 }
388 }
389
390 return StatusCode::SUCCESS;
391}
392
396StatusCode CSC_Digitizer::digitize_hit(const CSCSimHit* cscHit, std::vector<IdentifierHash>& hashVec,
397 std::map<IdentifierHash, std::pair<double, double>>& data_map, CLHEP::HepRandomEngine* rndmEngine) {
398 // method to digitize a single hit. Must be called in a loop over hits
399 // after a call to the method "StatusCode CSC_Digitize::initialize()"
400 // get the step vector from the begining and end vectors of the G4 step
401 Amg::Vector3D startHit = cscHit->getHitStart();
402 Amg::Vector3D endHit = cscHit->getHitEnd();
403
404 // decode the hit ID
405 const Identifier HitId = to_identifier(cscHit);
406 const int chamberLayer = m_cscHitHelper->GetChamberLayer(cscHit->CSCid());
407 // find the detector descriptor
408 const CscReadoutElement* descriptor = m_muonMgr->getCscReadoutElement(HitId);
409 if (!descriptor) {
410 std::cout << "CSC_Digitizer::ERROR : Cannot get descriptor for GeoModel = " << std::endl;
411 return StatusCode::FAILURE;
412 }
413
414 // particle ID
415 int ipart = cscHit->particleID();
416
417 Amg::Vector3D stepHit = endHit - startHit;
418 double step = stepHit.mag();
419
420 if (step == 0) return StatusCode::SUCCESS;
421
422 // get average number of interaction::one interaction for photons
423 // std::cout << "The particle ID = " << ipart << std::endl;
424
425 int nInter = 0;
426 if (ipart == 1)
427 nInter = 1;
428 else {
429 double average_int = 30; // average interactions per cm
430 double pois = CLHEP::RandPoisson::shoot(rndmEngine, average_int);
431 nInter = int(step * pois / 10.0 + 0.5); // number of interaction according to Poisson
432 if (m_debug)
433 std::cout << "[CSC_Digitizer::digitize_hit] nInter info from random number pois:step:nInter " << pois << " " << step << " "
434 << nInter << std::endl;
435 }
436
437 if (nInter <= 0) return StatusCode::SUCCESS;
438
439 double wireCharge;
440 int nElectrons = 0;
441
442 // loop over number of interactions and do digitization
443 for (int i = 0; i < nInter; ++i) {
444 double t = 0.0;
445 if (ipart == 1 || ipart == 999)
446 t = step * 0.50; // one interaction for photons & geantinos
447 else
448 t = CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0); // for other particles
449
450 const Amg::Vector3D pos_vec = startHit + t * stepHit;
451 // pileup - check if within time window
452 double preDriftTime = getDriftTime(descriptor, pos_vec); // before geant hit time addition.
453 double driftTime = m_bunchTime + cscHit->meanTime() + preDriftTime;
454
455 if (m_debug) {
456 std::cout << "[CSC_Digitizer::digitize_hit] totTime:driftTime:hitTime:bunchTime (ns) = " << driftTime << " "
457 << cscHit->meanTime() << " " << preDriftTime << " " << m_bunchTime << std::endl;
458 std::cout << "[CSC_Digitizer::digitize_hit] start hit coordinates (xc,yc,zc) / step hit and t / the hit are " << startHit
459 << " " << stepHit << " " << t << " " << pos_vec << std::endl;
460 }
461
462 // Prompt muon case::
463 // CSL 25.02ns CSS 26.3ns :: Dec03 2009 geant hit time was not added but it's added now.
464 // so previous +- 50ns time window may not work. We need to tune it. Temporally, I put -inf +inf.
465
466 // it should be decided by bunchtime. -400 to +200
467 if (outsideWindow(m_bunchTime)) continue;
468
469 // number of electrons in this interaction
470 double flat = CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0);
471 double p = m_sprob[s_maxElectron - 1] * flat;
472 for (int k = 0; k < s_maxElectron; ++k) {
473 if (p <= m_sprob[k]) {
474 nElectrons = k + 1;
475 break;
476 }
477 }
478
479 // find the charge on the wire in electron-equivalent charge
480 m_Polia = 0.38; // parmeter for charge loss:: random gamma function
481 double gammaDist = CLHEP::RandGamma::shoot(rndmEngine, (1.0 + m_Polia), 1.0);
482 wireCharge = qWire(nElectrons, gammaDist);
483
484 if (m_debug) {
485 std::cout << "[CSC_Digitizer::digitize_hit] flat:p:maxEle:nEle:gammaDist:wireCharge " << flat << " " << p << " "
486 << s_maxElectron << " " << nElectrons << " " << gammaDist << " " << wireCharge << std::endl;
487 }
488
489 // now digitize hits for R- and phi-strips
490 for (int measuresPhi = 0; measuresPhi <= 1; ++measuresPhi) {
491 float stripWidth = descriptor->cathodeReadoutPitch(chamberLayer, measuresPhi);
492 const int maxStrip = descriptor->maxNumberOfStrips(measuresPhi, stripWidth);
493
494 // now digitize hits for R-strips/phi-strips
495
496 if (measuresPhi == 0) { // R-strips :: find the charge+noise
497 double zz = pos_vec.z() + maxStrip * stripWidth * 0.50; // assuming zero offset
498 int strip = int(zz / stripWidth) + 1;
499 // find the charges induced on the phi strips
500
501 for (int j = strip - 4; j <= strip + 4; j++) {
502 double zpos = stripWidth * j - stripWidth * 0.50;
503 if (j > 0 && j <= maxStrip) {
504 double stripCharge = wireCharge * qStripR((zpos - zz) / stripWidth, HitId) * 0.50;
505
506 if (m_debug)
507 std::cout << "[CSC_Digitizer::digitize_hit] zpos = " << zpos << " zz = " << zz
508 << " diff = " << std::abs(zz - zpos) << " strip = " << j << " charge = " << stripCharge << std::endl;
509
510 IdentifierHash hashId = getHashId(HitId, j, measuresPhi);
511
512 fillMaps(hashId, driftTime, stripCharge, hashVec, data_map);
513
514 if (m_debug)
515 std::cout << "[CSC_Digitizer::digitize_hit] DriftTimeVSstripCharge " << driftTime << " " << stripCharge
516 << std::endl;
517 }
518 }
519 } else { // Phi-strips :: find the charge+noise
520 double yy = 0.0;
521 int strip = 0;
522
523 yy = pos_vec.y() + maxStrip * stripWidth * 0.5; // non-pointing phi-strips :: assuming zero offset
524 if (m_cscHitHelper->GetZSector(cscHit->CSCid()) > 0)
525 yy = -pos_vec.y() + maxStrip * stripWidth * 0.5; // non-pointing phi-strips :: assuming zero offset
526 strip = int(yy / stripWidth) + 1;
527
528 // find the charges induced on the phi strips
529 for (int j = strip - 1; j <= strip + 1; ++j) {
530 if (j > 0 && j <= maxStrip) {
531 double ypos = stripWidth * (j - 0.5);
532 double stripCharge = wireCharge * qStripPhi(ypos - yy, HitId) * 0.50;
533 if (m_debug)
534 std::cout << "[CSC_Digitizer::digitize_hit] ypos = " << ypos << " yy = " << yy
535 << " diff = " << std::abs(yy - ypos) << " strip = " << j << " charge = " << stripCharge << std::endl;
536
537 IdentifierHash hashId = getHashId(HitId, j, measuresPhi);
538
539 fillMaps(hashId, driftTime, stripCharge, hashVec, data_map);
540 }
541 }
542 }
543 }
544 }
545
546 return StatusCode::SUCCESS;
547}
548
549// public methods
550// 10/2010
551// New way of adding charges...
552// only care for samples...
553// charges are represented by samples...
554// and then in the end we need to convert them into one pair of time and charge (short term goal)
555// Long term goal, we need to change EDM to carry over sample charges to RDOCollection...
556void CSC_Digitizer::fillSampleMaps(const IdentifierHash hashId, const double driftTime, const double stripCharge,
557 std::vector<IdentifierHash>& hashVec, std::map<IdentifierHash, std::vector<float>>& data_map,
558 bool phase) {
559 if (stripCharge == 0.0) return;
560
561 // fill the CSC specific charge map the conversion hash -. id is done later !
562 if (data_map.find(hashId) != data_map.end()) {
563 float phaseOffset = (phase) ? +25 : 0;
564 std::vector<float> samples = m_pcalib->getSamplesFromBipolarFunc(driftTime + phaseOffset, stripCharge);
565 std::vector<float> existingSamples = data_map[hashId]; // assuming that there are four elements...
566
567 if (m_debug) {
568 std::cout << "[CSC_Digitizer::fillSampleMaps] ";
569
570 for (unsigned int i = 0; i < samples.size(); ++i) std::cout << samples[i] << " ";
571 std::cout << " + ";
572
573 for (unsigned int i = 0; i < existingSamples.size(); ++i) std::cout << existingSamples[i] << " ";
574
575 std::cout << " ==> ";
576 }
577
578 for (unsigned int i = 0; i < samples.size(); ++i) { existingSamples[i] += samples[i]; }
579
580 if (m_debug) {
581 for (unsigned int i = 0; i < existingSamples.size(); ++i) std::cout << existingSamples[i] << " ";
582 std::cout << std::endl;
583 }
584
585 data_map[hashId] = existingSamples;
586
587 } else {
588 data_map.insert(std::pair<IdentifierHash, std::vector<float>>(hashId, m_pcalib->getSamplesFromBipolarFunc(driftTime, stripCharge)));
589 hashVec.push_back(hashId);
590 }
591}
592
593void CSC_Digitizer::setWindow(const double t1, const double t2) {
596}
597
598void CSC_Digitizer::set(const double bunchTime) { m_bunchTime = bunchTime; }
599
600// Private methods d
601
602double CSC_Digitizer::qWire(const int& nElectrons, const double& gammaDist) const {
603 // find the charge on the wire
604
605 // double amplification = 0.58e5;
606 double amplification = m_amplification;
607 double wireCharge = 0.0;
608
609 for (int i = 0; i < nElectrons; ++i) {
610 double RNDpol = 0.0;
611 if (m_Polia > -1.0) { RNDpol = gammaDist / (1.0 + m_Polia); }
612 wireCharge += amplification * RNDpol;
613 }
614 return wireCharge;
615}
616
617// old implementation before Jan 2012:
618double CSC_Digitizer::qStripR(const double x) {
619 // induced charge on the r-strip
620 // parametrization based on experimental data
621
622 double rStripCharge = 0.0;
623 static constexpr std::array<double,4> Par{0.185, 2.315, 0.48, 5.2}; // obtained from test beam
624 double xx = std::abs(x) / 10.0; // divide by 10 to convert to cm!
625
626 rStripCharge = Par[0] * exp(-Par[1] * xx) + Par[2] * exp(-Par[3] * (xx * xx));
627
628 return rStripCharge;
629}
630
637double CSC_Digitizer::qStripR(const double x, const Identifier& id) const {
638 double stripCharge = 0.0;
639 double xx = x * x; // distance in strip widths squared
640
641 if (m_cscIdHelper->isSmall(id)) { // small chamber
642 stripCharge = 0.7001 / (1.0 + 1.38 * xx + 2.255 * xx * xx);
643 } else { // large chamber
644 stripCharge = 0.7 / (1.0 + 1.381 * xx + 2.248 * xx * xx);
645 }
646 return stripCharge;
647}
648
649double CSC_Digitizer::qStripPhi(const double x, const Identifier& id) const {
650 // parameters obtained from test beam
651 static constexpr std::array<double, 9> pSmall{.9092, .0634, -1.051, 8.05, -35.477, 58.883, -46.111, 17.446, -2.5824};
652 static constexpr std::array<double, 9> pLarge{.98, -.36, 5.07, -27.81, 72.257, -99.456, 72.778, -26.779, 3.9054};
653 double xx = std::abs(x) / 10.0; // divide by 10 to convert to cm!
654 double phiStripCharge = 0.0;
655
656 if (xx < 1.75) {
657 if (m_cscIdHelper->isSmall(id)) {
658 phiStripCharge = fparamPhi(xx, pSmall);
659 } else {
660 phiStripCharge = fparamPhi(xx, pLarge);
661 }
662 }
663
664 return phiStripCharge;
665}
666
667double CSC_Digitizer::fparamPhi(const double x, const std::array<double, 9>& p) {
668 double fparam{0}, pow {1.};
669 for (size_t i = 0; i < p.size(); ++i) {
670 fparam += p[i] * pow;
671 pow *= x;
672 }
673 return fparam;
674}
675
676bool CSC_Digitizer::outsideWindow(double driftTime) const {
677 // m_bunchTime is included already....updated one..
678 return driftTime < m_timeWindowLowerOffset || driftTime > m_timeWindowUpperOffset;
679}
680
681double CSC_Digitizer::getDriftTime(const MuonGM::CscReadoutElement* descriptor, const Amg::Vector3D& pos) const {
682 // need to be calculated correct - Garfield?
683 // assumption on the field lines not good but of for pileup stuff!
684 double time = -1000.0;
685 // tested with 60, 45, 30 and 60 looks the best 12/7/2009
686 double v0 = m_driftVelocity * 1.e-3; // mm/microsecond 6 cm/microsecond -> mm/ns
687 float anodeCathodeDist = descriptor->anodeCathodeDistance();
688 float roxacellWidth = descriptor->roxacellWidth();
689 float beta = std::atan((descriptor->longWidth() - descriptor->shortWidth()) / (2. * descriptor->lengthUpToMaxWidth()));
690 float longWidth = descriptor->longWidth() - 2 * roxacellWidth * (1 + std::sin(beta)) / std::cos(beta);
691 float yy = pos.y() + longWidth * 0.5;
692 float x0 = pos.x();
693 int wire = int(yy / anodeCathodeDist) + 1;
694 float y0 = (yy - wire * anodeCathodeDist);
695 if (std::abs(y0) > anodeCathodeDist / 2) y0 = std::abs(y0) - anodeCathodeDist * 0.5;
696 float driftDist = std::hypot(x0, y0); // Lorentz effect small
697 time = driftDist / v0;
698 return time;
699}
700
701// public methods
702// old way to add electron charges...
703// * represent electron charge with bipolar function
704// * add two charges with bipolar functions
705// * then extract charge and time out of function...
706//
707// Then, try to speed up (09/2010)
708// but it turns out to be vulernable for pileup simulation...
709void CSC_Digitizer::fillMaps(const IdentifierHash hashId, const double driftTime, const double stripCharge,
710 std::vector<IdentifierHash>& hashVec, std::map<IdentifierHash, std::pair<double, double>>& data_map) {
711 if (stripCharge == 0.0) return;
712
713 // fill the CSC specific charge map the conversion hash -. id is done later !
714 if (data_map.find(hashId) != data_map.end()) {
715 /*
716 http://indico.cern.ch/getFile.py/access?contribId=9&resId=0&materialId=slides&confId=106902
717 */
718 std::pair<double, double> result = m_pcalib->addBipfunc(data_map[hashId].first, data_map[hashId].second, driftTime, stripCharge);
719 // To check out conversion is correct...
720 if (m_debug)
721 std::cout << "[CSC_Digitizer::fillMaps] (" << data_map[hashId].first << ":" << int(data_map[hashId].second) << ")"
722 << "+(" << driftTime << ":" << int(stripCharge) << ")"
723 << " ==> " << result.first << ":" << int(result.second) << " e- which was "
724 << int(data_map[hashId].second + stripCharge) << std::endl;
725
726 data_map[hashId].first = result.first;
727 data_map[hashId].second = result.second;
728
729 } else {
730 data_map[hashId].first = driftTime;
731 data_map[hashId].second = stripCharge;
732 hashVec.push_back(hashId);
733 }
734}
735
736IdentifierHash CSC_Digitizer::getHashId(const Identifier& input_id, const int stripId, const int measuresPhi) const {
737 const int chamberLayer = m_cscIdHelper->chamberLayer(input_id);
738 const int wireLayer = m_cscIdHelper->wireLayer(input_id);
739 Identifier realHitId = m_cscIdHelper->channelID(input_id, chamberLayer, wireLayer, measuresPhi, stripId);
740 IdentifierHash hashId;
741 if (m_cscIdHelper->get_channel_hash(realHitId, hashId)) {
742 throw std::runtime_error(
743 Form("File: %s, Line: %d\nCSC_Digitizer::getHashId() - Failed to retrieve channel hash from identifier %llu", __FILE__,
744 __LINE__, realHitId.get_compact()));
745 }
746 return hashId;
747}
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define x
constexpr int pow(int base, int exp) noexcept
const Amg::Vector3D & getHitEnd() const
Definition CSCSimHit.h:52
int CSCid() const
Definition CSCSimHit.h:54
int particleID() const
Definition CSCSimHit.h:53
const Amg::Vector3D & getHitStart() const
Definition CSCSimHit.h:51
double meanTime() const
Definition CSCSimHit.h:90
double energyDeposit() const
Definition CSCSimHit.h:50
const CscHitIdHelper * m_cscHitHelper
static double fparamPhi(const double x, const std::array< double, 9 > &p)
void fillMaps(const IdentifierHash hash, const double driftTime, const double stripCharge, std::vector< IdentifierHash > &hashVec, std::map< IdentifierHash, std::pair< double, double > > &data_map)
StatusCode initialize()
double m_amplification
static constexpr int s_maxElectron
double qStripPhi(const double x, const Identifier &id) const
std::map< char, int > m_stationDict
Cache the csc id dictionary.
double m_electronEnergy
double getDriftTime(const MuonGM::CscReadoutElement *descriptor, const Amg::Vector3D &pos) const
void fillSampleMaps(const IdentifierHash hash, const double driftTime, const double stripCharge, std::vector< IdentifierHash > &hashVec, std::map< IdentifierHash, std::vector< float > > &data_map, bool phase=0)
static double qStripR(const double x)
double m_driftVelocity
void setWindow(const double t1, const double t2)
const CscIdHelper * m_cscIdHelper
const MuonGM::MuonDetectorManager * m_muonMgr
std::array< double, s_maxElectron > m_sprob
IdentifierHash getHashId(const Identifier &input_id, const int stripId, const int measuresPhi) const
ICscCalibTool * m_pcalib
double qWire(const int &nElectrons, const double &gammaDist) const
bool m_NInterFromEnergyLoss
StatusCode digitize_hit(const CSCSimHit *cscHit, std::vector< IdentifierHash > &hashVec, std::map< IdentifierHash, std::pair< double, double > > &data_map, CLHEP::HepRandomEngine *rndmEngine)
Old way before 10/2010.
CSC_Digitizer(const CscHitIdHelper *cscHitHelper, const MuonGM::MuonDetectorManager *muonMgr, ICscCalibTool *pcalib)
double m_timeWindowUpperOffset
double m_timeWindowLowerOffset
bool outsideWindow(double time) const
void set(const double bunchTime)
Identifier to_identifier(const CSCSimHit *cscHit) const
This is a "hash" representation of an Identifier.
value_type get_compact() const
Get the compact id.
double cathodeReadoutPitch(int chLayer, int measuresPhi) const
int maxNumberOfStrips(int measuresPhi) const
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
Eigen::Matrix< double, 3, 1 > Vector3D
Ensure that the Athena extensions are properly loaded.
Definition GeoMuonHits.h:27