53 {
54
56 if (energyDeposit == 0.) return {};
57
58
59 const MuonGMR4::MuonDetectorManager* detMgr = condContainers.detMgr;
60
61
62 const Identifier hitId = hit->identify();
63 ATH_MSG_DEBUG(
"Retrieving detector element for: "<<
m_idHelperSvc->toStringDetEl(hitId) <<
" energyDeposit "<< energyDeposit );
64 const MuonGMR4::sTgcReadoutElement* readoutElement = detMgr->getsTgcReadoutElement(hitId);
65
66
67
68 Amg::Vector3D locHitDir = xAOD::toEigen(hit->localDirection());
69 Amg::Vector3D locHitPos = xAOD::toEigen(hit->localPosition());
73 << " mclink " << hit->genParticleLink() << " PDG ID " << hit->pdgId() );
78
79
80
81
82
83
84
85
86
87
89 const Identifier wireLayId = idHelper.
channelID(hitId,
92 ReadoutChannelType::Wire,
93 1);
94
95 const MuonGMR4::WireGroupDesign& wireDesign{readoutElement->
wireDesign(wireLayId)};
98 return {};
99 }
100 std::pair<int, int> wireGrpWireNum = wireDesign.
wireNumber(hitOnWire2D);
101 int wireNumber = -1;
102 wireNumber = wireDesign.
numPitchesToGroup(wireGrpWireNum.first) + wireGrpWireNum.second;
103
104
105 const int numWires = wireDesign.
nAllWires();
106 if((wireNumber < 1) || (wireNumber > numWires)) {
107 wireGrpWireNum = wireDesign.
wireNumber(locHitPos.block<2,1>(0,0));
108 wireNumber = wireDesign.
numPitchesToGroup(wireGrpWireNum.first) + wireGrpWireNum.second;
109 if((wireNumber < 1) || (wireNumber > numWires)) {
111 return {};
112 }
113 }
114
116 double distToWire = ionization.distance;
117 if(distToWire > 0.) {
118
119
120
122 if (ionization.posOnSegment.x() < ionization.posOnWire.x()) {
adjacent = -1;}
123
125
126 double distToWireAdj = ionizationAdj.distance;
127 if ((distToWireAdj > 0.) && (distToWireAdj < distToWire)) {
128 distToWire = distToWireAdj;
130 ionization = std::move(ionizationAdj);
131 }
132 } else {
133 ATH_MSG_DEBUG(
"Failed to get the distance between the wire number = " << wireNumber
135 << ". Number of wires = " << numWires
137 return {};
138 }
139
140
141 hitOnWireSurf = ionization.posOnWire;
143 <<
" posOnTrack: " <<
Amg::toString(ionization.posOnSegment, 3)
147 << " EDep: " << hit->energyDeposit() << " EKin: " << hit->kineticEnergy()
148 << " pdgId: " << hit->pdgId()
150
151
152
153
154
155
156 const double wirePitch = wireDesign.
stripPitch();
157 if ((distToWire > 0.) && (std::abs(hit->pdgId()) == 13) && (distToWire > (0.5 * wirePitch))) {
158 ATH_MSG_DEBUG(
"Distance to the nearest wire (" << distToWire <<
") is greater than expected.");
161 << " EDeposited: " << hit->energyDeposit()
162 << " EKinetic: " << hit->kineticEnergy()
163 << " pdgID: " << hit->pdgId()
165 }
166
167 if (distToWire > wirePitch) {
168 return {};
169 }
170
171
173 const double par_kappa = gamParam.kParameter;
174 const double par_theta = gamParam.thetaParameter;
176
177 double gamma_mpv = (par_kappa - 1) * par_theta;
178
179 if (gamma_mpv < 0.) {gamma_mpv = 0.;}
180 const double t0_par = most_prob_time - gamma_mpv;
181
182
183
184
185
186
187 double digitTime = t0_par + CLHEP::RandGamma::shoot(condContainers.rndEngine, par_kappa, 1/par_theta);
188
189
190
191
192
193
194 constexpr int shoot_limit = 4;
195 int shoot_counter = 0;
196 while (digitTime < 0.) {
197 if (shoot_counter > shoot_limit) {
198 digitTime = 0.;
199 break;
200 }
201 digitTime = t0_par + CLHEP::RandGamma::shoot(condContainers.rndEngine, par_kappa, 1/par_theta);
202 ++shoot_counter;
203 }
204
206 << ", time = " << digitTime
207 << ", k parameter = " << par_kappa
208 << ", theta parameter = " << par_theta
209 << ", most probable time = " << most_prob_time);
210
212 if (condContainers.efficiencies) {
213 const double efficiency = condContainers.efficiencies->getEfficiency(wireLayId);
214
215 if (CLHEP::RandFlat::shoot(condContainers.rndEngine,0.0,1.0) >
efficiency)
return {};
216 }
217
219
220 double sDigitTimeWire = digitTime;
221 double sDigitTimePad = sDigitTimeWire;
222 double sDigitTimeStrip = sDigitTimeWire;
223
225
226
227
228
231 int channelType = ReadoutChannelType::Strip;
232 const Identifier stripLayId = idHelper.
channelID(wireLayId, idHelper.
multilayer(wireLayId),
234
235 const MuonGMR4::StripDesign& stripDesign{readoutElement->
stripDesign(stripLayId)};
236
238
240 if(!insideBounds) {
242 return {};
243 }
244
245
246
247 constexpr double tolerance_length = 0.01*Gaudi::Units::mm;
248 int stripNumber = stripDesign.
stripNumber(hitOnStripSurf);
249 if( stripNumber < 0){
250
251 const double newPosX = (hitOnStripSurf.x() > 0.0)? hitOnStripSurf.x() - tolerance_length
252 : hitOnStripSurf.x() + tolerance_length;
255
256 if (stripNumber < 0) {
258 ATH_MSG_WARNING(
"Position on strip surface = (" << hitOnStripSurf.x() <<
", " << hitOnStripSurf.y() <<
")");
259 return {};
260 }
261 }
263 const Identifier stripHitId = idHelper.
channelID(stripLayId, idHelper.
multilayer(stripLayId),
264 idHelper.
gasGap(stripLayId), channelType, stripNumber,
isValid);
265 if(!
isValid && stripNumber != -1) {
267 return {};
268 }
269
270 const int numStrips = stripDesign.
numStrips();
271 const double stripHalfPitch = 0.5 * stripDesign.
stripPitch();
272
273
274
275
276
277
278
279 const double ionized_charge = (5.65E-6)*energyDeposit/CLHEP::keV;
280
281
282
283
284
285
286
287
288
290
291
292 const double total_charge =
gain*ionized_charge;
293
294
295 const double tan_theta = locHitDir.perp()/locHitDir.z();
296
298
299 const double cluster_posX = hitOnStripSurf.x();
300 double peak_position = CLHEP::RandGaussZiggurat::shoot(condContainers.rndEngine, cluster_posX,
m_StripResolution*angle_dependency);
301
302
303
304 const double norm = 0.5 * total_charge;
305
306
307 constexpr double tolerance_charge = 0.0005;
308
309 constexpr unsigned int max_neighbor = 10;
310
311
312 for (unsigned int iStrip = 0; iStrip <= max_neighbor; ++iStrip) {
313 int currentStrip = stripNumber + iStrip;
314 if (currentStrip > numStrips) {
315 ATH_MSG_VERBOSE(
"Breaking the upper half strip loop stripNumber: " << currentStrip <<
" > " << numStrips);
316 break;
317 }
318
319
321 const Identifier currentStripId = idHelper.
channelID(stripLayId, idHelper.
multilayer(stripLayId), idHelper.
gasGap(stripLayId),
322 channelType, currentStrip,
isValid);
325 if (currentStripPos == Amg::Vector2D::Zero()) {
327 }
328
329
330
331 double x_relative = currentStripPos.x() - peak_position;
332
334
335 if (
charge < tolerance_charge) {
336 ATH_MSG_VERBOSE(
"Breaking the upper half strip loop stripCharge: " <<
charge <<
" < " << tolerance_charge);
337 break;
338 }
339
340
341 double strip_time = sDigitTimeStrip;
342
343
345
346 int indexFromMiddleStrip = iStrip;
347 if ((iStrip > 0) && ((x_relative + (0.75 - iStrip * 2) * stripHalfPitch) < 0))
348 indexFromMiddleStrip = iStrip - 1;
349
351 }
352
354
356 << ", time = " << strip_time << ", time offset = " << strip_time-sDigitTimeStrip
357 << ", neighbor index = " << iStrip
358 <<
", strip position = "<<
Amg::toString(currentStripPos, 2));
359 }
360 }
361
362
363 for (unsigned int iStrip = 1; iStrip <= max_neighbor; ++iStrip) {
364 int currentStrip = stripNumber - iStrip;
365 if (currentStrip < 1) {
366 ATH_MSG_VERBOSE(
"Breaking the lower half strip loop stripNumber: " << currentStrip <<
" < 1 ");
367 break;
368 }
369
371 const Identifier currentStripId = idHelper.
channelID(stripLayId, idHelper.
multilayer(stripLayId), idHelper.
gasGap(stripLayId),
372 channelType, currentStrip,
isValid);
375 if (currentStripPos == Amg::Vector2D::Zero()) {
377 }
378
379
380 double x_relative = currentStripPos.x() - peak_position;
382 if (
charge < tolerance_charge) {
383 ATH_MSG_VERBOSE(
"Breaking the lower half strip loop stripCharge: " <<
charge <<
" < " << tolerance_charge);
384 break;
385 }
386
387
388 double strip_time = sDigitTimeStrip;
389
391 int indexFromMiddleStrip = ((x_relative + (iStrip * 2 - 0.75) * stripHalfPitch) > 0)? iStrip - 1 : iStrip;
393 }
394
396
398 << ", time = " << strip_time << ", time offset = " << strip_time-sDigitTimeStrip
399 << ", neighbor index = " << iStrip
400 <<
", strip position = " <<
Amg::toString(currentStripPos, 2));
401 }
402 }
403
404
407 return digits;
408 }
409
410
411
412
414 channelType = ReadoutChannelType::Pad;
415
417 idHelper.
gasGap(wireLayId), channelType, 1);
418
419 const MuonGMR4::PadDesign& padDesign{readoutElement->
padDesign(padLayId)};
420
421
422
423
424 const Amg::Vector2D hitOnPadSurf = hitOnWireSurf.block<2,1>(0,0);
425
426
428
429 if(insideBounds) {
430 std::pair<uint, uint> padEtaPhi = padDesign.
channelNumber(hitOnPadSurf);
431 unsigned int padEta = padEtaPhi.first;
432 unsigned int padPhi = padEtaPhi.second;
433 if( padEta < 1 || padPhi < 1){
434
435 const double newPosX = (hitOnPadSurf.x()>0.0)? hitOnPadSurf.x() - tolerance_length
436 : hitOnPadSurf.x() + tolerance_length;
437 const double newPosY = (hitOnPadSurf.y()>0.0)? hitOnPadSurf.y() - tolerance_length
438 : hitOnPadSurf.y() + tolerance_length;
441 padEta = padEtaPhi.first;
442 padPhi = padEtaPhi.second;
443
444 if( padEta < 1 || padPhi < 1){
446 ATH_MSG_WARNING(
"Position on pad surface = (" << hitOnPadSurf.x() <<
", " << hitOnPadSurf.y() <<
")");
447 return digits;
448 }
449 }
451 const Identifier padHitId = idHelper.
padID(padLayId, idHelper.
multilayer(padLayId),
452 idHelper.
gasGap(padLayId), channelType, padEta, padPhi,
isValid);
454
456 if (padPos == Amg::Vector2D::Zero()) {
458 return digits;
459 }
460
461
463 double halfPadHeight = 0.5 * readoutElement->
padHeight(padHitId);
464
465 std::array<Amg::Vector2D, 4> padHitCorners = padDesign.
padCorners(padEtaPhi);
466 double padBottomBase = (padHitCorners[0] - padHitCorners[1]).
norm();
467 double padTopBase = (padHitCorners[2] - padHitCorners[3]).
norm();
468
469
470
471
472 double halfPadWidth = 0.5 * padBottomBase + 0.25 * (1 +
diff.y()/halfPadHeight) * (padTopBase - padBottomBase);
473
474
475
476
477
478
479 double deltaX = halfPadWidth - std::abs(
diff.x());
480 double deltaY = halfPadHeight - std::abs(
diff.y());
483
484
485 if (deltaX < 0.)
deltaX = 0.1;
486 if (deltaY < 0.)
deltaY = 0.1;
487
489
490
491 unsigned int newPhi = padEtaPhi.second - Acts::copySign(1,
diff.x());
492 unsigned int newEta = padEtaPhi.first + Acts::copySign(1,
diff.y());
493 bool validEta = newEta > 0 && newEta < readoutElement->
numPadEta(padHitId) + 1;
494 bool validPhi = newPhi > 0 && newPhi < readoutElement->
numPadPhi(padHitId) + 1;
495
496 if (isNeighX && isNeighY && validEta && validPhi){
497
499 const Identifier neigh_ID_X = idHelper.
padID(padHitId, idHelper.
multilayer(padHitId), idHelper.
gasGap(padHitId),
500 channelType, padEta, newPhi,
isValid);
502 const Identifier neigh_ID_Y = idHelper.
padID(padHitId, idHelper.
multilayer(padHitId), idHelper.
gasGap(padHitId),
503 channelType, newEta, padPhi,
isValid);
505 const Identifier neigh_ID_XY = idHelper.
padID(padHitId, idHelper.
multilayer(padHitId), idHelper.
gasGap(padHitId),
506 channelType, newEta, newPhi,
isValid);
509
510
511 addDigit(digits, neigh_ID_X, bctag, sDigitTimePad, xQfraction*(1.-yQfraction)*0.5*total_charge);
512 addDigit(digits, neigh_ID_Y, bctag, sDigitTimePad, yQfraction*(1.-xQfraction)*0.5*total_charge);
513 addDigit(digits, neigh_ID_XY, bctag, sDigitTimePad, xQfraction*yQfraction*0.5*total_charge);
514 addDigit(digits, padHitId, bctag, sDigitTimePad, (1.-xQfraction-yQfraction+xQfraction*yQfraction)*0.5*total_charge);
515 } else if (isNeighX && validPhi){
516
518 const Identifier neigh_ID = idHelper.
padID(padHitId, idHelper.
multilayer(padHitId), idHelper.
gasGap(padHitId),
519 channelType, padEta, newPhi,
isValid);
520
521
522
524 addDigit(digits, padHitId, bctag, sDigitTimePad, (1.-xQfraction)*0.5*total_charge);
525 addDigit(digits, neigh_ID, bctag, sDigitTimePad, xQfraction*0.5*total_charge);
526 }
527 else if (isNeighY && validEta){
528
530 const Identifier neigh_ID = idHelper.
padID(padHitId, idHelper.
multilayer(padHitId), idHelper.
gasGap(padHitId),
531 channelType, newEta, padPhi,
isValid);
532
533
534
536 addDigit(digits, padHitId, bctag, sDigitTimePad, (1.-yQfraction)*0.5*total_charge);
537 addDigit(digits, neigh_ID, bctag, sDigitTimePad, yQfraction*0.5*total_charge);
538 }
539
540 }
541 else{
542
543 addDigit(digits, padHitId, bctag, sDigitTimePad, 0.5*total_charge);
544 }
545
546 }
547 else if(padEta != 0 || padPhi != 0) {
549 }
550 }
551 else {
553 }
554
557 return digits;
558 }
559
560
561
562
564 channelType = ReadoutChannelType::Wire;
565
566
567
568 insideBounds = wireDesign.
insideTrapezoid(hitOnWireSurf.block<2,1>(0,0));
569
570 if(insideBounds) {
571
572 int wiregroupNumber = (wireDesign.
wireNumber(hitOnWireSurf.block<2,1>(0,0))).first;
573 if( wiregroupNumber < 1){
574
575 const double newPosX = (hitOnWireSurf.x() > 0.0)? hitOnWireSurf.x() - tolerance_length
576 : hitOnWireSurf.x() + tolerance_length;
578 wiregroupNumber = (wireDesign.
wireNumber(newPos)).first;
579
580 if (wiregroupNumber < 1) {
582 ATH_MSG_WARNING(
"Position on wire surface = (" << hitOnWireSurf.x() <<
", " << hitOnWireSurf.y() <<
")");
583 return digits;
584 }
585 }
586
587
589 const Identifier wireGroupHitId = idHelper.
channelID(wireLayId, idHelper.
multilayer(wireLayId), idHelper.
gasGap(wireLayId),
590 channelType, wiregroupNumber,
isValid);
591
593 int numWireGroups = readoutElement->
numChannels(wireLayId);
594 if(wiregroupNumber >=1 && wiregroupNumber <= numWireGroups) {
595 addDigit(digits, wireGroupHitId, bctag, sDigitTimeWire, total_charge);
596 }
597 }
598 else if (wiregroupNumber != -1){
600 }
601 }
602 else {
604 }
605
606
607 return digits;
608}
std::pair< int, int > channelNumber(const Amg::Vector2D &hitPos) const
Function to retrieve the pad eta and phi given a local position coordinate.
double stripPitch() const
Distance between two adjacent strips.
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.
unsigned int numPitchesToGroup(unsigned int groupNum) const
Returns the number of wire pitches to reach the given group.
std::pair< int, int > wireNumber(const Amg::Vector2D &extPos) const
Returns a pair where the first component indicate the wire group number and the second one returns th...
unsigned int nAllWires() const
Returns the number of all wires.
Amg::Vector2D localChannelPosition(const Identifier &measId) const
Returns the local pad/strip/wireGroup position.
const WireGroupDesign & wireDesign(const Identifier &measId) const
Retrieves the readoutElement Layer given the Identifier/Hash.
const PadDesign & padDesign(const Identifier &measId) const
Retrieves the readoutElement Layer given the Identifier/Hash.
const StripDesign & stripDesign(const Identifier &measId) const
Retrieves the readoutElement Layer given the Identifier/Hash.
unsigned int numPadPhi(const Identifier &measId) const
Returns the number of pads in the Phi direction in the given gasGap layer.
unsigned int numPadEta(const Identifier &measId) const
Returns the number of pads in the eta direction in the given layer.
double padHeight(const Identifier &measId) const
Returns the height of all the pads that are not adjacent to the bottom edge of the trapezoid active a...
unsigned int numChannels(const Identifier &measId) const
Returns the number of strips / wires / pads in a given gasGap.
double chargeIntegral(double N, double M) const
std::optional< double > intersect(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
Calculates the point B' along the line B that's closest to a second line A.
Amg::Transform3D getRotateZ3D(double angle)
get a rotation transformation around Z-axis