68 Amg::Vector3D locHitDir = xAOD::toEigen(hit->localDirection());
69 Amg::Vector3D locHitPos = xAOD::toEigen(hit->localPosition());
73 <<
" mclink " << hit->genParticleLink() <<
" PDG ID " << hit->pdgId() );
75 const double scale = Amg::intersect<3>(locHitPos, locHitDir, Amg::Vector3D::UnitZ(), 0.).value_or(0);
89 const Identifier wireLayId = idHelper.channelID(hitId,
90 idHelper.multilayer(hitId),
91 idHelper.gasGap(hitId),
92 ReadoutChannelType::Wire,
97 if(!wireDesign.insideTrapezoid(hitOnWire2D)) {
100 std::pair<int, int> wireGrpWireNum = wireDesign.
wireNumber(hitOnWire2D);
102 wireNumber = wireDesign.numPitchesToGroup(wireGrpWireNum.first) + wireGrpWireNum.second;
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)) {
115 Ionization ionization =
pointClosestApproach(wireDesign, wireNumber, locHitPos, locHitDir, hit->stepLength());
116 double distToWire = ionization.distance;
117 if(distToWire > 0.) {
122 if (ionization.posOnSegment.x() < ionization.posOnWire.x()) {
adjacent = -1;}
126 double distToWireAdj = ionizationAdj.distance;
127 if ((distToWireAdj > 0.) && (distToWireAdj < distToWire)) {
128 distToWire = distToWireAdj;
130 ionization = std::move(ionizationAdj);
133 ATH_MSG_DEBUG(
"Failed to get the distance between the wire number = " << wireNumber
135 <<
". Number of wires = " << numWires
141 hitOnWireSurf = ionization.posOnWire;
143 <<
" posOnTrack: " <<
Amg::toString(ionization.posOnSegment, 3)
147 <<
" EDep: " << hit->energyDeposit() <<
" EKin: " << hit->kineticEnergy()
148 <<
" pdgId: " << hit->pdgId()
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()
167 if (distToWire > wirePitch) {
173 const double par_kappa = gamParam.kParameter;
174 const double par_theta = gamParam.thetaParameter;
177 double gamma_mpv = (par_kappa - 1) * par_theta;
179 if (gamma_mpv < 0.) {gamma_mpv = 0.;}
180 const double t0_par = most_prob_time - gamma_mpv;
187 double digitTime = t0_par + CLHEP::RandGamma::shoot(condContainers.rndEngine, par_kappa, 1/par_theta);
194 constexpr
int shoot_limit = 4;
195 int shoot_counter = 0;
196 while (digitTime < 0.) {
197 if (shoot_counter > shoot_limit) {
201 digitTime = t0_par + CLHEP::RandGamma::shoot(condContainers.rndEngine, par_kappa, 1/par_theta);
206 <<
", time = " << digitTime
207 <<
", k parameter = " << par_kappa
208 <<
", theta parameter = " << par_theta
209 <<
", most probable time = " << most_prob_time);
212 if (condContainers.efficiencies) {
213 const double efficiency = condContainers.efficiencies->getEfficiency(wireLayId);
215 if (CLHEP::RandFlat::shoot(condContainers.rndEngine,0.0,1.0) >
efficiency)
return {};
220 double sDigitTimeWire = digitTime;
221 double sDigitTimePad = sDigitTimeWire;
222 double sDigitTimeStrip = sDigitTimeWire;
231 int channelType = ReadoutChannelType::Strip;
232 const Identifier stripLayId = idHelper.channelID(wireLayId, idHelper.multilayer(wireLayId),
233 idHelper.gasGap(wireLayId), channelType, 1,
isValid);
248 int stripNumber = stripDesign.stripNumber(hitOnStripSurf);
249 if( stripNumber < 0){
251 const double newPosX = (hitOnStripSurf.x() > 0.0)? hitOnStripSurf.x() - tolerance_length
252 : hitOnStripSurf.x() + tolerance_length;
254 stripNumber = stripDesign.stripNumber(newPos);
256 if (stripNumber < 0) {
258 ATH_MSG_WARNING(
"Position on strip surface = (" << hitOnStripSurf.x() <<
", " << hitOnStripSurf.y() <<
")");
263 const Identifier stripHitId = idHelper.channelID(stripLayId, idHelper.multilayer(stripLayId),
264 idHelper.gasGap(stripLayId), channelType, stripNumber,
isValid);
265 if(!
isValid && stripNumber != -1) {
270 const int numStrips = stripDesign.numStrips();
271 const double stripHalfPitch = 0.5 * stripDesign.stripPitch();
292 const double total_charge =
gain*ionized_charge;
295 const double tan_theta = locHitDir.perp()/locHitDir.z();
299 const double cluster_posX = hitOnStripSurf.x();
300 double peak_position = CLHEP::RandGaussZiggurat::shoot(condContainers.rndEngine, cluster_posX,
m_StripResolution*angle_dependency);
304 const double norm = 0.5 * total_charge;
307 constexpr
double tolerance_charge = 0.0005;
309 constexpr
unsigned int max_neighbor = 10;
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);
321 const Identifier currentStripId = idHelper.channelID(stripLayId, idHelper.multilayer(stripLayId), idHelper.gasGap(stripLayId),
322 channelType, currentStrip,
isValid);
331 double x_relative = currentStripPos.x() - peak_position;
335 if (
charge < tolerance_charge) {
336 ATH_MSG_VERBOSE(
"Breaking the upper half strip loop stripCharge: " <<
charge <<
" < " << tolerance_charge);
341 double strip_time = sDigitTimeStrip;
346 int indexFromMiddleStrip = iStrip;
347 if ((iStrip > 0) && ((x_relative + (0.75 - iStrip * 2) * stripHalfPitch) < 0))
348 indexFromMiddleStrip = iStrip - 1;
356 <<
", time = " << strip_time <<
", time offset = " << strip_time-sDigitTimeStrip
357 <<
", neighbor index = " << iStrip
358 <<
", strip position = "<<
Amg::toString(currentStripPos, 2));
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 ");
371 const Identifier currentStripId = idHelper.channelID(stripLayId, idHelper.multilayer(stripLayId), idHelper.gasGap(stripLayId),
372 channelType, currentStrip,
isValid);
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);
388 double strip_time = sDigitTimeStrip;
391 int indexFromMiddleStrip = ((x_relative + (iStrip * 2 - 0.75) * stripHalfPitch) > 0)? iStrip - 1 : iStrip;
398 <<
", time = " << strip_time <<
", time offset = " << strip_time-sDigitTimeStrip
399 <<
", neighbor index = " << iStrip
400 <<
", strip position = " <<
Amg::toString(currentStripPos, 2));
414 channelType = ReadoutChannelType::Pad;
416 Identifier padLayId = idHelper.channelID(wireLayId, idHelper.multilayer(wireLayId),
417 idHelper.gasGap(wireLayId), channelType, 1);
424 const Amg::Vector2D hitOnPadSurf = hitOnWireSurf.block<2,1>(0,0);
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){
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;
440 padEtaPhi = padDesign.channelNumber(newPosition);
441 padEta = padEtaPhi.first;
442 padPhi = padEtaPhi.second;
444 if( padEta < 1 || padPhi < 1){
446 ATH_MSG_WARNING(
"Position on pad surface = (" << hitOnPadSurf.x() <<
", " << hitOnPadSurf.y() <<
")");
451 const Identifier padHitId = idHelper.padID(padLayId, idHelper.multilayer(padLayId),
452 idHelper.gasGap(padLayId), channelType, padEta, padPhi,
isValid);
463 double halfPadHeight = 0.5 * readoutElement->
padHeight(padHitId);
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();
472 double halfPadWidth = 0.5 * padBottomBase + 0.25 * (1 +
diff.y()/halfPadHeight) * (padTopBase - padBottomBase);
479 double deltaX = halfPadWidth - std::abs(
diff.x());
480 double deltaY = halfPadHeight - std::abs(
diff.y());
491 unsigned int newPhi =
diff.x() > 0 ? padEtaPhi.second-1 : padEtaPhi.second+1;
492 unsigned int newEta =
diff.y() > 0 ? padEtaPhi.first+1 : padEtaPhi.first-1;
493 bool validEta = newEta > 0 && newEta < readoutElement->
numPadEta(padHitId) + 1;
494 bool validPhi = newPhi > 0 && newPhi < readoutElement->
numPadPhi(padHitId) + 1;
496 if (isNeighX && isNeighY && validEta && validPhi){
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);
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){
518 const Identifier neigh_ID = idHelper.padID(padHitId, idHelper.multilayer(padHitId), idHelper.gasGap(padHitId),
519 channelType, padEta, newPhi,
isValid);
524 addDigit(digits, padHitId, bctag, sDigitTimePad, (1.-xQfraction)*0.5*total_charge);
525 addDigit(digits, neigh_ID, bctag, sDigitTimePad, xQfraction*0.5*total_charge);
527 else if (isNeighY && validEta){
530 const Identifier neigh_ID = idHelper.padID(padHitId, idHelper.multilayer(padHitId), idHelper.gasGap(padHitId),
531 channelType, newEta, padPhi,
isValid);
536 addDigit(digits, padHitId, bctag, sDigitTimePad, (1.-yQfraction)*0.5*total_charge);
537 addDigit(digits, neigh_ID, bctag, sDigitTimePad, yQfraction*0.5*total_charge);
543 addDigit(digits, padHitId, bctag, sDigitTimePad, 0.5*total_charge);
547 else if(padEta != 0 || padPhi != 0) {
564 channelType = ReadoutChannelType::Wire;
568 insideBounds = wireDesign.insideTrapezoid(hitOnWireSurf.block<2,1>(0,0));
572 int wiregroupNumber = (wireDesign.wireNumber(hitOnWireSurf.block<2,1>(0,0))).
first;
573 if( wiregroupNumber < 1){
575 const double newPosX = (hitOnWireSurf.x() > 0.0)? hitOnWireSurf.x() - tolerance_length
576 : hitOnWireSurf.x() + tolerance_length;
578 wiregroupNumber = (wireDesign.wireNumber(newPos)).
first;
580 if (wiregroupNumber < 1) {
582 ATH_MSG_WARNING(
"Position on wire surface = (" << hitOnWireSurf.x() <<
", " << hitOnWireSurf.y() <<
")");
589 const Identifier wireGroupHitId = idHelper.channelID(wireLayId, idHelper.multilayer(wireLayId), idHelper.gasGap(wireLayId),
590 channelType, wiregroupNumber,
isValid);
593 int numWireGroups = readoutElement->
numChannels(wireLayId);
594 if(wiregroupNumber >=1 && wiregroupNumber <= numWireGroups) {
595 addDigit(digits, wireGroupHitId, bctag, sDigitTimeWire, total_charge);
598 else if (wiregroupNumber != -1){