ATLAS Offline Software
Loading...
Searching...
No Matches
RpcDigiTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4#include "RpcDigiTool.h"
5
6#include "CLHEP/Random/RandGaussZiggurat.h"
7#include "GaudiKernel/SystemOfUnits.h"
11
12namespace {
13 constexpr double percentage(unsigned int numerator, unsigned int denom) {
14 return 100. * numerator / std::max(denom, 1u);
15 }
16 using ChVec_t = std::vector<std::uint16_t>;
18 static const SG::Decorator<ChVec_t> dec_phiChannel{"SDO_phiChannels"};
19 static const SG::Decorator<ChVec_t> dec_etaChannel{"SDO_etaChannels"};
20
21} // namespace
22namespace MuonR4 {
23
26 ATH_CHECK(m_writeKey.initialize());
27 ATH_CHECK(m_effiDataKey.initialize(!m_effiDataKey.empty()));
28 return StatusCode::SUCCESS;
29}
30
32 ATH_MSG_INFO("Tried to convert "
33 << m_allHits[0] << "/" << m_allHits[1] << " hits. In, "
34 << percentage(m_acceptedHits[0], m_allHits[0]) << "/"
35 << percentage(m_acceptedHits[1], m_allHits[1])
36 << "% of the cases, the conversion was successful");
37 return StatusCode::SUCCESS;
38}
39
40
41 double RpcDigiTool::getTOT(const double aCharge) const {
42 // This is a parameterization of BIRPC TOT (ns) values corresponding to
43 // a charge (fC), it was obtained from a detailed model for
44 // RPC signal emulation.
45 // See presentation by L. Pezzotti: https://indico.cern.ch/event/1602299/contributions/6751266/attachments/3160083/5614107/lopezzot_muonsw_23_10_2025.pdf
46 constexpr std::array<double, 3> coeffs{19.9587, 0.10081, -0.00017};
47 using namespace Acts::detail;
48
49 return polynomialSum(aCharge, coeffs);
50 }
51 double RpcDigiTool::getTOA(const double aDistance) const {
52 // A 2.0 ns offset is due to the signal formation and is obtained from a detailed model for RPC signal emulation.
53 // See presentation by L. Pezzotti: https://indico.cern.ch/event/1602299/contributions/6751266/attachments/3160083/5614107/lopezzot_muonsw_23_10_2025.pdf
54
55 return aDistance/m_propagationVelocity+2.0;
56 }
57
58StatusCode
59RpcDigiTool::digitize(const EventContext &ctx, const TimedHits &hitsToDigit,
60 xAOD::MuonSimHitContainer *sdoContainer) const {
61 const RpcIdHelper &idHelper{m_idHelperSvc->rpcIdHelper()};
62 // Prepare the temporary cache
63 DigiCache digitCache{};
65 const Muon::DigitEffiData *efficiencyMap{nullptr};
66 ATH_CHECK(SG::get(efficiencyMap, m_effiDataKey, ctx));
67
68 CLHEP::HepRandomEngine *rndEngine = getRandomEngine(ctx);
69 xAOD::ChamberViewer viewer{hitsToDigit, m_idHelperSvc.get()};
70 do {
71 DeadTimeMap deadTimes{};
72 for (const TimedHit &simHit : viewer) {
73 if (m_digitizeMuonOnly && !MC::isMuon(simHit)) {
74 continue;
75 }
76 const Identifier hitId{simHit->identify()};
77 RpcDigitCollection *digiColl = fetchCollection(hitId, digitCache);
78 const std::size_t beforeDigiSize = digiColl->size();
79 xAOD::MuonSimHit* sdo{nullptr};
80 if (m_detMgr->getRpcReadoutElement(hitId)->nPhiStrips() > 0) {
82
83 const bool digitizedPhi = digitizeHit(simHit, true, efficiencyMap,
84 *digiColl, rndEngine, deadTimes);
85 const bool digitizedEta = digitizeHit(simHit, false, efficiencyMap,
86 *digiColl, rndEngine, deadTimes);
87 if (digitizedEta || digitizedPhi) {
88 sdo = addSDO(simHit, sdoContainer);
89 }
90 } else if (digitizeHitBI(simHit, efficiencyMap, *digiColl, rndEngine,
91 deadTimes)) {
92 sdo = addSDO(simHit, sdoContainer);
93 }
94 if (sdo) {
95 sdo->setIdentifier(digiColl->back()->identify());
96 dec_etaChannel(*sdo).clear();
97 dec_phiChannel(*sdo).clear();
98 for (std::size_t newDigit = beforeDigiSize; newDigit< digiColl->size(); ++newDigit) {
99 const Identifier id = digiColl->at(newDigit)->identify();
100 ChVec_t& ch{idHelper.measuresPhi(id)? dec_phiChannel(*sdo) : dec_etaChannel(*sdo)};
101 ch.push_back(idHelper.channel(id));
102 }
103 }
104 }
105 } while (viewer.next());
107 ATH_CHECK(writeDigitContainer(ctx, m_writeKey, std::move(digitCache),
108 idHelper.module_hash_max()));
109 return StatusCode::SUCCESS;
110}
111bool RpcDigiTool::digitizeHit(const TimedHit &simHit, const bool measuresPhi,
112 const Muon::DigitEffiData *effiMap,
113 RpcDigitCollection &outContainer,
114 CLHEP::HepRandomEngine *rndEngine,
115 DeadTimeMap &deadTimes) const {
116
117 ++(m_allHits[measuresPhi]); // Count all hits separately for eta and phi ([0] and [1], respectively)
118
119 const Identifier gasGapId = simHit->identify();
120 const MuonGMR4::RpcReadoutElement *reEle =
121 m_detMgr->getRpcReadoutElement(gasGapId);
122
123 const RpcIdHelper &idHelper{m_idHelperSvc->rpcIdHelper()};
124
125 bool isValid{false};
126
127 const Identifier layerId = idHelper.channelID(
128 gasGapId, idHelper.doubletZ(gasGapId), idHelper.doubletPhi(gasGapId),
129 idHelper.gasGap(gasGapId), measuresPhi, 1, isValid);
130 const IdentifierHash layHash = reEle->layerHash(gasGapId);
131
132 const MuonGMR4::StripLayerPtr &layerDesign =
133 reEle->sensorLayout(reEle->layerHash(layerId));
134
135 const MuonGMR4::StripDesign &design{layerDesign->design(measuresPhi)};
136
137 Amg::Vector3D locHitPos{xAOD::toEigen(simHit->localPosition())};
138
139 const Amg::Vector2D locPos2D = layerDesign->to2D(locHitPos, measuresPhi);
140 if (!design.insideTrapezoid(locPos2D)) {
141 ATH_MSG_VERBOSE("The hit " << Amg::toString(locHitPos) << " / "
142 << Amg::toString(locPos2D)
143 << " is outside of the trapezoid bounds for "
144 << m_idHelperSvc->toString(layerId));
145 return false;
146 }
147 const int strip = design.stripNumber(locPos2D);
148 if (strip < 0) {
149 ATH_MSG_VERBOSE("Hit " << Amg::toString(locHitPos) << " / "
150 << Amg::toString(locPos2D)
151 << " cannot trigger any signal in a strip for "
152 << m_idHelperSvc->toString(layerId) << std::endl
153 << design);
154 return false;
155 }
156
157 // Check whether the digit is actually efficient
158 const bool effiSignal =
159 !effiMap || effiMap->getEfficiency(gasGapId) >=
160 CLHEP::RandFlat::shoot(rndEngine, 0., 1.);
161 if (!effiSignal) return false;
162
163 // Calculate distance from readout
164 const double DistanceToEdge =
165 reEle->distanceToEdge(layHash, locHitPos, EdgeSide::readOut); // mm
166
167 // Calculate charge deposited
168 const double TotalChargeOnStrip =
169 calculateChargeOnStrip(simHit, rndEngine, 2.0); // 2 mm gap for BM/BO chambers
170 ATH_MSG_VERBOSE(" total charge (fC): " << TotalChargeOnStrip);
171
172 // Calculate cluster size (number of strips)
173 int clusterSize = determineClusterSize(gasGapId, rndEngine, false);
174 ATH_MSG_VERBOSE(" cluster size: " << clusterSize);
175
176 // Get min and max strips
177 int minStrip{strip}, maxStrip{strip}; // case strip number is 1
178 if (clusterSize > 1) {
179 int halfCluster = clusterSize / 2; // half cluster size (int)
180 minStrip = strip - halfCluster; // min strip number
181 if (clusterSize % 2 == 0) { // if clusterSize is even, we have to randomly
182 // assign one strip on left or right side
183 int side = Acts::copySign(1,CLHEP::RandFlat::shoot(rndEngine, 0., 1.) + 0.5);
184 minStrip += side; // if side==1 move the min strip to right
185 }
186 maxStrip = minStrip + clusterSize - 1;
187 // Check design strip boundaries
188 minStrip = std::max(minStrip, design.firstStripNumber());
189 maxStrip = std::min(design.firstStripNumber() + design.numStrips() - 1, maxStrip);
190 }
191
192 // Recalculate cluster size with minStrip and maxStrip
193 clusterSize = (maxStrip - minStrip) + 1;
194
195 // Divide charge on N strips
196 const std::vector<double> StripCharges =
197 divideChargeOnStrips(TotalChargeOnStrip, clusterSize, rndEngine);
198
199 // Digitize each strip
200 bool hasAcceptedStrip=false;
201 for (int aStrip = minStrip; aStrip <= maxStrip; aStrip++) {
202
203 bool isValid{false};
204 const Identifier digitId{idHelper.channelID(
205 gasGapId, idHelper.doubletZ(gasGapId), idHelper.doubletPhi(gasGapId),
206 idHelper.gasGap(gasGapId), measuresPhi, aStrip, isValid)};
207
208 // Check digitID is valid
209 if (!isValid) {
210 ATH_MSG_WARNING("Failed to create a valid strip "
211 << m_idHelperSvc->toStringGasGap(gasGapId)
212 << ", strip: " << aStrip);
213 return false;
214 }
215 // Check is not dead time
216 if (!passDeadTime(digitId, hitTime(simHit), m_deadTime, deadTimes)) {
217 ATH_MSG_VERBOSE("Reject hit due to dead map constraint");
218 return false;
219 }
220
221 outContainer.push_back(std::make_unique<RpcDigit>(
222 digitId,
223 hitTime(simHit) + getTOA(DistanceToEdge) + CLHEP::RandGaussZiggurat::shoot(rndEngine, 0.0, m_stripTimeResolution),
224 getTOT(StripCharges[aStrip-minStrip])));
225
226 ATH_MSG_VERBOSE("Digitize hit "
227 << m_idHelperSvc->toString(digitId)
228 << " located at: " << Amg::toString(locHitPos) );
229 ++(m_acceptedHits[measuresPhi]); // Count accepted hits for eta ([0]) or phi ([1])
230 hasAcceptedStrip=true;
231 }
232
233 return hasAcceptedStrip;
234}
235
236
238 const Muon::DigitEffiData *effiMap,
239 RpcDigitCollection &outContainer,
240 CLHEP::HepRandomEngine *rndEngine,
241 DeadTimeMap &deadTimes) const {
242
243 ++(m_allHits[false]); // Count all hits for eta ([0]) since there are no phi strips in BI chambers
244 const Identifier gasGapId = simHit->identify();
245 const MuonGMR4::RpcReadoutElement *reEle =
246 m_detMgr->getRpcReadoutElement(gasGapId);
247 const Amg::Vector3D locHitPos = xAOD::toEigen(simHit->localPosition());
248 const MuonGMR4::StripDesign &design{*reEle->getParameters().etaDesign};
249 const RpcIdHelper &idHelper{m_idHelperSvc->rpcIdHelper()};
250
251 /* with RpcReadoutElement reEle you can access infor about the readout like */
252 ATH_MSG_VERBOSE("RpcDigiTool::digitizeHitBI reEle->nGasGaps "<< reEle->nGasGaps());
253 /* with StripDesign you can access the strip information of the readout
254 * element for instance: */
255 ATH_MSG_VERBOSE("RpcDigiTool::digitizeHitBI design: "<< design);
256
257 // Check the correctness of the local hit position
258 const Amg::Vector2D locHitPosition{locHitPos.x(), locHitPos.y()};
259 if (!design.insideTrapezoid(locHitPosition)) {
260 ATH_MSG_VERBOSE("The hit " << Amg::toString(locHitPosition)
261 << " is outside of the trapezoid bounds for "
262 << m_idHelperSvc->toStringGasGap(gasGapId));
263 return false;
264 }
265
266 // Calculate distance to strip edges (mm)
267 const IdentifierHash layHash = reEle->layerHash(gasGapId);
268 const double DistanceToReadOut =
269 reEle->distanceToEdge(layHash, locHitPos, EdgeSide::readOut); // mm
270 const double DistanceToHV =
271 reEle->distanceToEdge(layHash, locHitPos, EdgeSide::highVoltage); // mm
272
273 // Calculate charge deposited
274 const double TotalChargeOnStrip =
275 calculateChargeOnStrip(simHit, rndEngine, 1.0); // 1 mm gap for BI chambers
276 ATH_MSG_VERBOSE(" total charge (fC): " << TotalChargeOnStrip);
277
278 // Calculate cluster size (number of strips)
279 int clusterSize = determineClusterSize(gasGapId, rndEngine, true);
280 ATH_MSG_VERBOSE(" cluster size: " << clusterSize);
281
282 // Get corresponding strip number and apply checks
283 const int strip = design.stripNumber(locHitPosition);
284 if (strip < 0) {
285 ATH_MSG_VERBOSE("Hit " << Amg::toString(locHitPosition)
286 << " cannot trigger any signal in a strip for "
287 << m_idHelperSvc->toStringGasGap(gasGapId)
288 << std::endl
289 << design);
290 return false;
291 }
292
293 // Check whether the digit is actually efficient
294 const bool effiSignal1 =
295 !effiMap || effiMap->getEfficiency(gasGapId) >=
296 CLHEP::RandFlat::shoot(rndEngine, 0., 1.);
297 const bool effiSignal2 =
298 !effiMap || effiMap->getEfficiency(gasGapId) >=
299 CLHEP::RandFlat::shoot(rndEngine, 0., 1.);
300 if (!effiSignal1 && !effiSignal2) return false;
301
302 // Get min and max strips
303 int minStrip{strip}, maxStrip{strip}; // case strip number is 1
304 if (clusterSize > 1) {
305 int halfCluster = clusterSize / 2; // half cluster size (int)
306 minStrip = strip - halfCluster; // min strip number
307 if (clusterSize % 2 == 0) { // if clusterSize is even, we have to randomly
308 // assign one strip on left or right side
309 int side = Acts::copySign(1,CLHEP::RandFlat::shoot(rndEngine, 0., 1.) + 0.5);
310 minStrip += side; // if side==1 move the min strip to right
311 }
312 maxStrip = minStrip + clusterSize - 1;
313 // Check design strip boundaries
314 minStrip = std::max(minStrip, design.firstStripNumber());
315 maxStrip = std::min(design.firstStripNumber() + design.numStrips() - 1, maxStrip);
316 }
317
318 // Recalculate cluster size with minStrip and maxStrip
319 clusterSize = (maxStrip - minStrip) + 1;
320
321 // Divide charge on N strips
322 const std::vector<double> StripCharges =
323 divideChargeOnStrips(TotalChargeOnStrip, clusterSize, rndEngine);
324
325 // Digitize each strip
326 bool hasAcceptedStrip=false;
327 for (int aStrip = minStrip; aStrip <= maxStrip; aStrip++) {
328 bool isValid{false};
329 const Identifier digitId{idHelper.channelID(
330 gasGapId, idHelper.doubletZ(gasGapId), idHelper.doubletPhi(gasGapId),
331 idHelper.gasGap(gasGapId), false, aStrip, isValid)};
332
333 // Check digitID is valid
334 if (!isValid) {
335 ATH_MSG_WARNING("Failed to create a valid strip "
336 << m_idHelperSvc->toStringGasGap(gasGapId)
337 << ", strip: " << aStrip);
338 return false;
339 }
340 // Check is not dead time
341 if (!passDeadTime(digitId, hitTime(simHit), m_deadTime, deadTimes)) {
342 ATH_MSG_VERBOSE("Reject hit due to dead map constraint");
343 return false;
344 }
345
346 if (effiSignal1) {
347 outContainer.push_back(std::make_unique<RpcDigit>(
348 digitId,
349 hitTime(simHit) + getTOA(DistanceToHV) + CLHEP::RandGaussZiggurat::shoot(rndEngine, 0.0, m_stripTimeResolution),
350 getTOT(StripCharges[aStrip-minStrip])));
351 }
352 if (effiSignal2) {
353 outContainer.push_back(std::make_unique<RpcDigit>(
354 digitId,
355 hitTime(simHit) + getTOA(DistanceToReadOut) + CLHEP::RandGaussZiggurat::shoot(rndEngine, 0.0, m_stripTimeResolution),
356 getTOT(StripCharges[aStrip-minStrip]), true));
357 }
358 if (effiSignal1 || effiSignal2) {
359 ATH_MSG_VERBOSE("Digitize hit "
360 << m_idHelperSvc->toString(digitId)
361 << " located at: " << Amg::toString(locHitPos)
362 << ", SDO: " << Amg::toString(locHitPosition));
363 ++(m_acceptedHits[false]); // Count accepted hits for eta ([0]) since there are no phi strips in BI chambers
364 hasAcceptedStrip=true;
365 }
366 }
367
368 return hasAcceptedStrip;
369}
370
371std::vector<double>
372RpcDigiTool::divideChargeOnStrips(double totalCharge, int n_strips,
373 CLHEP::HepRandomEngine *rndmEngine) const {
374
375 std::vector<double> charges;
376
377 switch (n_strips) {
378 case 1: {
379 // Trivial case, all charge on a single strip
380 charges.push_back(totalCharge);
381 break;
382 }
383 case 2: {
384 // We use a Gaussian distribution centered over 0.5 to simulate
385 // a charge sharing that is on average 50/50 but includes fluctuations
386 double f = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.5, 0.15);
387
388 // Make sure fraction is bounded between 0 and 1
389 f = std::clamp(f, 0., 1.);
390
391 charges.push_back(f * totalCharge);
392 charges.push_back((1.0 - f) * totalCharge);
393 break;
394 }
395 case 3: {
396 // These fractions are guesses on a reasonable charge
397 // sharing when three strips are activated.
398 // These fractions must be updated once the final
399 // distributions of TOT from Phase-II BI RPCs
400 // are available.
401 charges.push_back(0.20 * totalCharge); // left strip
402 charges.push_back(0.60 * totalCharge); // center strip
403 charges.push_back(0.20 * totalCharge); // right strip
404 break;
405 }
406 case 4: {
407 // These fractions are guesses on a reasonable charge
408 // sharing when four strips are activated.
409 // These fractions must be updated once the final
410 // distributions of TOT from Phase-II BI RPCs
411 // are available.
412 charges.push_back(0.15 * totalCharge); // left external strip
413 charges.push_back(0.35 * totalCharge); // left internal strip
414 charges.push_back(0.35 * totalCharge); // right internal strip
415 charges.push_back(0.15 * totalCharge); // right external strip
416 break;
417 }
418 default: {
419 // return empy vector
420 break;
421 }
422 }
423
424 return charges;
425}
426
428 CLHEP::HepRandomEngine *rndmEngine,
429 const double gasGapSize) const {
430
431 // Average energy to create an electron-ion pair inside RPC gas
432 constexpr double W_VALUE_EV = 30.0; // Unit: [eV/pair]
433
434 // RPC BI gas gap thickness
435 const double GAP_THICKNESS_MM = gasGapSize; // Unit: [mm] (1 mm for Phase-II BI RPCs, 2 mm for BM/BO RPCs))
436
437 // Townsend coefficient for gas mixture and operational voltage
438 constexpr double ALPHA_PER_MM = 5.5; // Unit: [1/mm]
439
440 // Energy deposited by Geant4
441 const double energy_deposit_ev = simHit->energyDeposit() / Gaudi::Units::eV;
442
443 // Number of electron-ion pairs created
444 const double N0 = energy_deposit_ev / W_VALUE_EV;
445
446 // Primary ionization poistion inside gas gap
447 const double z_hit_mm =
448 CLHEP::RandFlat::shoot(rndmEngine, 0.0, GAP_THICKNESS_MM); // Unit: [mm]
449
450 // Distance to anode
451 const double z_drift_mm = std::abs(GAP_THICKNESS_MM - z_hit_mm); // Unit: [mm]
452
453 // Avalanche gain
454 const double gas_gain = std::exp(ALPHA_PER_MM * z_drift_mm);
455
456 // Total charge
457 const double total_charge_c = N0 * gas_gain * Gaudi::Units::e_SI; // Unit: [C]
458
459 ATH_MSG_DEBUG(__func__<<"() - "<<__LINE__<<" GAP_THICKNESS_MM: "<<GAP_THICKNESS_MM<<
460 ", "<<energy_deposit_ev<<", z_hit_mm: "<<z_hit_mm<<", N0: "<<N0<<", z_drift_mm: "<<z_drift_mm
461 <<", gas_gain: "<<gas_gain<< "---> Charge on strip (fC): " << total_charge_c * 1e15);
462
463 return total_charge_c * 1e15; // charge in fC
464}
465
467 const Identifier &idGasGap, CLHEP::HepRandomEngine *rndmEngine, bool isBIRPC) const {
468
469 const RpcIdHelper &id_helper{m_idHelperSvc->rpcIdHelper()};
470
471 ATH_MSG_DEBUG("RpcDigitizationTool::in determineClusterSize");
472
473 ATH_MSG_DEBUG("Digit Id = " << id_helper.show_to_string(idGasGap));
474
475 // These cluster size probabilities were taken from the legacy RPC code.
476 // MuonSpectrometer/MuonConfig/python/RPC_DigitizationConfig.py
477 static constexpr std::array<double, 4> ClusterSizeProbabilities{0.610, 0.260,
478 0.083, 0.047};
479 // Compile-time calculation of the cumulative array
480 // Used empty capture list [] since variables are static constexpr
481 static constexpr std::array<double, 4> cumulative = []() {
482 std::array<double, 4> acumulative{};
483 acumulative[0] = ClusterSizeProbabilities[0];
484 for (size_t i = 1; i < ClusterSizeProbabilities.size(); ++i) {
485 acumulative[i] = acumulative[i - 1] + ClusterSizeProbabilities[i];
486 }
487 return acumulative;
488 }();
489
490 // These cluster size probabilities were taken from preliminary
491 // results from the BI RPC Upgrade work in 2025 at BB5.
492 // They could be updated if new results for BI RPCs become available.
493 static constexpr std::array<double, 4> ClusterSizeProbabilitiesBI{0.642, 0.316,
494 0.032, 0.010};
495 // Compile-time calculation of the cumulative array
496 // Used empty capture list [] since variables are static constexpr
497 static constexpr std::array<double, 4> cumulativeBI = []() {
498 std::array<double, 4> acumulative{};
499 acumulative[0] = ClusterSizeProbabilitiesBI[0];
500 for (size_t i = 1; i < ClusterSizeProbabilitiesBI.size(); ++i) {
501 acumulative[i] = acumulative[i - 1] + ClusterSizeProbabilitiesBI[i];
502 }
503 return acumulative;
504 }();
505
506 std::array<double, 4> theCumulative{};
507 if (isBIRPC) {
508 theCumulative=cumulativeBI;
509 } else {
510 theCumulative=cumulative;
511 }
512
513 float rndmCS = CLHEP::RandFlat::shoot(rndmEngine, 1.);
514
515 unsigned ClusterSize{1};
516 while (ClusterSize < theCumulative.size() &&
517 rndmCS > theCumulative[ClusterSize-1])
518 ++ClusterSize;
519
520 if (ClusterSize > theCumulative.size())
521 ClusterSize = theCumulative.size();
522 return ClusterSize;
523}
524
525
526} // namespace MuonR4
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_MSG_INFO(x,...)
ATLAS-specific HepMC functions.
std::string show_to_string(Identifier id, const IdContext *context=0, char sep='.') const
or provide the printout in string form
const T * back() const
Access the last element in the collection as an rvalue.
const T * at(size_type n) const
Access an element, as an rvalue.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
This is a "hash" representation of an Identifier.
Identifier identify() const
Definition MuonDigit.h:30
double distanceToEdge(const IdentifierHash &measHash, const Amg::Vector3D &posInStripPlane, const EdgeSide side) const
Returns the disance to the readout.
IdentifierHash layerHash(const Identifier &measId) const override final
The layer hash removes the bits from the IdentifierHash corresponding to the measurement's channel nu...
const StripLayerPtr & sensorLayout(const IdentifierHash &measHash) const
Access to the StripLayer associated to a given measurement Hash.
unsigned nGasGaps() const
Returns the number of gasgaps described by this ReadOutElement (usally 2 or 3).
int firstStripNumber() const
Returns the number of the first strip.
bool insideTrapezoid(const Amg::Vector2D &extPos) const
Checks whether an external point is inside the trapezoidal area.
virtual int stripNumber(const Amg::Vector2D &pos) const
Calculates the number of the strip whose center is closest to the given point.
virtual int numStrips() const
Number of strips on the panel.
size_type module_hash_max() const
the maximum hash value
xAOD::MuonSimHit * addSDO(const TimedHit &hit, xAOD::MuonSimHitContainer *sdoContainer) const
Adds the timed simHit to the output SDO container.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
std::vector< TimedHitPtr< xAOD::MuonSimHit > > TimedHits
CLHEP::HepRandomEngine * getRandomEngine(const EventContext &ctx) const
static bool passDeadTime(const Identifier &channelId, const double hitTime, const double deadTimeWindow, DeadTimeMap &deadTimeMap)
Returns whether the new digit is within the dead time window.
TimedHitPtr< xAOD::MuonSimHit > TimedHit
DigitColl * fetchCollection(const Identifier &hitId, OutDigitCache_t< DigitColl > &digitCache) const
Helper function that provides fetches the proper DigitCollection from the DigitCache for a given hit ...
const MuonGMR4::MuonDetectorManager * m_detMgr
StatusCode writeDigitContainer(const EventContext &ctx, const SG::WriteHandleKey< DigitCont > &key, OutDigitCache_t< DigitColl > &&digitCache, unsigned int hashMax) const
Helper function to move the collected digits into the final DigitContainer.
static double hitTime(const TimedHit &hit)
Returns the global time of the hit which is the sum of eventTime & individual hit time.
std::unordered_map< Identifier, double > DeadTimeMap
StatusCode initialize() override final
Gaudi::Property< double > m_stripTimeResolution
Definition RpcDigiTool.h:74
double getTOT(const double aCharge) const
Returns Time Over Threshold (ns) for a signal on a strip.
bool digitizeHit(const TimedHit &simHit, const bool measuresPhi, const Muon::DigitEffiData *effiMap, RpcDigitCollection &outContainer, CLHEP::HepRandomEngine *rndEngine, DeadTimeMap &deadTimes) const
Digitize the sim hit as Rpc strip 1D hit.
Gaudi::Property< bool > m_digitizeMuonOnly
Definition RpcDigiTool.h:81
Gaudi::Property< double > m_deadTime
Definition RpcDigiTool.h:78
SG::ReadCondHandleKey< Muon::DigitEffiData > m_effiDataKey
Definition RpcDigiTool.h:62
StatusCode digitize(const EventContext &ctx, const TimedHits &hitsToDigit, xAOD::MuonSimHitContainer *sdoContainer) const override final
Digitize the time ordered hits and write them to the digit format specific for the detector technolog...
std::vector< double > divideChargeOnStrips(double totalCharge, int n_strips, CLHEP::HepRandomEngine *rndmEngine) const
Returns a vector with chages (fC) divided on strips.
SG::WriteHandleKey< RpcDigitContainer > m_writeKey
Definition RpcDigiTool.h:59
int determineClusterSize(const Identifier &id, CLHEP::HepRandomEngine *rndmEngine, bool isBIRPC) const
Returns cluster strip molteplicity.
StatusCode finalize() override final
Gaudi::Property< double > m_propagationVelocity
Definition RpcDigiTool.h:70
OutDigitCache_t< RpcDigitCollection > DigiCache
Definition RpcDigiTool.h:58
double calculateChargeOnStrip(const TimedHit &simHit, CLHEP::HepRandomEngine *rndmEngine, const double gasGapSize) const
Returns the charge (fC) after the amplification in gas.
double getTOA(const double aDistance) const
Returns Time Of Arrival (ns) for a signal on a strip.
bool digitizeHitBI(const TimedHit &simHit, const Muon::DigitEffiData *effiMap, RpcDigitCollection &outContainer, CLHEP::HepRandomEngine *rndEngine, DeadTimeMap &deadTimes) const
Digitize the sim hit as Rpc strip 2D hit.
double getEfficiency(const Identifier &channelId, bool isInnerQ1=false) const
Returns the signal generation efficiency of the sTgc channel.
Identifier channelID(int stationName, int stationEta, int stationPhi, int doubletR, int doubletZ, int doubletPhi, int gasGap, int measuresPhi, int strip) const
int gasGap(const Identifier &id) const override
get the hashes
int channel(const Identifier &id) const override
int doubletPhi(const Identifier &id) const
bool measuresPhi(const Identifier &id) const override
int doubletZ(const Identifier &id) const
bool next()
Loads the hits from the next chamber.
void setIdentifier(const Identifier &id)
Sets the global ATLAS identifier.
Identifier identify() const
Returns the global ATLAS identifier of the SimHit.
float energyDeposit() const
Returns the energy deposited by the traversing particle inside the gas volume.
ConstVectorMap< 3 > localPosition() const
Returns the local postion of the traversing particle.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
bool isMuon(const T &p)
GeoModel::TransientConstSharedPtr< StripLayer > StripLayerPtr
Definition StripLayer.h:100
This header ties the generic definitions in this package.
SG::Decorator< T, ALLOC > Decorator
Helper class to provide type-safe access to aux data, specialized for JaggedVecElt.
Definition AuxElement.h:576
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
MuonSimHitContainer_v1 MuonSimHitContainer
Define the version of the pixel cluster container.
MuonSimHit_v1 MuonSimHit
Defined the version of the MuonSimHit.
Definition MuonSimHit.h:12