ATLAS Offline Software
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 
10 #include "AtlasHepMC/GenParticle.h"
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"
18 #include "StoreGate/StoreGateSvc.h"
19 
20 using namespace MuonGM;
21 
22 // Constructors
23 CSC_Digitizer::CSC_Digitizer(const CscHitIdHelper* cscHitHelper, const MuonDetectorManager* muonMgr, ICscCalibTool* pcalib) :
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 
51 Identifier CSC_Digitizer::to_identifier(const CSCSimHit* cscHit) const {
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 
67 StatusCode 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 
235 StatusCode 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 
396 StatusCode 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...
556 void 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 
593 void CSC_Digitizer::setWindow(const double t1, const double t2) {
596 }
597 
598 void CSC_Digitizer::set(const double bunchTime) { m_bunchTime = bunchTime; }
599 
600 // Private methods d
601 
602 double 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:
618 double 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 
637 double 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 
649 double 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 
667 double 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 
677  // m_bunchTime is included already....updated one..
678  return driftTime < m_timeWindowLowerOffset || driftTime > m_timeWindowUpperOffset;
679 }
680 
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...
709 void 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 
736 IdentifierHash 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 }
CSC_Digitizer::CSC_Digitizer
CSC_Digitizer(const CscHitIdHelper *cscHitHelper, const MuonGM::MuonDetectorManager *muonMgr, ICscCalibTool *pcalib)
Definition: CSC_Digitizer.cxx:23
CSCSimHit::getHitEnd
const Amg::Vector3D & getHitEnd() const
Definition: CSCSimHit.h:52
CSC_Digitizer::setWindow
void setWindow(const double t1, const double t2)
Definition: CSC_Digitizer.cxx:593
python.SystemOfUnits.second
int second
Definition: SystemOfUnits.py:120
ReadOfcFromCool.phase
phase
Definition: ReadOfcFromCool.py:127
MuonGM
Ensure that the Athena extensions are properly loaded.
Definition: GeoMuonHits.h:27
MuonGM::CscReadoutElement::anodeCathodeDistance
double anodeCathodeDistance() const
Definition: CscReadoutElement.h:306
get_generator_info.result
result
Definition: get_generator_info.py:21
SiliconTech::strip
@ strip
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
phi
Scalar phi() const
phi method
Definition: AmgMatrixBasePlugin.h:64
PlotCalibFromCool.yy
yy
Definition: PlotCalibFromCool.py:714
CSC_Digitizer::m_timeWindowLowerOffset
double m_timeWindowLowerOffset
Definition: CSC_Digitizer.h:104
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
CalibDbCompareRT.st_str
st_str
Definition: CalibDbCompareRT.py:94
CSC_Digitizer::getDriftTime
double getDriftTime(const MuonGM::CscReadoutElement *descriptor, const Amg::Vector3D &pos) const
Definition: CSC_Digitizer.cxx:681
CSC_Digitizer::m_cscIdHelper
const CscIdHelper * m_cscIdHelper
Definition: CSC_Digitizer.h:95
dumpTgcDigiDeadChambers.stationName
dictionary stationName
Definition: dumpTgcDigiDeadChambers.py:30
eta
Scalar eta() const
pseudorapidity method
Definition: AmgMatrixBasePlugin.h:79
MuonGM::CscReadoutElement::lengthUpToMaxWidth
double lengthUpToMaxWidth() const
Definition: CscReadoutElement.h:302
CSCSimHit::CSCid
int CSCid() const
Definition: CSCSimHit.h:54
CSC_Digitizer::m_driftVelocity
double m_driftVelocity
Definition: CSC_Digitizer.h:108
conifer::pow
constexpr int pow(int x)
Definition: conifer.h:20
ALFA_EventTPCnv_Dict::t1
std::vector< ALFA_RawDataCollection_p1 > t1
Definition: ALFA_EventTPCnvDict.h:43
CSC_Digitizer::m_stationDict
std::map< char, int > m_stationDict
Cache the csc id dictionary.
Definition: CSC_Digitizer.h:111
CSC_Digitizer::m_bunchTime
double m_bunchTime
Definition: CSC_Digitizer.h:106
MuonGM::CscReadoutElement
Definition: CscReadoutElement.h:56
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
drawFromPickle.cos
cos
Definition: drawFromPickle.py:36
drawFromPickle.exp
exp
Definition: drawFromPickle.py:36
covarianceTool.prob
prob
Definition: covarianceTool.py:678
x
#define x
CSCSimHit::energyDeposit
double energyDeposit() const
Definition: CSCSimHit.h:50
GenParticle.h
CscHitIdHelper::GetChamberLayer
int GetChamberLayer(const int &hid) const
Definition: CscHitIdHelper.cxx:78
drawFromPickle.atan
atan
Definition: drawFromPickle.py:36
CscHitIdHelper::GetPhiSector
int GetPhiSector(const int &hid) const
Definition: CscHitIdHelper.cxx:67
MuonIdHelper::isSmall
bool isSmall(const Identifier &id) const
Definition: MuonIdHelper.cxx:835
CSC_Digitizer::m_cscHitHelper
const CscHitIdHelper * m_cscHitHelper
Definition: CSC_Digitizer.h:93
MuonGM::CscReadoutElement::shortWidth
double shortWidth() const
Definition: CscReadoutElement.h:294
CscIdHelper::wireLayer
int wireLayer(const Identifier &id) const
Definition: CscIdHelper.cxx:772
CSC_Digitizer::m_sprob
std::array< double, s_maxElectron > m_sprob
Definition: CSC_Digitizer.h:103
CSC_Digitizer::m_Polia
double m_Polia
Definition: CSC_Digitizer.h:102
CSC_Digitizer::fillSampleMaps
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)
Definition: CSC_Digitizer.cxx:556
CSC_Digitizer::fillMaps
void fillMaps(const IdentifierHash hash, const double driftTime, const double stripCharge, std::vector< IdentifierHash > &hashVec, std::map< IdentifierHash, std::pair< double, double > > &data_map)
Definition: CSC_Digitizer.cxx:709
CSC_Digitizer::qWire
double qWire(const int &nElectrons, const double &gammaDist) const
Definition: CSC_Digitizer.cxx:602
CSCSimHit
Definition: CSCSimHit.h:18
MuonGM::CscReadoutElement::maxNumberOfStrips
int maxNumberOfStrips(int measuresPhi) const
Definition: CscReadoutElement.cxx:162
CSC_Digitizer.h
TRT::Hit::driftTime
@ driftTime
Definition: HitInfo.h:43
CSCSimHit::particleID
int particleID() const
Definition: CSCSimHit.h:53
parseMapping.v0
def v0
Definition: parseMapping.py:149
lumiFormat.i
int i
Definition: lumiFormat.py:92
CSC_Digitizer::qStripPhi
double qStripPhi(const double x, const Identifier &id) const
Definition: CSC_Digitizer.cxx:649
CSC_Digitizer::set
void set(const double bunchTime)
Definition: CSC_Digitizer.cxx:598
MuonGM::MuonDetectorManager::getCscReadoutElement
const CscReadoutElement * getCscReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
Definition: MuonDetDescr/MuonReadoutGeometry/src/MuonDetectorManager.cxx:225
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
01SubmitToGrid.samples
samples
Definition: 01SubmitToGrid.py:58
CscHitIdHelper
Definition: CscHitIdHelper.h:13
CSC_Digitizer::getHashId
IdentifierHash getHashId(const Identifier &input_id, const int stripId, const int measuresPhi) const
Definition: CSC_Digitizer.cxx:736
CSC_Digitizer::m_electronEnergy
double m_electronEnergy
Definition: CSC_Digitizer.h:100
CscReadoutElement.h
CscHitIdHelper::GetWireLayer
int GetWireLayer(const int &hid) const
Definition: CscHitIdHelper.cxx:83
ICscCalibTool
Definition: ICscCalibTool.h:24
CSC_Digitizer::m_timeWindowUpperOffset
double m_timeWindowUpperOffset
Definition: CSC_Digitizer.h:105
MuonGM::CscReadoutElement::roxacellWidth
double roxacellWidth() const
Definition: CscReadoutElement.h:300
MuonGM::CscReadoutElement::longWidth
double longWidth() const
Definition: CscReadoutElement.h:298
CSCSimHit::meanTime
double meanTime() const
Definition: CSCSimHit.h:90
MuonIdHelper::get_channel_hash
virtual int get_channel_hash(const Identifier &id, IdentifierHash &hash_id) const
Definition: MuonIdHelper.cxx:138
CSC_Digitizer::m_debug
int m_debug
Definition: CSC_Digitizer.h:109
CscIdHelper::channelID
Identifier channelID(int stationName, int stationEta, int stationPhi, int chamberLayer, int wireLayer, int measuresPhi, int strip) const
Definition: CscIdHelper.cxx:706
dumpNswErrorDb.maxStrip
tuple maxStrip
Definition: dumpNswErrorDb.py:27
ICscCalibTool::addBipfunc
virtual std::pair< double, double > addBipfunc(const double driftTime0, const double stripCharge0, const double driftTime1, const double stripCharge1) const =0
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
CSC_Digitizer::outsideWindow
bool outsideWindow(double time) const
Definition: CSC_Digitizer.cxx:676
CscHitIdHelper::GetStationName
std::string GetStationName(const int &hid) const
Definition: CscHitIdHelper.cxx:56
CSC_Digitizer::fparamPhi
static double fparamPhi(const double x, const std::array< double, 9 > &p)
Definition: CSC_Digitizer.cxx:667
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:18
CscHitIdHelper::GetZSector
int GetZSector(const int &hid) const
Definition: CscHitIdHelper.cxx:72
CSCSimHit::getHitStart
const Amg::Vector3D & getHitStart() const
Definition: CSCSimHit.h:51
CSC_Digitizer::initialize
StatusCode initialize()
Definition: CSC_Digitizer.cxx:31
ALFA_EventTPCnv_Dict::t2
std::vector< ALFA_RawDataContainer_p1 > t2
Definition: ALFA_EventTPCnvDict.h:44
CSC_Digitizer::digitize_hit
StatusCode digitize_hit(const CSCSimHit *cscHit, std::vector< IdentifierHash > &hashVec, std::map< IdentifierHash, std::pair< double, double > > &data_map, CLHEP::HepRandomEngine *rndmEngine)
CSC_Digitizer::m_muonMgr
const MuonGM::MuonDetectorManager * m_muonMgr
Definition: CSC_Digitizer.h:94
CaloSwCorrections.time
def time(flags, cells_name, *args, **kw)
Definition: CaloSwCorrections.py:242
ICscCalibTool::getSamplesFromBipolarFunc
virtual std::vector< float > getSamplesFromBipolarFunc(const double driftTime0, const double stripCharge0) const =0
MuonGM::MuonDetectorManager
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/MuonDetectorManager.h:49
DeMoScan.first
bool first
Definition: DeMoScan.py:534
CSC_Digitizer::to_identifier
Identifier to_identifier(const CSCSimHit *cscHit) const
Definition: CSC_Digitizer.cxx:51
CSC_Digitizer::m_NInterFromEnergyLoss
bool m_NInterFromEnergyLoss
Definition: CSC_Digitizer.h:99
LArCellBinning.step
step
Definition: LArCellBinning.py:158
CSC_Digitizer::m_pcalib
ICscCalibTool * m_pcalib
Definition: CSC_Digitizer.h:96
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
MuonParameters::beta
@ beta
Definition: MuonParamDefs.h:144
CSC_Digitizer::s_maxElectron
static constexpr int s_maxElectron
Definition: CSC_Digitizer.h:98
StoreGateSvc.h
CSC_Digitizer::qStripR
static double qStripR(const double x)
Definition: CSC_Digitizer.cxx:618
CscIdHelper::chamberLayer
int chamberLayer(const Identifier &id) const
Definition: CscIdHelper.cxx:770
fitman.k
k
Definition: fitman.py:528
CSC_Digitizer::m_amplification
double m_amplification
Definition: CSC_Digitizer.h:107
MuonGM::CscReadoutElement::cathodeReadoutPitch
double cathodeReadoutPitch(int chLayer, int measuresPhi) const
Definition: CscReadoutElement.cxx:147