29#include "CLHEP/Units/SystemOfUnits.h"
30#include "CLHEP/Units/PhysicalConstants.h"
33#include "HepPDT/ParticleData.hh"
38#include "CLHEP/Random/RandPoisson.h"
39#include "CLHEP/Random/RandFlat.h"
40#include "CLHEP/Random/RandBinomial.h"
41#include "CLHEP/Random/RandExpZiggurat.h"
42#include "CLHEP/Random/RandGaussZiggurat.h"
55 const HepPDT::ParticleDataTable* pdt,
104 ATH_MSG_FATAL (
"TRT_PAITool for Xenon not defined! no point in continuing!" );
107 ATH_MSG_ERROR (
"TRT_PAITool for Krypton is not defined!!! Xenon TRT_PAITool will be used for Krypton straws!" );
111 ATH_MSG_ERROR (
"TRT_PAITool for Argon is not defined!!! Xenon TRT_PAITool will be used for Argon straws!" );
121 const double intervalBetweenCrossings(
m_settings->timeInterval() / 3.);
129 for (
unsigned int k=0; k<150; k++) {
130 double dist = 10.0*(k+0.5);
141 for (
unsigned int iwheel = 0; iwheel < num->getNEndcapWheels(); ++iwheel)
143 for (
unsigned int iside = 0; iside < 2; ++iside)
145 for (
unsigned int ilayer = 0; ilayer < num->getNEndcapLayers(iwheel); ++ilayer)
155 ATH_MSG_VERBOSE (
"Failed to retrieve endcap element for (iside,iwheel,ilayer)=("
156 << iside<<
", "<<iwheel<<
", "<<ilayer<<
")." );
165 const double zcoordfrac((v.z()>0?v.z():-v.z())/v.mag());
166 if (zcoordfrac<0.98 || zcoordfrac > 1.02)
168 ATH_MSG_WARNING (
"Found endcap straw where the assumption that local x-direction"
169 <<
" is parallel to global z-direction is NOT valid."
170 <<
" Drift times will be somewhat off." );
177 for (
unsigned int phi_it = 0; phi_it < 32; phi_it++)
186 const double coordfrac(atan2(v.x(),v.y()));
187 if (coordfrac>0.2 || coordfrac < -0.2)
189 ATH_MSG_WARNING (
"Found barrel straw where the assumption that local y-direction"
190 <<
" is along the straw is NOT valid."
191 <<
" Drift times will be somewhat off." );
205 const double& timeOfHit,
206 const double& prex,
const double& prey,
const double& prez,
207 const double& postx,
const double& posty,
const double& postz,
208 std::vector<cluster>& clusterlist,
int strawGasType,
209 CLHEP::HepRandomEngine* rndmEngine,
210 CLHEP::HepRandomEngine* paiRndmEngine)
216 else if (strawGasType==1) { activePAITool =
m_pPAItoolKr; }
217 else if (strawGasType==2) { activePAITool =
m_pPAItoolAr; }
221 const double deltaX(postx - prex);
222 const double deltaY(posty - prey);
223 const double deltaZ(postz - prez);
224 const double stepLength(sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ));
226 const double meanFreePath(activePAITool->
GetMeanFreePath( scaledKineticEnergy, particleCharge*particleCharge ));
229 const unsigned int numberOfClusters(CLHEP::RandPoisson::shoot(rndmEngine,stepLength / meanFreePath));
233 for (
unsigned int iclus(0); iclus<numberOfClusters; ++iclus)
236 const double lambda(CLHEP::RandFlat::shoot(rndmEngine));
239 double clusE(activePAITool->
GetEnergyTransfer(scaledKineticEnergy, paiRndmEngine));
240 clusterlist.emplace_back(clusE, timeOfHit,
241 prex + lambda * deltaX,
242 prey + lambda * deltaY,
243 prez + lambda * deltaZ);
254 bool & alreadyPrintedPDGcodeWarning,
255 double cosmicEventPhase,
257 bool emulationArflag,
258 bool emulationKrflag,
259 CLHEP::HepRandomEngine* rndmEngine,
260 CLHEP::HepRandomEngine* elecProcRndmEngine,
261 CLHEP::HepRandomEngine* elecNoiseRndmEngine,
262 CLHEP::HepRandomEngine* paiRndmEngine)
268 const int hitID((*i)->GetHitID());
270 const bool isBarrel(region<3 );
274 const bool isECA (region==3);
275 const bool isECB (region==4);
310 double timeOfHit(0.0);
312 const double globalHitTime(
hitTime(*theHit));
313 const double globalTime =
static_cast<double>((*theHit)->GetGlobalTime());
314 const double bunchCrossingTime(globalHitTime - globalTime);
322 const int particleEncoding((*theHit)->GetParticleEncoding());
325 if (particleEncoding == 0)
333 ATH_MSG_WARNING (
"Ignoring sim. particle with pdgcode 0. This warning is only shown once per job" );
342 const double energyDeposit = (*theHit)->GetEnergyDeposit();
348 if ( energyDeposit<30.0 ) {
352 double ArEmulationScaling_BA = 0.05;
353 double ArEmulationScaling_ECA = 0.20;
354 double ArEmulationScaling_ECB = 0.20;
357 double KrEmulationScaling_BA = 0.20;
358 double KrEmulationScaling_ECA = 0.39;
359 double KrEmulationScaling_ECB = 0.39;
362 double trEfficiencyBarrel =
m_settings->trEfficiencyBarrel(strawGasType);
363 double hitx = TRThitGlobalPos[0];
364 double hity = TRThitGlobalPos[1];
365 double hitz = TRThitGlobalPos[2];
366 double hitEta = std::abs(log(tan(0.5*atan2(sqrt(hitx*hitx+hity*hity),hitz))));
367 if ( hitEta < 0.5 ) { trEfficiencyBarrel *= ( 0.833333+0.6666667*hitEta*hitEta ); }
369 if ( strawGasType == 0 && emulationArflag ) { trEfficiencyBarrel *= ArEmulationScaling_BA; }
370 if ( strawGasType == 0 && emulationKrflag ) { trEfficiencyBarrel *= KrEmulationScaling_BA; }
371 if ( CLHEP::RandFlat::shoot(rndmEngine) > trEfficiencyBarrel )
continue;
375 double trEfficiencyEndCapA =
m_settings->trEfficiencyEndCapA(strawGasType);
377 if ( strawGasType == 0 && emulationArflag ) { trEfficiencyEndCapA *= ArEmulationScaling_ECA; }
378 if ( strawGasType == 0 && emulationKrflag ) { trEfficiencyEndCapA *= KrEmulationScaling_ECA; }
379 if ( CLHEP::RandFlat::shoot(rndmEngine) > trEfficiencyEndCapA )
continue;
382 double trEfficiencyEndCapB =
m_settings->trEfficiencyEndCapB(strawGasType);
384 if ( strawGasType == 0 && emulationArflag ) { trEfficiencyEndCapB *= ArEmulationScaling_ECB; }
385 if ( strawGasType == 0 && emulationKrflag ) { trEfficiencyEndCapB *= KrEmulationScaling_ECB; }
386 if ( CLHEP::RandFlat::shoot(rndmEngine) > trEfficiencyEndCapB )
continue;
392 m_clusterlist.emplace_back( energyDeposit*CLHEP::keV, timeOfHit, (*theHit)->GetPostStepX(), (*theHit)->GetPostStepY(), (*theHit)->GetPostStepZ() );
401 m_clusterlist.emplace_back( (*theHit)->GetEnergyDeposit()*CLHEP::keV, timeOfHit, (*theHit)->GetPostStepX(), (*theHit)->GetPostStepY(), (*theHit)->GetPostStepZ() );
406 const HepPDT::ParticleData *particle(
m_pParticleTable->particle(HepPDT::ParticleID(abs(particleEncoding))));
407 double particleCharge(0.);
408 double particleMass(0.);
411 particleCharge = particle->charge();
412 particleMass = particle->mass().value();
421 ATH_MSG_WARNING (
"Data for sim. particle with pdgcode "<<particleEncoding
422 <<
" is not a nucleus and could not be retrieved from PartPropSvc. Assuming mass and charge as pion. Please investigate." );
427 particleCharge =
MC::charge(particleEncoding);
433 particleMass = std::abs( Z*Mp+(
A-Z)*Mn );
435 if (!alreadyPrintedPDGcodeWarning) {
436 ATH_MSG_WARNING (
"Data for sim. particle with pdgcode "<<particleEncoding
437 <<
" could not be retrieved from PartPropSvc (unexpected ion)."
438 <<
" Please Investigate the PDGTABLE.MeV file."
439 <<
" Calculating mass and charge from pdg code."
440 <<
" The result is: Charge = "<<particleCharge<<
" Mass = "<<particleMass<<
"MeV" );
441 alreadyPrintedPDGcodeWarning =
true;
446 if (!particleCharge) {
continue; }
449 ATH_MSG_WARNING (
"Ignoring ionization from particle with pdg code "<<particleEncoding
450 <<
" since it appears to be a massless charged particle. Please investigate." );
458 const double scaledKineticEnergy(
static_cast<double>((*theHit)->GetKineticEnergy()) * ( CLHEP::proton_mass_c2 / particleMass ));
461 (*theHit)->GetPreStepX(),(*theHit)->GetPreStepY(),(*theHit)->GetPreStepZ(),
462 (*theHit)->GetPostStepX(),(*theHit)->GetPostStepY(),(*theHit)->GetPostStepZ(),
508 double lowthreshold, noiseamplitude;
512 lowthreshold = isBarrel ?
m_settings->lowThresholdBar(strawGasType) :
m_settings->lowThresholdEC(strawGasType);
513 noiseamplitude = 0.0;
522 const std::vector<cluster>& clusters,
523 std::vector<TRTElectronicsProcessing::Deposit>& deposits,
525 double cosmicEventPhase,
527 CLHEP::HepRandomEngine* rndmEngine)
537 const bool isBarrel(region<3 );
538 const bool isEC (!isBarrel);
539 const bool isShort (region==1);
540 const bool isLong (region==2);
550 double ionisationPotential =
m_settings->ionisationPotential(strawGasType);
551 double smearingFactor =
m_settings->smearingFactor(strawGasType);
553 std::vector<cluster>::const_iterator currentClusterIter(clusters.begin());
554 const std::vector<cluster>::const_iterator endOfClusterList(clusters.end());
566 double map_x2(0.),map_y2(0.),map_z2(0.);
567 double effectiveField2(0.);
572 globalPosition[0]=TRThitGlobalPos[0]*CLHEP::mm;
573 globalPosition[1]=TRThitGlobalPos[1]*CLHEP::mm;
574 globalPosition[2]=TRThitGlobalPos[2]*CLHEP::mm;
577 fieldCache.
getField (globalPosition.data(), mField.data());
579 map_x2 = mField.x()*mField.x();
580 map_y2 = mField.y()*mField.y();
581 map_z2 = mField.z()*mField.z();
608 for (;currentClusterIter!=endOfClusterList;++currentClusterIter)
611 const double cluster_x(currentClusterIter->xpos);
612 const double cluster_y(currentClusterIter->ypos);
613 const double cluster_z(this->
setClusterZ(currentClusterIter->zpos, isLong, isShort, isEC));
614 const double cluster_x2(cluster_x*cluster_x);
615 const double cluster_y2(cluster_y*cluster_y);
616 double cluster_r2(cluster_x2+cluster_y2);
619 if (cluster_r2<wire_r2) cluster_r2=wire_r2;
620 if (cluster_r2>straw_r2) cluster_r2=straw_r2;
622 const double cluster_r(std::sqrt(cluster_r2));
623 const double cluster_E(currentClusterIter->energy);
624 const unsigned int nprimaryelectrons(
static_cast<unsigned int>( cluster_E / ionisationPotential + 1.0 ) );
629 double depositEnergy(0.);
633 unsigned int nsurvivingprimaryelectrons =
static_cast<unsigned int>(randBinomial->
fire(rndmEngine,nprimaryelectrons) + 0.5);
634 if (nsurvivingprimaryelectrons==0)
continue;
635 const double meanElectronEnergy(ionisationPotential / smearingFactor);
636 for (
unsigned int ielec(0); ielec<nsurvivingprimaryelectrons; ++ielec) {
637 depositEnergy += CLHEP::RandExpZiggurat::shoot(rndmEngine, meanElectronEnergy);
642 const double fluctSigma(sqrt(cluster_E * ionisationPotential * (2 - smearingFactor) / smearingFactor));
644 depositEnergy = CLHEP::RandGaussZiggurat::shoot(rndmEngine, cluster_E, fluctSigma);
645 }
while(depositEnergy<0.0);
660 effectiveField2 = map_z2*cluster_y2/cluster_r2 + map_x2 + map_y2;
669 effectiveField2 = map_z2 + (map_x2+map_y2)*cluster_y2/cluster_r2;
685 double clusterTime(currentClusterIter->time);
690 clusterTime = clusterTime + cosmicEventPhase +
m_settings->jitterTimeOffset()*( CLHEP::RandFlat::shoot(rndmEngine) );
695 double timedirect(0.), timereflect(0.);
699 double expdirect(1.0), expreflect(1.0);
713 const unsigned int kdirect =
static_cast<unsigned int>(distdirect/10);
714 const unsigned int kreflect =
static_cast<unsigned int>(distreflect/10);
720 double commondrifttime =
m_pSimDriftTimeTool->getAverageDriftTime(cluster_r,effectiveField2,strawGasType);
721 double dt = clusterTime + commondrifttime;
722 deposits.emplace_back(0.5*depositEnergy*expdirect, timedirect+dt);
723 deposits.emplace_back(0.5*depositEnergy*expreflect, timereflect+dt);
732 const int mask(0x0000001F);
734 int trtID, ringID, moduleID, layerID, strawID;
735 int wheelID, planeID, sectorID;
740 if ( !(hitID & 0x00200000) ) {
742 strawID = hitID & mask;
743 hitID >>= word_shift;
744 layerID = hitID & mask;
745 hitID >>= word_shift;
746 moduleID = hitID & mask;
747 hitID >>= word_shift;
748 ringID = hitID & mask;
749 trtID = hitID >> word_shift;
751 barrelElement =
m_detmgr->getBarrelElement(trtID, ringID, moduleID, layerID);
754 const Amg::Vector3D v( (*theHit)->GetPreStepX(),(*theHit)->GetPreStepY(),(*theHit)->GetPreStepZ());
760 strawID = hitID & mask;
761 hitID >>= word_shift;
762 planeID = hitID & mask;
763 hitID >>= word_shift;
764 sectorID = hitID & mask;
765 hitID >>= word_shift;
766 wheelID = hitID & mask;
767 trtID = hitID >> word_shift;
770 if (trtID == 3) trtID = 0;
773 endcapElement =
m_detmgr->getEndcapElement(trtID, wheelID, planeID, sectorID);
775 if ( endcapElement ) {
776 const Amg::Vector3D v( (*theHit)->GetPreStepX(),(*theHit)->GetPreStepY(),(*theHit)->GetPreStepZ());
782 ATH_MSG_WARNING (
"Could not find global coordinate of a straw - drifttime calculation will be inaccurate" );
783 return {0.0,0.0,0.0};
789 double cluster_z(cluster_z_in);
794 const double longBarrelStrawHalfLength(349.315*CLHEP::mm);
795 const double shortBarrelStrawHalfLength(153.375*CLHEP::mm);
796 const double EndcapStrawHalfLength(177.150*CLHEP::mm);
797 if ( isLong && std::abs(cluster_z)>longBarrelStrawHalfLength+30 ) {
798 double d = cluster_z<0 ? cluster_z+longBarrelStrawHalfLength : cluster_z-longBarrelStrawHalfLength;
799 ATH_MSG_WARNING (
"Long barrel straw cluster is outside the active gas volume z = +- 349.315 mm by " << d <<
" mm.");
803 if ( isShort && std::abs(cluster_z)>shortBarrelStrawHalfLength+30 ) {
804 double d = cluster_z<0 ? cluster_z+shortBarrelStrawHalfLength : cluster_z-shortBarrelStrawHalfLength;
805 ATH_MSG_WARNING (
"Short barrel straw cluster is outside the active gas volume z = +- 153.375 mm by " << d <<
" mm.");
809 if ( isEC && std::abs(cluster_z)>EndcapStrawHalfLength+30 ) {
810 double d = cluster_z<0 ? cluster_z+EndcapStrawHalfLength : cluster_z-EndcapStrawHalfLength;
811 ATH_MSG_WARNING (
"End cap straw cluster is outside the active gas volume z = +- 177.150 mm by " << d <<
" mm.");
float hitTime(const AFP_SIDSimHit &hit)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
ATLAS-specific HepMC functions.
A number of constexpr particle constants to avoid hardcoding them directly in various places.
This is an Identifier helper class for the TRT subdetector.
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
Extended TRT_BaseElement to describe a TRT readout element, this is a planar layer with n ( order of ...
const Amg::Transform3D & strawTransform(unsigned int straw) const
Straw transform - fast access in array, in Tracking frame: Amg.
The Detector Manager for all TRT Detector elements, it acts as the interface to the detector elements...
Extended class of a TRT_BaseElement to describe a readout elment in the endcap.
Helper class to organize the straw elements on TRT readout elements.
Local cache for magnetic field (based on MagFieldServices/AtlasFieldSvcTLS.h)
void getField(const double *ATH_RESTRICT xyz, double *ATH_RESTRICT bxyz, double *ATH_RESTRICT deriv=nullptr)
get B field value at given position xyz[3] is in mm, bxyz[3] is in kT if deriv[9] is given,...
Communication with CondDB.
Class containing parameters and settings used by TRT digitization.
Simulation of noise hits in the TRT.
std::unique_ptr< CLHEP::RandBinomialFixedP > m_randBinomialXe
const HepPDT::ParticleDataTable * m_pParticleTable
TRTProcessingOfStraw(const TRTDigSettings *, const InDetDD::TRT_DetectorManager *, ITRT_PAITool *, ITRT_SimDriftTimeTool *, TRTElectronicsProcessing *ep, TRTNoise *noise, TRTDigCondBase *digcond, const HepPDT::ParticleDataTable *, const TRT_ID *, ITRT_PAITool *=nullptr, ITRT_PAITool *=nullptr, const ITRT_CalDbTool *=nullptr)
Constructor: Calls Initialize method.
TRTDigCondBase * m_pDigConditions
std::unique_ptr< CLHEP::RandBinomialFixedP > m_randBinomialKr
std::vector< cluster > m_clusterlist
double m_innerRadiusOfStraw
unsigned int m_maxelectrons
void ClustersToDeposits(MagField::AtlasFieldCache &fieldCache, const int &hitID, const std::vector< cluster > &clusters, std::vector< TRTElectronicsProcessing::Deposit > &deposits, Amg::Vector3D TRThitGlobalPos, double m_cosmicEventPhase, int strawGasType, CLHEP::HepRandomEngine *rndmEngine)
Transform the ioniation clusters along the particle trajectory inside a straw to energy deposits (i....
std::unique_ptr< CLHEP::RandBinomialFixedP > m_randBinomialAr
TRTElectronicsProcessing * m_pElectronicsProcessing
void addClustersFromStep(const double &scaledKineticEnergy, const double &particleCharge, const double &timeOfHit, const double &prex, const double &prey, const double &prez, const double &postx, const double &posty, const double &postz, std::vector< cluster > &clusterlist, int strawGasType, CLHEP::HepRandomEngine *rndmEngine, CLHEP::HepRandomEngine *paiRndmEngine)
This is the main function for re-simulation of the ionisation in the active gas via the PAI model.
Amg::Vector3D getGlobalPosition(int hitID, const TimedHitPtr< TRTUncompressedHit > *theHit)
void Initialize(const ITRT_CalDbTool *)
Initialize.
std::vector< TRTElectronicsProcessing::Deposit > m_depositList
std::vector< double > m_expattenuation
bool m_timeCorrection
Time to be corrected for flight and wire propagation delays false when beamType='cosmics'.
double m_shiftOfZeroPoint
double m_signalPropagationSpeed
ITRT_PAITool * m_pPAItoolXe
ITRT_PAITool * m_pPAItoolKr
TimedHitCollection< TRTUncompressedHit >::const_iterator hitCollConstIter
bool m_useMagneticFieldMap
const TRT_ID * m_id_helper
bool m_alreadywarnedagainstpdg0
void ProcessStraw(MagField::AtlasFieldCache &fieldCache, hitCollConstIter i, hitCollConstIter e, TRTDigit &outdigit, bool &m_alreadyPrintedPDGcodeWarning, double m_cosmicEventPhase, int strawGasType, bool emulationArflag, bool emulationKrflag, CLHEP::HepRandomEngine *rndmEngine, CLHEP::HepRandomEngine *elecProcRndmEngine, CLHEP::HepRandomEngine *elecNoiseRndmEngine, CLHEP::HepRandomEngine *paiRndmEngine)
Process this straw all the way from Geant4 hit to output digit.
ITRT_PAITool * m_pPAItoolAr
double m_attenuationLength
double m_solenoidFieldStrength
~TRTProcessingOfStraw()
Destructor.
double m_outerRadiusOfWire
TRTTimeCorrection * m_pTimeCorrection
const TRTDigSettings * m_settings
ITRT_SimDriftTimeTool * m_pSimDriftTimeTool
const InDetDD::TRT_DetectorManager * m_detmgr
double setClusterZ(double cluster_z_in, bool isLong, bool isShort, bool isEC) const
This is an Identifier helper class for the TRT subdetector.
a smart pointer to a hit that also provides access to the extended timing info of the host event.
Eigen::Matrix< double, 3, 1 > Vector3D
int numberOfProtons(const T &p)
bool isGenericMultichargedParticle(const T &p)
In addition, there is a need to identify ”Q-ball” and similar very exotic (multi-charged) particles w...
bool isPhoton(const T &p)
bool isMonopole(const T &p)
PDG rule 11i Magnetic monopoles and dyons are assumed to have one unit of Dirac monopole charge and a...
double charge(const T &p)
bool isNucleus(const T &p)
PDG rule 16 Nuclear codes are given as 10-digit numbers ±10LZZZAAAI.
double baryonNumber(const T &p)
constexpr double protonMassInMeV
the mass of the proton (in MeV)
constexpr double chargedPionMassInMeV
the mass of the charged pion (in MeV)
constexpr double neutronMassInMeV
the mass of the neutron (in MeV)
unsigned int getRegion(int hitID)
hold the test vectors and ease the comparison