Loading [MathJax]/extensions/tex2jax.js
ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
sTgcDigitMaker.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 
13 #include "TrkSurfaces/Surface.h"
14 #include "GaudiKernel/MsgStream.h"
16 #include "CLHEP/Units/SystemOfUnits.h"
17 #include "CLHEP/Random/RandomEngine.h"
18 #include "CLHEP/Random/RandFlat.h"
19 #include "CLHEP/Random/RandGaussZiggurat.h"
20 #include "CLHEP/Random/RandGamma.h"
21 #include "CLHEP/Vector/ThreeVector.h"
23 
24 #include "TF1.h"
25 #include <cmath>
26 #include <iostream>
27 #include <fstream>
28 
29 //---------------------------------------------------
30 // Constructor and Destructor
31 //---------------------------------------------------
32 
33 //----- Constructor
35  const int channelTypes,
36  double meanGasGain,
37  bool doPadChargeSharing,
38  double stripChargeScale,
39  bool applyAsBuiltBLines)
40  : AthMessaging ("sTgcDigitMaker"),
41  m_idHelperSvc{idHelperSvc},
42  m_channelTypes{channelTypes},
43  m_meanGasGain{meanGasGain},
44  m_doPadSharing{doPadChargeSharing},
45  m_stripChargeScale{stripChargeScale},
46  m_applyAsBuiltBLines(applyAsBuiltBLines) {}
47 //----- Destructor
49 //------------------------------------------------------
50 // Initialize
51 //------------------------------------------------------
53 
54  // Read share/sTGC_Digitization_timeArrivale.dat, containing the digit time of arrival
56 
57  // Read share/sTGC_Digitization_timeOffsetStrip.dat if the the strip time correction is enable
58  if (m_doTimeOffsetStrip) {
60  }
61  // check the digitization channel type
62  if(m_channelTypes!=1 && m_channelTypes!=2 && m_channelTypes!=3) {
63  ATH_MSG_ERROR("Invalid ChannelTypes : " << m_channelTypes << " (valid values are : 1 --> strips ; 2 --> strips / wires ; 3 --> strips / wires / pads)");
64  return StatusCode::FAILURE;
65  }
66  return StatusCode::SUCCESS;
67 }
68 
69 //---------------------------------------------------
70 // Execute Digitization
71 //---------------------------------------------------
73  const sTGCSimHit& hit) const {
74  // SimHits without energy loss are not recorded.
75  double energyDeposit = hit.depositEnergy(); // Energy deposit in MeV
76  if(energyDeposit==0.) return {};
77 
79  const sTgcIdHelper& idHelper{m_idHelperSvc->stgcIdHelper()};
80  sTgcSimIdToOfflineId simToOffline{&idHelper};
81  const Identifier offlineId = simToOffline.convert(hit.sTGCId());
82  const Identifier layid = idHelper.channelID(offlineId,
83  idHelper.multilayer(offlineId),
84  idHelper.gasGap(offlineId),
85  sTgcIdHelper::sTgcChannelTypes::Wire, 1);
86 
87  ATH_MSG_VERBOSE("sTgc hit: time " << hit.globalTime()
88  << " position " << Amg::toString(hit.globalPosition(), 2)
89  << " mclink " << hit.particleLink() << " PDG ID " << hit.particleEncoding() );
90 
91 
92  ATH_MSG_DEBUG("Retrieving detector element for: "<< m_idHelperSvc->toStringDetEl(layid) << " energyDeposit "<<energyDeposit );
93 
94  const MuonGM::sTgcReadoutElement* detEl = condContainers.detMgr->getsTgcReadoutElement(layid);
95  if( !detEl ){ return {}; }
96 
97 
98  // DO THE DIGITIZATTION HERE ////////
99 
100  // Required precision on length in mm
101  constexpr double length_tolerance = 0.01;
102 
103  // Retrieve the wire surface
104  int surfHash_wire = detEl->surfaceHash(layid);
105  const Trk::PlaneSurface& SURF_WIRE = detEl->surface(surfHash_wire); // get the wire surface
106 
107  // Hit post-Step global position
108  const Amg::Vector3D& GPOS{hit.globalPosition()};
109  // Hit pre-Step global position
110  const Amg::Vector3D& pre_pos{hit.globalPrePosition()};
111  // Hit global direction
112  const Amg::Vector3D& GLODIRE{hit.globalDirection()};
113 
114  // Hit position in the wire surface's coordinate frame
115  Amg::Vector3D hitOnSurface_wire{SURF_WIRE.transform().inverse() * GPOS};
116  Amg::Vector3D pre_pos_wire_surf{SURF_WIRE.transform().inverse() * pre_pos};
117  Amg::Vector2D posOnSurf_wire{0.5 * (hitOnSurface_wire + pre_pos_wire_surf).block<2,1>(0,0)};
118 
119  /* Determine the closest wire and the distance of closest approach
120  * Since most particles pass through the the wire plane between two wires,
121  * the nearest wire should be one of these two wire. Otherwise, the particle's
122  * trajectory is uncommon, and such rare case is not supported yet.
123  *
124  * Finding that nearest wire follows the following steps:
125  * - Compute the distance to the wire at the center of the current wire pitch
126  * - Compute the distance to the other adjacent wire
127  */
128 
129  // Wire number of the current wire pitch
130  int wire_number = detEl->getDesign(layid)->wireNumber(posOnSurf_wire);
131 
132  // If wire number is invalid, verify if hit is near the edge of the chamber.
133  const int number_wires = detEl->numberOfWires(layid);
134  if ((wire_number < 1) || (wire_number > number_wires)) {
135  // Compute the wire number using either the pos-step position or
136  // the pre-step position, whichever yields a valid wire number.
137  wire_number = detEl->getDesign(layid)->wireNumber(hitOnSurface_wire.block<2,1>(0,0));
138  if ((wire_number < 1) || (wire_number > number_wires)) {
139  wire_number = detEl->getDesign(layid)->wireNumber(pre_pos_wire_surf.block<2,1>(0,0));
140  }
141  }
142 
143  // Compute the position of the ionization and its distance relative to a given sTGC wire.
144  Ionization ionization = pointClosestApproach(detEl, layid, wire_number, pre_pos_wire_surf, hitOnSurface_wire);
145  double dist_wire = ionization.distance;
146  if (dist_wire > 0.) {
147  // Determine the other adjacent wire, which is
148  // -1 if particle crosses the wire surface between wire_number-1 and wire_number
149  // +1 if particle crosses the wire surface between wire_number and wire_number+1
150  int adjacent = 1;
151  if (ionization.posOnSegment.x() < ionization.posOnWire.x()) {adjacent = -1;}
152 
153  // Find the position of the ionization with respect to the adjacent wire
154  Ionization ion_adj = pointClosestApproach(detEl, layid, wire_number+adjacent, pre_pos_wire_surf, hitOnSurface_wire);
155  // Keep the closest point
156  double dist_wire_adj = ion_adj.distance;
157  if ((dist_wire_adj > 0.) && (dist_wire_adj < dist_wire)) {
158  dist_wire = dist_wire_adj;
159  wire_number += adjacent;
160  ionization = std::move(ion_adj);
161  }
162  } else {
163  ATH_MSG_DEBUG("Failed to get the distance between the wire number = " << wire_number
164  << " and hit at " <<Amg::toString(hitOnSurface_wire, 2)
165  << ". Number of wires = " << number_wires
166  << ", "<<m_idHelperSvc->toStringGasGap(layid));
167  return {};
168  }
169 
170  // Update the position of ionization on the wire surface
171  posOnSurf_wire = ionization.posOnWire.block<2,1>(0,0);
172  // Position of the ionization in the global coordinate frame
173  const Amg::Vector3D glob_ionization_pos = SURF_WIRE.transform() * ionization.posOnWire;
174 
175  ATH_MSG_VERBOSE("Ionization_info: distance: " << ionization.distance
176  << " posOnTrack: " <<Amg::toString(ionization.posOnSegment, 3)
177  << " posOnWire: " << Amg::toString(ionization.posOnWire, 3)
178  << " hitGPos: " << Amg::toString(GPOS,3)
179  << " hitPrePos: " <<Amg::toString(pre_pos, 3)
180  << " EDep: " << hit.depositEnergy() << " EKin: " << hit.kineticEnergy()
181  << " pdgId: " << hit.particleEncoding()
182  <<" "<<m_idHelperSvc->toStringGasGap(layid));
183 
184  // Distance should be in the range [0, 0.9] mm, excepting
185  // - particles pass through the wire plane near the edges
186  // - secondary particles created inside the gas gap that go through the gas gap partially.
187  // Most of such particles are not muons and have low kinetic energy.
188  // - particle with trajectory parallel to the sTGC wire plane
189  const double wire_pitch = detEl->wirePitch();
190  if ((dist_wire > 0.) && (std::abs(hit.particleEncoding()) == 13) && (dist_wire > (wire_pitch/2))) {
191  ATH_MSG_DEBUG("Distance to the nearest wire (" << dist_wire << ") is greater than expected.");
192  ATH_MSG_DEBUG("Hit globalPos: "<<Amg::toString(GPOS,2)
193  << " globalPrePos: " << Amg::toString(pre_pos, 2)
194  << " EDeposited: " << hit.depositEnergy()
195  << " EKinetic: " << hit.kineticEnergy()
196  << " pdgID: " << hit.particleEncoding()
197  << " "<<m_idHelperSvc->toStringGasGap(layid));
198  }
199 
200  // Do not digitize hits that are too far from the nearest wire
201  if (dist_wire > wire_pitch) {
202  return {};
203  }
204 
205  // Get the gamma pdf parameters associated with the distance of closest approach.
206  const GammaParameter gamParam = getGammaParameter(dist_wire);
207  const double par_kappa = gamParam.kParameter;
208  const double par_theta = gamParam.thetaParameter;
209  const double most_prob_time = getMostProbableArrivalTime(dist_wire);
210  // Compute the most probable value of the gamma pdf
211  double gamma_mpv = (par_kappa - 1) * par_theta;
212  // If the most probable value is less than zero, then set it to zero
213  if (gamma_mpv < 0.) {gamma_mpv = 0.;}
214  const double t0_par = most_prob_time - gamma_mpv;
215 
216  // Digit time follows a gamma distribution, so a value val is
217  // chosen using a gamma random generator then is shifted by t0
218  // to account for drift time.
219  // Note: CLHEP::RandGamma takes the parameters k and lambda,
220  // where lambda = 1 / theta.
221  double digit_time = t0_par + CLHEP::RandGamma::shoot(condContainers.rndmEngine, par_kappa, 1/par_theta);
222 
223  // Sometimes, digit_time is negative because t0_par can be negative.
224  // In such case, discard the negative value and shoot RandGamma for another value.
225  // However, if that has already been done many times then set digit_time to zero
226  // in order to avoid runaway loop.
227  constexpr int shoot_limit = 4;
228  int shoot_counter = 0;
229  while (digit_time < 0.) {
230  if (shoot_counter > shoot_limit) {
231  digit_time = 0.;
232  break;
233  }
234  digit_time = t0_par + CLHEP::RandGamma::shoot(condContainers.rndmEngine, par_kappa, 1/par_theta);
235  ++shoot_counter;
236  }
237 
238  ATH_MSG_DEBUG("sTgcDigitMaker distance = " << dist_wire
239  << ", time = " << digit_time
240  << ", k parameter = " << par_kappa
241  << ", theta parameter = " << par_theta
242  << ", most probable time = " << most_prob_time);
243 
244  bool isValid = false;
246  if (condContainers.efficiencies) {
247  const double efficiency = condContainers.efficiencies->getEfficiency(layid);
248  // Lose Hits to match HV efficiency
249  if (CLHEP::RandFlat::shoot(condContainers.rndmEngine,0.0,1.0) > efficiency) return {};
250  }
251 
252 
253  sTgcDigitVec digits{};
254 
255  //const double stripPropagationTime = 3.3*CLHEP::ns/CLHEP::m * detEl->distanceToReadout(posOnSurf_strip, elemId); // 8.5*ns/m was used until MC10.
256  const double stripPropagationTime = 0.; // 8.5*ns/m was used until MC10.
257 
258  double sDigitTimeWire = digit_time;
259  double sDigitTimePad = sDigitTimeWire;
260  double sDigitTimeStrip = sDigitTimeWire + stripPropagationTime;
261 
262  uint16_t bctag = 0;
263 
264  //##################################################################################
265  //######################################### strip readout ##########################
266  //##################################################################################
267  ATH_MSG_DEBUG("sTgcDigitMaker::strip response ");
268  int channelType = sTgcIdHelper::sTgcChannelTypes::Strip;
269 
270  Identifier newId = idHelper.channelID(layid,idHelper.multilayer(layid),
271  idHelper.gasGap(layid), channelType, 1, isValid);
272 
273  // get strip surface
274  int surfHash_strip = detEl->surfaceHash(newId);
275  const Trk::PlaneSurface& SURF_STRIP = detEl->surface(surfHash_strip); // get the strip surface
276 
277  const Amg::Vector3D hitOnSurface_strip = SURF_STRIP.transform().inverse()*glob_ionization_pos;
278  Amg::Vector2D posOnSurf_strip {Amg::Vector2D::Zero()};
279 
281  //This block is used to apply As-Built and BLine corrections for dedicated studies.
282  Amg::Vector3D posAfterAsBuilt {Amg::Vector3D::Zero()};
283  detEl->spacePointPosition(newId, hitOnSurface_strip.x(), hitOnSurface_strip.y(), posAfterAsBuilt);
284  posOnSurf_strip = posAfterAsBuilt.block<2,1>(0,0);
285  } else {
286  posOnSurf_strip = hitOnSurface_strip.block<2,1>(0,0);
287  }
288 
289  bool insideBounds = SURF_STRIP.insideBounds(posOnSurf_strip);
290  if(!insideBounds) {
291  ATH_MSG_DEBUG("Outside of the strip surface boundary : " << m_idHelperSvc->toString(newId) << "; local position " <<posOnSurf_strip );
292  return {};
293  }
294 
295  //************************************ find the nearest readout element **************************************
296 
297  int stripNumber = detEl->stripNumber(posOnSurf_strip, newId);
298  if( stripNumber == -1 ){
299  // Verify if the energy deposit is at the boundary
300  const double new_posX = (posOnSurf_strip.x() > 0.0)? posOnSurf_strip.x() - length_tolerance
301  : posOnSurf_strip.x() + length_tolerance;
302  const Amg::Vector2D new_position(new_posX, posOnSurf_strip.y());
303  stripNumber = detEl->stripNumber(new_position, newId);
304  // Skip hit if still unable to obtain strip number
305  if (stripNumber < 1) {
306  ATH_MSG_WARNING("Failed to obtain strip number " << m_idHelperSvc->toString(newId) );
307  ATH_MSG_WARNING("Position on strip surface = (" << posOnSurf_strip.x() << ", " << posOnSurf_strip.y() << ")");
308  return {};
309  }
310  }
311  newId = idHelper.channelID(layid, idHelper.multilayer(layid),
312  idHelper.gasGap(layid), channelType, stripNumber, isValid);
313  if(!isValid && stripNumber != -1) {
314  ATH_MSG_ERROR("Failed to obtain identifier " << m_idHelperSvc->toString(newId) );
315  return {};
316  }
317 
318  const int NumberOfStrips = detEl->numberOfStrips(newId);
319  const double stripHalfPitch = detEl->channelPitch(newId)*0.5; // 3.2/2 = 1.6 mm
320 
321  //************************************ conversion of energy to charge **************************************
322 
323  // Typical ionized charge in pC per keV deposited. The constant is determined from ionization
324  // study with Garfield program. A note titled "Charge Energy Relation" which outlines
325  // conversion can be found here:
326  // https://cernbox.cern.ch/index.php/apps/files/?dir=/__myshares/Documents (id:274113) // link is dead
327  const double ionized_charge = (5.65E-6)*energyDeposit/CLHEP::keV;
328 
329  // To get avalanche gain, polya function is taken from Blum paper https://inspirehep.net/literature/807304
330  // m_polyaFunction = new TF1("m_polyaFunction","(1.0/[1])*(TMath::Power([0]+1,[0]+1)/TMath::Gamma([0]+1))*TMath::Power(x/[1],[0])*TMath::Exp(-([0]+1)*x/[1])",0,3000000);
331 
332  // Mean value for total gain due to E field;
333  // To calculate this gain from polya distibution, we replace in gamma PDF:
334  // alpha = 1+theta and
335  // beta = 1+theta/mean
336  // With these substitutions, gamma PDF gives the same sampling values as those from polya PDF.
337  const double gain = CLHEP::RandGamma::shoot(condContainers.rndmEngine, 1. + m_theta, (1. + m_theta)/m_meanGasGain);
338 
339  // total charge after avalanche
340  const double total_charge = gain*ionized_charge;
341 
342  //************************************ spread charge among readout element **************************************
343 
344  // Charge Spread including tan(theta) resolution term.
345  const double tan_theta = GLODIRE.perp()/GLODIRE.z();
346  // The angle dependance on strip resolution goes as tan^2(angle)
347  const double angle_dependency = std::hypot(m_posResIncident, m_posResAngular * tan_theta);
348 
349  const double cluster_posX = posOnSurf_strip.x();
350  double peak_position = CLHEP::RandGaussZiggurat::shoot(condContainers.rndmEngine, cluster_posX, m_StripResolution*angle_dependency);
351 
352  // Each readout plane reads about half the total charge produced on the wire,
353  // including a tan(theta) term to describe the increase of charge with incident angle
354  const double norm = 0.5 * total_charge * m_stripChargeScale * std::hypot(1, m_chargeAngularFactor * tan_theta);
355  // Strip cluster charge profile described by a double Gaussian.
356  // The independent parameter x is in the units of strip channel, one strip channel = 3.2 mm,
357  // so convert position from mm to strip channel if it is not already.
358  std::unique_ptr<TF1> clusterProfile = std::make_unique<TF1>("fgaus",
359  "[0]*exp(-0.5*(x/[1])^2)+[2]*exp(-0.5*(x/[3])^2)",
360  -300., 300.);
361  clusterProfile->SetParameters(norm * m_clusterProfile[0], // normalization of 1st Gaussian
362  m_clusterProfile[1], // sigma of 1st Gaussian
363  norm * m_clusterProfile[2], // normalization of 2nd Gaussian
364  m_clusterProfile[3]); // sigma of 2nd Gaussian
365 
366  // Lower limit on strip charge (arbitrary limit), in pC, which has the same units as the parameter ionized_charge.
367  constexpr double tolerance_charge = 0.0005;
368  // Set a maximum number of neighbour strips to avoid very long loop. This is an arbitrary number.
369  constexpr unsigned int max_neighbor = 10;
370 
371  // Spread charge on the strips that are on the upper half of the strip cluster
372  for (unsigned int iStrip = 0; iStrip <= max_neighbor; ++iStrip) {
373  int currentStrip = stripNumber + iStrip;
374  if (currentStrip > NumberOfStrips) break;
375 
376  // Get the strip identifier and create the digit
377  newId = idHelper.channelID(layid, idHelper.multilayer(layid), idHelper.gasGap(layid),
378  channelType, currentStrip, isValid);
379  if (isValid) {
381  if (!detEl->stripPosition(newId, locpos)) {
382  ATH_MSG_WARNING("Failed to obtain local position for identifier " << m_idHelperSvc->toString(newId) );
383  }
384 
385  // Estimate the digit charge
386  // Position with respect to the peak of the charge curve
387  double x_relative = locpos.x() - peak_position;
388  // In clusterProfile curve, position should be in the units of strip channel
389  double charge = clusterProfile->Integral(x_relative/(2*stripHalfPitch) - 0.5, x_relative/(2*stripHalfPitch) + 0.5);
390  // If charge is too small, stop creating neighbor strip
391  if (charge < tolerance_charge) break;
392 
393  // Estimate digit time
394  double strip_time = sDigitTimeStrip;
395  // Strip time response can be delayed due to the resistive layer.
396  // A correction would be required if the actual VMM front-end doesn't re-align the strip timing.
397  if (m_doTimeOffsetStrip) {
398  // Determine how far the current strip is from the middle strip
399  int indexFromMiddleStrip = iStrip;
400  if ((iStrip > 0) && ((x_relative + (0.75 - iStrip * 2) * stripHalfPitch) < 0))
401  indexFromMiddleStrip = iStrip - 1;
402  // Add time delay due to resistive layer
403  strip_time += getTimeOffsetStrip(indexFromMiddleStrip);
404  }
405 
406  addDigit(digits, newId, bctag, strip_time, charge);
407 
408  ATH_MSG_VERBOSE("Created a strip digit: strip number = " << currentStrip << ", charge = " << charge
409  << ", time = " << strip_time << ", time offset = " << strip_time-sDigitTimeStrip
410  << ", neighbor index = " << iStrip
411  << ", strip position = "<<Amg::toString(locpos, 2));
412  }
413  }
414 
415  // The lower half of the strip cluster
416  for (unsigned int iStrip = 1; iStrip <= max_neighbor; ++iStrip) {
417  int currentStrip = stripNumber - iStrip;
418  if (currentStrip < 1) break;
419 
420  newId = idHelper.channelID(layid,idHelper.multilayer(layid),
421  idHelper.gasGap(layid), channelType, currentStrip, isValid);
422  if (isValid) {
424  if (!detEl->stripPosition(newId, locpos)) {
425  ATH_MSG_WARNING("Failed to obtain local position for identifier " << m_idHelperSvc->toString(newId) );
426  }
427 
428  // Estimate the digit charge
429  double x_relative = locpos.x() - peak_position;
430  double charge = clusterProfile->Integral(x_relative/(2*stripHalfPitch) - 0.5, x_relative/(2*stripHalfPitch) + 0.5);
431  if (charge < tolerance_charge) break;
432 
433  // Estimate digit time
434  double strip_time = sDigitTimeStrip;
435  // Time delay due to resistive layer
436  if (m_doTimeOffsetStrip) {
437  int indexFromMiddleStrip = ((x_relative + (iStrip * 2 - 0.75) * stripHalfPitch) > 0)? iStrip - 1 : iStrip;
438  strip_time += getTimeOffsetStrip(indexFromMiddleStrip);
439  }
440 
441  addDigit(digits, newId, bctag, strip_time, charge);
442 
443  ATH_MSG_VERBOSE("Created a strip digit: strip number = " << currentStrip << ", charge = " << charge
444  << ", time = " << strip_time << ", time offset = " << strip_time-sDigitTimeStrip
445  << ", neighbor index = " << iStrip
446  << ", strip position = " << Amg::toString(locpos, 2));
447  }
448  }
449  // end of strip digitization
450 
451  if(m_channelTypes==1) {
452  ATH_MSG_WARNING("Only digitize strip response !");
453  return digits;
454  }
455 
456  //##################################################################################
457  //######################################### pad readout ##########################
458  //##################################################################################
459  ATH_MSG_DEBUG("sTgcDigitMaker::pad response ");
460  channelType = sTgcIdHelper::sTgcChannelTypes::Pad;
461 
462  Identifier PAD_ID = idHelper.channelID(layid, idHelper.multilayer(layid),
463  idHelper.gasGap(layid), channelType, 1);// find the a pad id
464  //************************************ find the nearest readout element **************************************
465  int surfHash_pad = detEl->surfaceHash(PAD_ID);
466  const Trk::PlaneSurface& SURF_PAD = detEl->surface(surfHash_pad); // get the pad surface
467 
468  const Amg::Vector3D hitOnSurface_pad = SURF_PAD.transform().inverse()*glob_ionization_pos;
469  const Amg::Vector2D posOnSurf_pad(hitOnSurface_pad.x(), hitOnSurface_pad.y());
470 
471 
472  insideBounds = SURF_PAD.insideBounds(posOnSurf_pad);
473 
474  if(insideBounds) {
475  int padNumber = detEl->stripNumber(posOnSurf_pad, PAD_ID);
476  if( padNumber == -1 ){
477  // Verify if the energy deposit is at the boundary
478  const double new_posX = (posOnSurf_pad.x()>0.0)? posOnSurf_pad.x()-length_tolerance
479  : posOnSurf_pad.x()+length_tolerance;
480  const double new_posY = (posOnSurf_pad.y()>0.0)? posOnSurf_pad.y()-length_tolerance
481  : posOnSurf_pad.y()+length_tolerance;
482  const Amg::Vector2D new_position(new_posX, new_posY);
483  padNumber = detEl->stripNumber(new_position, PAD_ID);
484  // Skip hit if still unable to obtain pad number
485  if (padNumber < 1) {
486  ATH_MSG_WARNING("Failed to obtain pad number " << m_idHelperSvc->toString(PAD_ID) );
487  ATH_MSG_WARNING("Position on pad surface = (" << posOnSurf_pad.x() << ", " << posOnSurf_pad.y() << ")");
488  return digits;
489  }
490  }
491  newId = idHelper.channelID(layid, idHelper.multilayer(layid),
492  idHelper.gasGap(layid), channelType, padNumber, isValid);
493  if(isValid) {
494  // Find centre position of pad
496  if (!detEl->stripPosition(newId, padPos)) {
497  ATH_MSG_ERROR("Failed to obtain local position for neighbor pad with identifier " << m_idHelperSvc->toString(newId) );
498  return digits;
499  }
500  // Pad sharing needs to look at position on hit vs pad boundaries
501  const Amg::Vector2D diff = posOnSurf_pad - padPos;
502  double halfPadWidthX = 0.5*detEl->getPadDesign(newId)->channelWidth(posOnSurf_pad, true, true);
503  double halfPadWidthY = 0.5*detEl->getPadDesign(newId)->channelWidth(posOnSurf_pad, false);
504 
505  // Charge sharing happens within 4mm window for pads
506  // i.e. the charge is spread over a 2D gaussian of total radius about 4mm
507  // This value depends on actual width of the distribution, but we don't have the
508  // width of the charge distribution for pads. So lets consider 2.5*sigma, where
509  // sigma is the width of the charge distribution for strips.
510  double deltaX = halfPadWidthX - std::abs(diff.x());
511  double deltaY= halfPadWidthY - std::abs(diff.y());
512  bool isNeighX = deltaX < 2.5*m_clusterProfile[3];
513  bool isNeighY = deltaY < 2.5*m_clusterProfile[3];
514  // Pad width can be calculated to be very slightly larger than it should due to rounding errors
515  // So if a hit falls on a given pad but is "outside" the width, just define it to be on the boundary of 2 pads.
516  if (deltaX < 0.) deltaX = 0.1;
517  if (deltaY < 0.) deltaY = 0.1;
518 
519  if (m_doPadSharing && (isNeighX || isNeighY)){
520  std::pair<int, int> padEtaPhi(detEl->getPadDesign(newId)->channelNumber(padPos));
521  // Phi == 1 at the right in the local geometry
522  // In local coordinates, the pad to the right has phi' = phi - 1
523  int newPhi = diff.x() > 0 ? padEtaPhi.second-1 : padEtaPhi.second+1;
524  int newEta = diff.y() > 0 ? padEtaPhi.first+1 : padEtaPhi.first-1;
525  bool validEta = newEta > 0 && newEta < detEl->getPadDesign(newId)->nPadH+1;
526  bool validPhi = newPhi > 0 && newPhi < detEl->getPadDesign(newId)->nPadColumns+1;
527 
528  if (isNeighX && isNeighY && validEta && validPhi){
529  // 4 pads total; makes life a bit harder. Corner of 4 valid pads
530  Identifier neigh_ID_X = idHelper.padID(newId, idHelper.multilayer(newId), idHelper.gasGap(newId),
531  channelType, padEtaPhi.first, newPhi, isValid);
532  Identifier neigh_ID_Y = idHelper.padID(newId, idHelper.multilayer(newId), idHelper.gasGap(newId),
533  channelType, newEta, padEtaPhi.second, isValid);
534  Identifier neigh_ID_XY = idHelper.padID(newId, idHelper.multilayer(newId), idHelper.gasGap(newId),
535  channelType, newEta, newPhi, isValid);
536  double xQfraction = getPadChargeFraction(deltaX);
537  double yQfraction = getPadChargeFraction(deltaY);
538 
539  // Main pad gets 1 - Qfraction of total
540  addDigit(digits, neigh_ID_X, bctag, sDigitTimePad, xQfraction*(1.-yQfraction)*0.5*total_charge);
541  addDigit(digits, neigh_ID_Y, bctag, sDigitTimePad, yQfraction*(1.-xQfraction)*0.5*total_charge);
542  addDigit(digits, neigh_ID_XY, bctag, sDigitTimePad, xQfraction*yQfraction*0.5*total_charge);
543  addDigit(digits, newId, bctag, sDigitTimePad, (1.-xQfraction-yQfraction+xQfraction*yQfraction)*0.5*total_charge);
544  } else if (isNeighX && validPhi){
545  // There is only 1 neighbor, immediately to the left or right.
546  Identifier neigh_ID = idHelper.padID(newId, idHelper.multilayer(newId), idHelper.gasGap(newId),
547  channelType, padEtaPhi.first, newPhi, isValid);
548 
549  // NeighborPad gets Qfraction of the total pad charge: 0.5*total_charge
550  // Main pad gets 1 - Qfraction of total
551  double xQfraction = getPadChargeFraction(deltaX);
552  addDigit(digits, newId, bctag, sDigitTimePad, (1.-xQfraction)*0.5*total_charge);
553  addDigit(digits, neigh_ID, bctag, sDigitTimePad, xQfraction*0.5*total_charge);
554  }
555  else if (isNeighY && validEta){
556  // There is only 1 neighbor, immediately above or below
557  Identifier neigh_ID = idHelper.padID(newId, idHelper.multilayer(newId), idHelper.gasGap(newId),
558  channelType, newEta, padEtaPhi.second, isValid);
559 
560  // NeighborPad gets Qfraction of the total pad charge: 0.5*total_charge
561  // Main pad gets 1 - Qfraction of total
562  double yQfraction = getPadChargeFraction(deltaX);
563  addDigit(digits, newId, bctag, sDigitTimePad, (1.-yQfraction)*0.5*total_charge);
564  addDigit(digits, neigh_ID, bctag, sDigitTimePad, yQfraction*0.5*total_charge);
565  }
566 
567  }
568  else{
569  // No charge sharing: hit is nicely isolated within pad
570  addDigit(digits, newId, bctag, sDigitTimePad, 0.5*total_charge);
571  }
572 
573  }
574  else if(padNumber != -1) {
575  ATH_MSG_ERROR("Failed to obtain identifier " << m_idHelperSvc->toString(newId) );
576  }
577  }
578  else {
579  ATH_MSG_DEBUG("Outside of the pad surface boundary :" << m_idHelperSvc->toString(PAD_ID)<< " local position " <<posOnSurf_pad );
580  }
581 
582  if(m_channelTypes==2) {
583  ATH_MSG_WARNING("Only digitize strip/pad response !");
584  return digits;
585  }
586 
587 
588  //##################################################################################
589  //######################################### wire readout ##########################
590  //##################################################################################
591  ATH_MSG_DEBUG("sTgcDigitMaker::wire response ");
592  channelType = sTgcIdHelper::sTgcChannelTypes::Wire;
593 
594  // Find the ID of the first wiregroup
595  Identifier WIREGP_ID = idHelper.channelID(layid, idHelper.multilayer(layid),
596  idHelper.gasGap(layid), channelType, 1);
597 
598  //************************************ find the nearest readout element **************************************
599  insideBounds = SURF_WIRE.insideBounds(posOnSurf_wire);
600 
601  if(insideBounds) {
602  // Determine the wire number
603 
604  int wiregroupNumber = detEl->stripNumber(posOnSurf_wire, WIREGP_ID);
605  if( wiregroupNumber == -1 ){
606  // Verify if the energy deposit is at the boundary
607  const double new_posX = (posOnSurf_wire.x() > 0.0)? posOnSurf_wire.x() - length_tolerance
608  : posOnSurf_wire.x() + length_tolerance;
609  const Amg::Vector2D new_position(new_posX, posOnSurf_wire.y());
610  wiregroupNumber = detEl->stripNumber(new_position, WIREGP_ID);
611  // Skip hit if still unable to obtain pad number
612  if (wiregroupNumber < 1) {
613  ATH_MSG_WARNING("Failed to obtain wire number " << m_idHelperSvc->toString(WIREGP_ID) );
614  ATH_MSG_WARNING("Position on wire surface = (" << posOnSurf_wire.x() << ", " << posOnSurf_wire.y() << ")");
615  return digits;
616  }
617  }
618 
619  // Find ID of the actual wiregroup
620  newId = idHelper.channelID(layid, idHelper.multilayer(layid), idHelper.gasGap(layid),
621  channelType, wiregroupNumber, isValid);
622 
623  if(isValid) {
624  int NumberOfWiregroups = detEl->numberOfStrips(newId);
625  if(wiregroupNumber>=1&&wiregroupNumber<=NumberOfWiregroups) {
626  addDigit(digits, newId, bctag, sDigitTimeWire, total_charge);
627  }
628  } // end of if(isValid)
629  else if (wiregroupNumber != -1){
630  ATH_MSG_ERROR("Failed to obtain wiregroup identifier " << m_idHelperSvc->toString(newId) );
631  }
632  }
633  else {
634  ATH_MSG_DEBUG("Outside of the wire surface boundary :" << m_idHelperSvc->toString(WIREGP_ID)<< " local position " <<posOnSurf_wire );
635  }
636  // end of wire digitization
637 
638  return digits;
639 }
640 
641 //+++++++++++++++++++++++++++++++++++++++++++++++
643  const Identifier& id,
644  int wireNumber,
645  const Amg::Vector3D& preStepPos,
646  const Amg::Vector3D& postStepPos) const {
647  // tolerance in mm
648  constexpr double tolerance = 0.001;
649  // minimum segment length
650  constexpr double min_length = 0.1;
651 
652  // Position of the ionization
653  Ionization ionization;
654 
655  // Wire number should be one or greater
656  if (wireNumber < 1) return ionization;
657 
658  // Wire number too large
659  if (wireNumber > detEl->numberOfWires(id)) return ionization;
660 
661  // Finding smallest distance and the points at the smallest distance.
662  // The smallest distance between two lines is perpendicular to both lines.
663  // We can construct two lines in the wire surface local coordinate frame:
664  // - one for the hit segment with equation h0 + t * v_h, where h0 is a point
665  // and v_h is the unit vector of the hit segment
666  // - another for the wire with similar equation w0 + s * v_w, where w0 is a
667  // point and v_w is the unit vector of the wire line
668  // Then it is possible to determine the factors s and t by requiring the
669  // dot product to be zero:
670  // 1. (h0 - w0) \dot v_h = 0
671  // 2. (h0 - w0) \dot v_w = 0
672 
673  // Wire pitch
674  const double wire_pitch = detEl->wirePitch();
675  // Wire local position on the wire plane, the y-coordinate is arbitrary and z-coordinate is zero
676  const double wire_posX = detEl->positionFirstWire(id) + (wireNumber - 1) * wire_pitch;
677  const Amg::Vector3D wire_position(wire_posX, postStepPos.y(), 0.);
678  // The wires are parallel to Y in the wire plane's coordinate frame
679  const Amg::Vector3D wire_direction{Amg::Vector3D::UnitY()};
680 
681  // particle trajectory
682  Amg::Vector3D hit_direction{postStepPos - preStepPos};
683  const double seg_length = hit_direction.mag();
684  if (seg_length > tolerance) hit_direction /= seg_length;
685 
686  // Find the point on the track segment that is closest to the wire
687  if (seg_length < min_length) {
688  ionization.posOnSegment = postStepPos;
689  ionization.posOnWire = wire_position;
690  ionization.distance = std::hypot(postStepPos.x() - wire_posX, postStepPos.z());
691  return ionization;
692  }
693 
694  // Dot product between the wire and hit direction
695  const double cos_theta = wire_direction.dot(hit_direction);
696  // distance between the hit and wire
697  const Amg::Vector3D dist_wire_hit = postStepPos - wire_position;
698 
699  // Verifier the special case where the two lines are parallel
700  if (std::abs(cos_theta - 1.0) < tolerance) {
701  ATH_MSG_DEBUG("The track segment is parallel to the wire, position of digit is undefined");
702  ionization.posOnSegment = 0.5 * (postStepPos + preStepPos);
703  ionization.posOnWire = Amg::Vector3D(wire_posX, ionization.posOnSegment.y(), 0.0);
704  ionization.distance = std::hypot(ionization.posOnSegment.x() - wire_posX,
705  ionization.posOnSegment.z());
706  return ionization;
707  }
708 
709  // Perpendicular component squared
710  const double sin_theta_2 = 1.0 - cos_theta * cos_theta;
711 
712  //* Point on the hit segment
713  const double factor_hit = (-dist_wire_hit.dot(hit_direction)
714  + dist_wire_hit.dot(wire_direction) * cos_theta) / sin_theta_2;
715  Amg::Vector3D ionization_pos = postStepPos + factor_hit * hit_direction;
716 
717  // If the point is on the track segment, then compute the other point on the wire.
718  // Otherwise, set the ionization at the pre-step position and compute where it
719  // should be on the wire.
720  Amg::Vector3D pos_on_wire{Amg::Vector3D::Zero()};
721  if (factor_hit < seg_length) {
722  //* Point on the wire line
723  const double factor_wire = (dist_wire_hit.dot(wire_direction)
724  - dist_wire_hit.dot(hit_direction) * cos_theta) / sin_theta_2;
725  pos_on_wire = wire_position + factor_wire * wire_direction;
726  } else {
727  ionization_pos = preStepPos;
728  pos_on_wire = wire_position - (seg_length * cos_theta) * wire_direction;
729  }
730 
731  // Save the distance and ionization position
732  ionization.distance = (ionization_pos - pos_on_wire).mag();
733  ionization.posOnSegment = ionization_pos;
734  ionization.posOnWire = pos_on_wire;
735 
736  return ionization;
737 }
738 
739 //+++++++++++++++++++++++++++++++++++++++++++++++
741  const Identifier& id,
742  const uint16_t bctag,
743  const double digittime,
744  const double charge) {
745 
746  constexpr double tolerance = 0.1;
747  if (std::find_if(digits.begin(),digits.end(), [&](std::unique_ptr<sTgcDigit>& known) {
748  return known->identify() == id && std::abs(digittime - known->time()) < tolerance;
749  }) == digits.end()) {
750  digits.push_back(std::make_unique<sTgcDigit>(id, bctag, digittime, charge, 0, 0));
751  }
752 }
753 
754 //+++++++++++++++++++++++++++++++++++++++++++++++
756  // Verify the file sTGC_Digitization_timeArrival.dat exists
757  const std::string file_name = "sTGC_Digitization_timeArrival.dat";
758  std::string file_path = PathResolver::find_file(file_name, "DATAPATH");
759  if(file_path.empty()) {
760  ATH_MSG_FATAL("readFileOfTimeWindowOffset(): Could not find file " << file_name );
761  return StatusCode::FAILURE;
762  }
763 
764  // Open the sTGC_Digitization_timeArrival.dat file
765  std::ifstream ifs{file_path, std::ios::in};
766  if(ifs.bad()) {
767  ATH_MSG_FATAL("sTgcDigitMaker: Failed to open time of arrival file " << file_name );
768  return StatusCode::FAILURE;
769  }
770 
771  // Read the sTGC_Digitization_timeWindowOffset.dat file
772  std::string line;
773  GammaParameter param{};
774 
775  while (std::getline(ifs, line)) {
776  std::string key;
777  std::istringstream iss(line);
778  iss >> key;
779  if (key.compare("bin") == 0) {
780  iss >> param.lowEdge >> param.kParameter >> param.thetaParameter;
781  m_gammaParameter.push_back(param);
782  } else if (key.compare("mpv") == 0) {
783  double mpt;
784  int idx{0};
785  while (iss >> mpt) {m_mostProbableArrivalTime[idx++] = mpt;}
786  }
787  }
788 
789  // Close the file
790  ifs.close();
791  return StatusCode::SUCCESS;
792 }
793 
794 //+++++++++++++++++++++++++++++++++++++++++++++++
796 
797  const double d = std::abs(distance);
798  // Find the parameters assuming the container is sorted in ascending order of 'lowEdge'
799  int index{-1};
800  for (const auto& par: m_gammaParameter) {
801  if (d < par.lowEdge) {
802  break;
803  }
804  ++index;
805  }
806  return m_gammaParameter.at(index);
807 }
808 
809 //+++++++++++++++++++++++++++++++++++++++++++++++
811 
812  const double d{std::abs(distance)};
813  double mpt{0};
814  for (size_t t = 0 ; t < m_mostProbableArrivalTime.size(); ++t){
815  mpt += m_mostProbableArrivalTime[t] * std::pow(d, t);
816  }
817  return mpt;
818 }
819 
820 //+++++++++++++++++++++++++++++++++++++++++++++++
822  // Verify the file sTGC_Digitization_timeOffsetStrip.dat exists
823  const std::string file_name = "sTGC_Digitization_timeOffsetStrip.dat";
824  std::string file_path = PathResolver::find_file(file_name, "DATAPATH");
825  if(file_path.empty()) {
826  ATH_MSG_FATAL("readFileOfTimeWindowOffset(): Could not find file " << file_name );
827  return StatusCode::FAILURE;
828  }
829 
830  // Open the sTGC_Digitization_timeOffsetStrip.dat file
831  std::ifstream ifs{file_path, std::ios::in};
832  if(ifs.bad()) {
833  ATH_MSG_FATAL("Failed to open time of arrival file " << file_name );
834  return StatusCode::FAILURE;
835  }
836 
837  // Initialize the container to store the time offset.
838  // The number of parameters, 6, corresponds to the number of lines to be read
839  // from sTGC_Digitization_timeOffsetStrip.dat.
840  // Setting the default offset to 0 ns.
841 
842  // Read the input file
843  std::string line;
844  size_t index{0};
845  double value{0.0};
846  while (std::getline(ifs, line)) {
847  std::string key;
848  std::istringstream iss(line);
849  iss >> key;
850  if (key.compare("strip") == 0) {
851  iss >> index >> value;
852  if (index >= m_timeOffsetStrip.size()) continue;
854  }
855  }
856  return StatusCode::SUCCESS;
857 }
858 
859 //+++++++++++++++++++++++++++++++++++++++++++++++
860 double sTgcDigitMaker::getTimeOffsetStrip(size_t neighbor_index) const {
861  return m_timeOffsetStrip.at(std::min(neighbor_index, m_timeOffsetStrip.size() -1));
862 }
863 
864 //+++++++++++++++++++++++++++++++++++++++++++++++
866  // The charge fraction that is found past a distance x away from the
867  // centre of a 2D gaussian distribution of width of cluster profile is
868  // described by a modified error function.
869 
870  // The modified error function perfectly describes
871  // the pad charge sharing distribution figure 16 of the sTGC
872  // testbeam paper https://arxiv.org/pdf/1509.06329.pdf
873 
874  return 0.5 * (1.0 - std::erf( distance / (std::sqrt(2) * m_clusterProfile[3])));
875 }
PlotCalibFromCool.norm
norm
Definition: PlotCalibFromCool.py:100
MuonGM::MuonPadDesign::channelNumber
std::pair< int, int > channelNumber(const Amg::Vector2D &pos) const
calculate local channel number, range 1=nstrips like identifiers.
Definition: MuonPadDesign.cxx:39
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
Muon::IMuonIdHelperSvc::stgcIdHelper
virtual const sTgcIdHelper & stgcIdHelper() const =0
access to TgcIdHelper
sTgcSimIdToOfflineId
Definition: sTgcSimIdToOfflineId.h:12
sTgcDigitMaker::m_posResIncident
double m_posResIncident
Definition: sTgcDigitMaker.h:158
AthCheckMacros.h
MuonGM::sTgcReadoutElement::numberOfStrips
virtual int numberOfStrips(const Identifier &layerId) const override final
number of strips per layer
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/sTgcReadoutElement.h:408
sTGCSimHit::particleLink
const HepMcParticleLink & particleLink() const
Definition: sTGCSimHit.h:96
PathResolver::find_file
static std::string find_file(const std::string &logical_file_name, const std::string &search_path, SearchType search_type=LocalSearch)
Definition: PathResolver.cxx:251
Surface.h
collListGuids.line
string line
Definition: collListGuids.py:77
makeComparison.deltaY
int deltaY
Definition: makeComparison.py:44
sTgcDigitMaker::getTimeOffsetStrip
double getTimeOffsetStrip(size_t neighbor_index) const
Get digit time offset of a strip depending on its relative position to the strip at the centre of the...
Definition: sTgcDigitMaker.cxx:860
sTgcReadoutElement.h
Amg::Vector2D
Eigen::Matrix< double, 2, 1 > Vector2D
Definition: GeoPrimitives.h:48
index
Definition: index.py:1
sTgcDigitMaker::readFileOfTimeOffsetStrip
StatusCode readFileOfTimeOffsetStrip()
Read share/sTGC_Digitization_timeOffsetStrip.dat.
Definition: sTgcDigitMaker.cxx:821
hist_file_dump.d
d
Definition: hist_file_dump.py:143
sTgcDigitMaker::Ionization
Ionization object with distance, position on the hit segment and position on the wire.
Definition: sTgcDigitMaker.h:84
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
CaloCondBlobAlgs_fillNoiseFromASCII.gain
gain
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:110
sTgcDigitMaker::getMostProbableArrivalTime
double getMostProbableArrivalTime(double distance) const
Get the most probable time of arrival.
Definition: sTgcDigitMaker.cxx:810
sTgcDigitMaker::m_chargeAngularFactor
double m_chargeAngularFactor
Definition: sTgcDigitMaker.h:164
InDet::adjacent
bool adjacent(unsigned int strip1, unsigned int strip2)
Definition: SCT_ClusteringTool.cxx:45
MuonGM::sTgcReadoutElement::getDesign
const MuonChannelDesign * getDesign(const Identifier &id) const
returns the MuonChannelDesign class for the given identifier
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/sTgcReadoutElement.h:279
mc.diff
diff
Definition: mc.SFGenPy8_MuMu_DD.py:14
sTgcDigitMaker::executeDigi
sTgcDigitVec executeDigi(const DigiConditions &condContainers, const sTGCSimHit &hit) const
Definition: sTgcDigitMaker.cxx:72
athena.value
value
Definition: athena.py:124
Muon::IMuonIdHelperSvc::toStringDetEl
virtual std::string toStringDetEl(const Identifier &id) const =0
print all fields up to detector element to string
MuonGM::sTgcReadoutElement::numberOfWires
int numberOfWires(const Identifier &id) const
Get the total number of wires (single wires) of a chamber.
Definition: MuonDetDescr/MuonReadoutGeometry/src/sTgcReadoutElement.cxx:691
sTgcDigitMaker::readFileOfTimeArrival
StatusCode readFileOfTimeArrival()
Read share/sTGC_Digitization_timeArrival.dat.
Definition: sTgcDigitMaker.cxx:755
sTgcDigitMaker::DigiConditions
Digitize a given hit, determining the time and charge spread on wires, pads and strips.
Definition: sTgcDigitMaker.h:58
MuonGM::sTgcReadoutElement::spacePointPosition
virtual bool spacePointPosition(const Identifier &phiId, const Identifier &etaId, Amg::Vector2D &pos) const override final
space point position for a given pair of phi and eta identifiers The LocalPosition is expressed in th...
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/sTgcReadoutElement.h:436
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
sTgcDigitMaker::GammaParameter
Parameters of a gamma probability distribution function, required for estimating wire digit's time of...
Definition: sTgcDigitMaker.h:75
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
isValid
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
Definition: AtlasPID.h:812
sTgcDigitMaker::~sTgcDigitMaker
virtual ~sTgcDigitMaker()
MuonGM::MuonClusterReadoutElement::surface
virtual const Trk::PlaneSurface & surface() const override
access to chamber surface (phi orientation), uses the first gas gap
Definition: MuonClusterReadoutElement.h:123
sTgcDigitMaker::GammaParameter::thetaParameter
double thetaParameter
Definition: sTgcDigitMaker.h:78
Trk::energyDeposit
@ energyDeposit
Definition: MeasurementType.h:32
MuonGM::sTgcReadoutElement::stripPosition
virtual bool stripPosition(const Identifier &id, Amg::Vector2D &pos) const override final
strip position - should be renamed to channel position If the strip number is outside the range of va...
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/sTgcReadoutElement.h:321
MuonGM::MuonPadDesign::nPadH
int nPadH
Definition: MuonPadDesign.h:68
sTgcDigitMaker::pointClosestApproach
Ionization pointClosestApproach(const MuonGM::sTgcReadoutElement *readoutEle, const Identifier &id, int wireNumber, const Amg::Vector3D &preStepPos, const Amg::Vector3D &postStepPos) const
Determine the points where the distance between two segments is smallest.
Definition: sTgcDigitMaker.cxx:642
sTgcDigitMaker::m_gammaParameter
std::vector< GammaParameter > m_gammaParameter
Definition: sTgcDigitMaker.h:132
physics_parameters.file_name
string file_name
Definition: physics_parameters.py:32
Trk::PlaneSurface::insideBounds
virtual bool insideBounds(const Amg::Vector2D &locpos, double tol1=0., double tol2=0.) const override
This method calls the inside() method of the Bounds.
efficiency
void efficiency(std::vector< double > &bins, std::vector< double > &values, const std::vector< std::string > &files, const std::string &histname, const std::string &tplotname, const std::string &label="")
Definition: dependence.cxx:128
Amg::toString
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Definition: GeoPrimitivesToStringConverter.h:40
sTgcDigitMaker::m_posResAngular
double m_posResAngular
Definition: sTgcDigitMaker.h:159
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
xAOD::uint16_t
setWord1 uint16_t
Definition: eFexEMRoI_v1.cxx:93
sTgcDigitMaker::m_channelTypes
int m_channelTypes
define offsets and widths of time windows for signals from wiregangs and strips.
Definition: sTgcDigitMaker.h:148
sTgcDigitMaker::getGammaParameter
GammaParameter getGammaParameter(double distance) const
Find the gamma pdf parameters of a given distance.
Definition: sTgcDigitMaker.cxx:795
MuonGM::sTgcReadoutElement::surfaceHash
virtual int surfaceHash(const Identifier &id) const override final
returns the hash to be used to look up the surface and transform in the MuonClusterReadoutElement tra...
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/sTgcReadoutElement.h:257
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
MuonGM::sTgcReadoutElement
An sTgcReadoutElement corresponds to a single STGC module; therefore typicaly a barrel muon station c...
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/sTgcReadoutElement.h:30
Muon::DigitEffiData::getEfficiency
double getEfficiency(const Identifier &channelId, bool isInnerQ1=false) const
Returns the signal generation efficiency of the sTgc channel.
Definition: DigitEffiData.cxx:38
Muon::IMuonIdHelperSvc::toStringGasGap
virtual std::string toStringGasGap(const Identifier &id) const =0
print all fields up to gas gap to string
athena.file_path
file_path
Definition: athena.py:94
AthMessaging
Class to provide easy MsgStream access and capabilities.
Definition: AthMessaging.h:55
sTGCSimHit::sTGCId
HitID sTGCId() const
Definition: sTGCSimHit.h:51
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
sTgcSimIdToOfflineId.h
sTgcDigitMaker::GammaParameter::kParameter
double kParameter
Definition: sTgcDigitMaker.h:77
sTgcDigitMaker::addDigit
static void addDigit(sTgcDigitVec &digits, const Identifier &id, const uint16_t bctag, const double digittime, const double charge)
Definition: sTgcDigitMaker.cxx:740
compareGeometries.deltaX
float deltaX
Definition: compareGeometries.py:32
MuonGM::MuonPadDesign::channelWidth
double channelWidth(const Amg::Vector2D &pos, bool measPhi, bool preciseMeas=false) const
calculate local channel width
Definition: MuonPadDesign.h:142
MuonGM::sTgcReadoutElement::channelPitch
double channelPitch(const Identifier &id) const
Channel pitch.
Definition: MuonDetDescr/MuonReadoutGeometry/src/sTgcReadoutElement.cxx:589
sTgcDigitMaker::Ionization::posOnWire
Amg::Vector3D posOnWire
Definition: sTgcDigitMaker.h:87
sTgcDigitMaker::Ionization::posOnSegment
Amg::Vector3D posOnSegment
Definition: sTgcDigitMaker.h:86
tolerance
Definition: suep_shower.h:17
sTGCSimHit::globalDirection
const Amg::Vector3D & globalDirection() const
Definition: sTGCSimHit.h:46
sTgcDigitMaker::m_doTimeOffsetStrip
bool m_doTimeOffsetStrip
Definition: sTgcDigitMaker.h:155
PathResolver.h
sTGCSimHit::kineticEnergy
double kineticEnergy() const
Definition: sTGCSimHit.h:48
sTGCSimHit::globalTime
double globalTime() const
Definition: sTGCSimHit.h:41
createCoolChannelIdFile.par
par
Definition: createCoolChannelIdFile.py:29
sTgcDigitMaker::m_doPadSharing
bool m_doPadSharing
Definition: sTgcDigitMaker.h:151
charge
double charge(const T &p)
Definition: AtlasPID.h:931
sTgcIdHelper
Definition: sTgcIdHelper.h:55
sTgcDigitMaker::getPadChargeFraction
static double getPadChargeFraction(double distance)
Definition: sTgcDigitMaker.cxx:865
MuonGM::MuonPadDesign::nPadColumns
int nPadColumns
Definition: MuonPadDesign.h:69
MuonGM::MuonChannelDesign::wireNumber
int wireNumber(const Amg::Vector2D &pos) const
calculate the sTGC wire number. The method can return a value outside the range [1,...
Definition: MuonChannelDesign.h:259
sTgcDigitMaker::Ionization::distance
double distance
Definition: sTgcDigitMaker.h:85
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
MuonDetectorManager.h
sTGCSimHit::particleEncoding
int particleEncoding() const
Definition: sTGCSimHit.h:45
sTgcDigitMaker::DigiConditions::detMgr
const MuonGM::MuonDetectorManager * detMgr
Definition: sTgcDigitMaker.h:59
sTGCSimHit
Definition: sTGCSimHit.h:15
sTgcDigitMaker::m_clusterProfile
static constexpr std::array< double, 4 > m_clusterProfile
Definition: sTgcDigitMaker.h:162
MuonGM::sTgcReadoutElement::stripNumber
virtual int stripNumber(const Amg::Vector2D &pos, const Identifier &id) const override final
strip number corresponding to local position.
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/sTgcReadoutElement.h:309
DeMoScan.index
string index
Definition: DeMoScan.py:364
python.SystemOfUnits.keV
float keV
Definition: SystemOfUnits.py:173
Muon::IMuonIdHelperSvc::toString
virtual std::string toString(const Identifier &id) const =0
print all fields to string
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
Trk::PlaneSurface
Definition: PlaneSurface.h:64
sTgcDigitMaker::m_timeOffsetStrip
std::array< double, 6 > m_timeOffsetStrip
Definition: sTgcDigitMaker.h:137
sTgcDigitMaker::m_stripChargeScale
double m_stripChargeScale
Definition: sTgcDigitMaker.h:166
known
Definition: TrigBStoxAODTool.cxx:107
sTgcDigitMaker::m_theta
double m_theta
Definition: sTgcDigitMaker.h:149
MuonGM::sTgcReadoutElement::positionFirstWire
double positionFirstWire(const Identifier &id) const
Get the local position of the first wire of the chamber corresponding to the identifier.
Definition: MuonDetDescr/MuonReadoutGeometry/src/sTgcReadoutElement.cxx:674
GeoPrimitivesToStringConverter.h
LArNewCalib_DelayDump_OFC_Cali.idx
idx
Definition: LArNewCalib_DelayDump_OFC_Cali.py:69
Muon::IMuonIdHelperSvc
Interface for Helper service that creates muon Identifiers and can be used to print Identifiers.
Definition: IMuonIdHelperSvc.h:27
sTgcDigitCollection.h
sTgcDigitMaker::m_mostProbableArrivalTime
std::array< double, 5 > m_mostProbableArrivalTime
Definition: sTgcDigitMaker.h:134
sTGCSimHit::depositEnergy
double depositEnergy() const
Definition: sTGCSimHit.h:47
sTgcDigitMaker::initialize
StatusCode initialize()
Initializes sTgcHitIdHelper and sTgcIdHelper, and call the functions to read files containing digitiz...
Definition: sTgcDigitMaker.cxx:52
sTgcDigitMaker::m_applyAsBuiltBLines
bool m_applyAsBuiltBLines
Definition: sTgcDigitMaker.h:168
sTgcDigitMaker::m_StripResolution
double m_StripResolution
Definition: sTgcDigitMaker.h:157
sTgcDigitMaker::sTgcDigitVec
std::vector< std::unique_ptr< sTgcDigit > > sTgcDigitVec
Definition: sTgcDigitMaker.h:65
LocalDirection.h
sTgcDigitMaker.h
MuonGM::sTgcReadoutElement::getPadDesign
const MuonPadDesign * getPadDesign(const Identifier &id) const
returns the MuonChannelDesign class for the given identifier
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/sTgcReadoutElement.h:285
MuonGM::sTgcReadoutElement::wirePitch
double wirePitch(int gas_gap=1) const
single wire pitch.
Definition: MuonDetDescr/MuonReadoutGeometry/src/sTgcReadoutElement.cxx:664
sTgcDigitMaker::DigiConditions::rndmEngine
CLHEP::HepRandomEngine * rndmEngine
Definition: sTgcDigitMaker.h:62
MuonGM::MuonDetectorManager::getsTgcReadoutElement
const sTgcReadoutElement * getsTgcReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
Definition: MuonDetDescr/MuonReadoutGeometry/src/MuonDetectorManager.cxx:261
sTGCSimHit::globalPrePosition
const Amg::Vector3D & globalPrePosition() const
Definition: sTGCSimHit.h:49
sTgcDigitMaker::sTgcDigitMaker
sTgcDigitMaker(const Muon::IMuonIdHelperSvc *idHelperSvc, const int channelTypes, double meanGasGain, bool doPadChargeSharing, double stripChargeScale, bool applyAsBuiltBLines)
Definition: sTgcDigitMaker.cxx:34
sTgcDigitMaker::m_meanGasGain
double m_meanGasGain
Definition: sTgcDigitMaker.h:150
pow
constexpr int pow(int base, int exp) noexcept
Definition: ap_fixedTest.cxx:15
Amg::distance
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:54
Trk::Surface::transform
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
sTGCSimHit::globalPosition
const Amg::Vector3D & globalPosition() const
Definition: sTGCSimHit.h:44
mag
Scalar mag() const
mag method
Definition: AmgMatrixBasePlugin.h:26
sTgcDigitMaker::m_idHelperSvc
const Muon::IMuonIdHelperSvc * m_idHelperSvc
Definition: sTgcDigitMaker.h:139
generate::Zero
void Zero(TH1D *hin)
Definition: generate.cxx:32
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37
sTgcDigitMaker::DigiConditions::efficiencies
const Muon::DigitEffiData * efficiencies
Definition: sTgcDigitMaker.h:60
Identifier
Definition: IdentifierFieldParser.cxx:14