30#include "CLHEP/Units/SystemOfUnits.h"
31#include "CLHEP/Units/PhysicalConstants.h"
34#include "HepPDT/ParticleData.hh"
39#include "CLHEP/Random/RandPoisson.h"
40#include "CLHEP/Random/RandFlat.h"
41#include "CLHEP/Random/RandBinomial.h"
42#include "CLHEP/Random/RandExpZiggurat.h"
43#include "CLHEP/Random/RandGaussZiggurat.h"
56 const HepPDT::ParticleDataTable* pdt,
105 ATH_MSG_FATAL (
"TRT_PAITool for Xenon not defined! no point in continuing!" );
108 ATH_MSG_ERROR (
"TRT_PAITool for Krypton is not defined!!! Xenon TRT_PAITool will be used for Krypton straws!" );
112 ATH_MSG_ERROR (
"TRT_PAITool for Argon is not defined!!! Xenon TRT_PAITool will be used for Argon straws!" );
122 const double intervalBetweenCrossings(
m_settings->timeInterval() / 3.);
130 for (
unsigned int k=0; k<150; k++) {
131 double dist = 10.0*(k+0.5);
142 for (
unsigned int iwheel = 0; iwheel < num->getNEndcapWheels(); ++iwheel)
144 for (
unsigned int iside = 0; iside < 2; ++iside)
146 for (
unsigned int ilayer = 0; ilayer < num->getNEndcapLayers(iwheel); ++ilayer)
156 ATH_MSG_VERBOSE (
"Failed to retrieve endcap element for (iside,iwheel,ilayer)=("
157 << iside<<
", "<<iwheel<<
", "<<ilayer<<
")." );
166 const double zcoordfrac((v.z()>0?v.z():-v.z())/v.mag());
167 if (zcoordfrac<0.98 || zcoordfrac > 1.02)
169 ATH_MSG_WARNING (
"Found endcap straw where the assumption that local x-direction"
170 <<
" is parallel to global z-direction is NOT valid."
171 <<
" Drift times will be somewhat off." );
178 for (
unsigned int phi_it = 0; phi_it < 32; phi_it++)
187 const double coordfrac(atan2(v.x(),v.y()));
188 if (coordfrac>0.2 || coordfrac < -0.2)
190 ATH_MSG_WARNING (
"Found barrel straw where the assumption that local y-direction"
191 <<
" is along the straw is NOT valid."
192 <<
" Drift times will be somewhat off." );
206 const double& timeOfHit,
207 const double& prex,
const double& prey,
const double& prez,
208 const double& postx,
const double& posty,
const double& postz,
209 std::vector<cluster>& clusterlist,
int strawGasType,
210 CLHEP::HepRandomEngine* rndmEngine,
211 CLHEP::HepRandomEngine* paiRndmEngine)
217 else if (strawGasType==1) { activePAITool =
m_pPAItoolKr; }
218 else if (strawGasType==2) { activePAITool =
m_pPAItoolAr; }
222 const double deltaX(postx - prex);
223 const double deltaY(posty - prey);
224 const double deltaZ(postz - prez);
225 const double stepLength(sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ));
227 const double meanFreePath(activePAITool->
GetMeanFreePath( scaledKineticEnergy, particleCharge*particleCharge ));
230 const unsigned int numberOfClusters(CLHEP::RandPoisson::shoot(rndmEngine,stepLength / meanFreePath));
234 for (
unsigned int iclus(0); iclus<numberOfClusters; ++iclus)
237 const double lambda(CLHEP::RandFlat::shoot(rndmEngine));
240 double clusE(activePAITool->
GetEnergyTransfer(scaledKineticEnergy, paiRndmEngine));
241 clusterlist.emplace_back(clusE, timeOfHit,
242 prex + lambda * deltaX,
243 prey + lambda * deltaY,
244 prez + lambda * deltaZ);
256 bool & alreadyPrintedPDGcodeWarning,
257 double cosmicEventPhase,
259 bool emulationArflag,
260 bool emulationKrflag,
261 CLHEP::HepRandomEngine* rndmEngine,
262 CLHEP::HepRandomEngine* elecProcRndmEngine,
263 CLHEP::HepRandomEngine* elecNoiseRndmEngine,
264 CLHEP::HepRandomEngine* paiRndmEngine)
270 const int hitID((*i)->GetHitID());
272 const bool isBarrel(region<3 );
276 const bool isECA (region==3);
277 const bool isECB (region==4);
312 double timeOfHit(0.0);
314 const double globalHitTime(
hitTime(*theHit));
315 const double globalTime =
static_cast<double>((*theHit)->GetGlobalTime());
316 const double bunchCrossingTime(globalHitTime - globalTime);
324 const int particleEncoding((*theHit)->GetParticleEncoding());
327 if (particleEncoding == 0)
335 ATH_MSG_WARNING (
"Ignoring sim. particle with pdgcode 0. This warning is only shown once per job" );
344 const double energyDeposit = (*theHit)->GetEnergyDeposit();
350 if ( energyDeposit<30.0 ) {
354 double ArEmulationScaling_BA = 0.05;
355 double ArEmulationScaling_ECA = 0.20;
356 double ArEmulationScaling_ECB = 0.20;
359 double KrEmulationScaling_BA = 0.20;
360 double KrEmulationScaling_ECA = 0.39;
361 double KrEmulationScaling_ECB = 0.39;
364 double trEfficiencyBarrel =
m_settings->trEfficiencyBarrel(strawGasType);
365 double hitx = TRThitGlobalPos[0];
366 double hity = TRThitGlobalPos[1];
367 double hitz = TRThitGlobalPos[2];
368 double hitEta = std::abs(log(tan(0.5*atan2(sqrt(hitx*hitx+hity*hity),hitz))));
369 if ( hitEta < 0.5 ) { trEfficiencyBarrel *= ( 0.833333+0.6666667*hitEta*hitEta ); }
371 if ( strawGasType == 0 && emulationArflag ) { trEfficiencyBarrel *= ArEmulationScaling_BA; }
372 if ( strawGasType == 0 && emulationKrflag ) { trEfficiencyBarrel *= KrEmulationScaling_BA; }
373 if ( CLHEP::RandFlat::shoot(rndmEngine) > trEfficiencyBarrel )
continue;
377 double trEfficiencyEndCapA =
m_settings->trEfficiencyEndCapA(strawGasType);
379 if ( strawGasType == 0 && emulationArflag ) { trEfficiencyEndCapA *= ArEmulationScaling_ECA; }
380 if ( strawGasType == 0 && emulationKrflag ) { trEfficiencyEndCapA *= KrEmulationScaling_ECA; }
381 if ( CLHEP::RandFlat::shoot(rndmEngine) > trEfficiencyEndCapA )
continue;
384 double trEfficiencyEndCapB =
m_settings->trEfficiencyEndCapB(strawGasType);
386 if ( strawGasType == 0 && emulationArflag ) { trEfficiencyEndCapB *= ArEmulationScaling_ECB; }
387 if ( strawGasType == 0 && emulationKrflag ) { trEfficiencyEndCapB *= KrEmulationScaling_ECB; }
388 if ( CLHEP::RandFlat::shoot(rndmEngine) > trEfficiencyEndCapB )
continue;
394 m_clusterlist.emplace_back( energyDeposit*CLHEP::keV, timeOfHit, (*theHit)->GetPostStepX(), (*theHit)->GetPostStepY(), (*theHit)->GetPostStepZ() );
403 m_clusterlist.emplace_back( (*theHit)->GetEnergyDeposit()*CLHEP::keV, timeOfHit, (*theHit)->GetPostStepX(), (*theHit)->GetPostStepY(), (*theHit)->GetPostStepZ() );
408 const HepPDT::ParticleData *particle(
m_pParticleTable->particle(HepPDT::ParticleID(abs(particleEncoding))));
409 double particleCharge(0.);
410 double particleMass(0.);
413 particleCharge = particle->charge();
414 particleMass = particle->mass().value();
423 ATH_MSG_WARNING (
"Data for sim. particle with pdgcode "<<particleEncoding
424 <<
" is not a nucleus and could not be retrieved from PartPropSvc. Assuming mass and charge as pion. Please investigate." );
429 particleCharge =
MC::charge(particleEncoding);
435 particleMass = std::abs( Z*Mp+(
A-Z)*Mn );
437 if (!alreadyPrintedPDGcodeWarning) {
438 ATH_MSG_WARNING (
"Data for sim. particle with pdgcode "<<particleEncoding
439 <<
" could not be retrieved from PartPropSvc (unexpected ion)."
440 <<
" Please Investigate the PDGTABLE.MeV file."
441 <<
" Calculating mass and charge from pdg code."
442 <<
" The result is: Charge = "<<particleCharge<<
" Mass = "<<particleMass<<
"MeV" );
443 alreadyPrintedPDGcodeWarning =
true;
448 if (!particleCharge) {
continue; }
451 ATH_MSG_WARNING (
"Ignoring ionization from particle with pdg code "<<particleEncoding
452 <<
" since it appears to be a massless charged particle. Please investigate." );
460 const double scaledKineticEnergy(
static_cast<double>((*theHit)->GetKineticEnergy()) * ( CLHEP::proton_mass_c2 / particleMass ));
463 (*theHit)->GetPreStepX(),(*theHit)->GetPreStepY(),(*theHit)->GetPreStepZ(),
464 (*theHit)->GetPostStepX(),(*theHit)->GetPostStepY(),(*theHit)->GetPostStepZ(),
510 double lowthreshold, noiseamplitude;
514 lowthreshold = isBarrel ?
m_settings->lowThresholdBar(strawGasType) :
m_settings->lowThresholdEC(strawGasType);
515 noiseamplitude = 0.0;
524 const std::vector<cluster>& clusters,
525 std::vector<TRTElectronicsProcessing::Deposit>& deposits,
527 double cosmicEventPhase,
529 CLHEP::HepRandomEngine* rndmEngine)
539 const bool isBarrel(region<3 );
540 const bool isEC (!isBarrel);
541 const bool isShort (region==1);
542 const bool isLong (region==2);
552 double ionisationPotential =
m_settings->ionisationPotential(strawGasType);
553 double smearingFactor =
m_settings->smearingFactor(strawGasType);
555 std::vector<cluster>::const_iterator currentClusterIter(clusters.begin());
556 const std::vector<cluster>::const_iterator endOfClusterList(clusters.end());
568 double map_x2(0.),map_y2(0.),map_z2(0.);
569 double effectiveField2(0.);
574 globalPosition[0]=TRThitGlobalPos[0]*CLHEP::mm;
575 globalPosition[1]=TRThitGlobalPos[1]*CLHEP::mm;
576 globalPosition[2]=TRThitGlobalPos[2]*CLHEP::mm;
579 fieldCache.
getField (globalPosition.data(), mField.data());
581 map_x2 = mField.x()*mField.x();
582 map_y2 = mField.y()*mField.y();
583 map_z2 = mField.z()*mField.z();
610 for (;currentClusterIter!=endOfClusterList;++currentClusterIter)
613 const double cluster_x(currentClusterIter->xpos);
614 const double cluster_y(currentClusterIter->ypos);
615 const double cluster_z(this->
setClusterZ(currentClusterIter->zpos, isLong, isShort, isEC));
616 const double cluster_x2(cluster_x*cluster_x);
617 const double cluster_y2(cluster_y*cluster_y);
618 double cluster_r2(cluster_x2+cluster_y2);
621 if (cluster_r2<wire_r2) cluster_r2=wire_r2;
622 if (cluster_r2>straw_r2) cluster_r2=straw_r2;
624 const double cluster_r(std::sqrt(cluster_r2));
625 const double cluster_E(currentClusterIter->energy);
626 const unsigned int nprimaryelectrons(
static_cast<unsigned int>( cluster_E / ionisationPotential + 1.0 ) );
631 double depositEnergy(0.);
635 unsigned int nsurvivingprimaryelectrons =
static_cast<unsigned int>(randBinomial->
fire(rndmEngine,nprimaryelectrons) + 0.5);
636 if (nsurvivingprimaryelectrons==0)
continue;
637 const double meanElectronEnergy(ionisationPotential / smearingFactor);
638 for (
unsigned int ielec(0); ielec<nsurvivingprimaryelectrons; ++ielec) {
639 depositEnergy += CLHEP::RandExpZiggurat::shoot(rndmEngine, meanElectronEnergy);
644 const double fluctSigma(sqrt(cluster_E * ionisationPotential * (2 - smearingFactor) / smearingFactor));
646 depositEnergy = CLHEP::RandGaussZiggurat::shoot(rndmEngine, cluster_E, fluctSigma);
647 }
while(depositEnergy<0.0);
662 effectiveField2 = map_z2*cluster_y2/cluster_r2 + map_x2 + map_y2;
671 effectiveField2 = map_z2 + (map_x2+map_y2)*cluster_y2/cluster_r2;
687 double clusterTime(currentClusterIter->time);
692 clusterTime = clusterTime + cosmicEventPhase +
m_settings->jitterTimeOffset()*( CLHEP::RandFlat::shoot(rndmEngine) );
697 double timedirect(0.), timereflect(0.);
701 double expdirect(1.0), expreflect(1.0);
717 const unsigned int kdirect =
static_cast<unsigned int>(std::max(distdirect,0.0)/10);
718 const unsigned int kreflect =
static_cast<unsigned int>(distreflect/10);
724 double commondrifttime =
m_pSimDriftTimeTool->getAverageDriftTime(cluster_r,effectiveField2,strawGasType);
725 double dt = clusterTime + commondrifttime;
726 deposits.emplace_back(0.5*depositEnergy*expdirect, timedirect+dt);
727 deposits.emplace_back(0.5*depositEnergy*expreflect, timereflect+dt);
739 const int mask(0x0000001F);
741 int trtID, ringID, moduleID, layerID, strawID;
742 int wheelID, planeID, sectorID;
747 if ( !(hitID & 0x00200000) ) {
749 strawID = hitID & mask;
750 hitID >>= word_shift;
751 layerID = hitID & mask;
752 hitID >>= word_shift;
753 moduleID = hitID & mask;
754 hitID >>= word_shift;
755 ringID = hitID & mask;
756 trtID = hitID >> word_shift;
761 const Amg::Vector3D v( (*theHit)->GetPreStepX(),(*theHit)->GetPreStepY(),(*theHit)->GetPreStepZ());
767 strawID = hitID & mask;
768 hitID >>= word_shift;
769 planeID = hitID & mask;
770 hitID >>= word_shift;
771 sectorID = hitID & mask;
772 hitID >>= word_shift;
773 wheelID = hitID & mask;
774 trtID = hitID >> word_shift;
777 if (trtID == 3) trtID = 0;
782 if ( endcapElement ) {
783 const Amg::Vector3D v( (*theHit)->GetPreStepX(),(*theHit)->GetPreStepY(),(*theHit)->GetPreStepZ());
789 ATH_MSG_WARNING (
"Could not find global coordinate of a straw - drifttime calculation will be inaccurate" );
790 return {0.0,0.0,0.0};
796 double cluster_z(cluster_z_in);
801 const double longBarrelStrawHalfLength(349.315*CLHEP::mm);
802 const double shortBarrelStrawHalfLength(153.375*CLHEP::mm);
803 const double EndcapStrawHalfLength(177.150*CLHEP::mm);
804 if ( isLong && std::abs(cluster_z)>longBarrelStrawHalfLength+30 ) {
805 double d = cluster_z<0 ? cluster_z+longBarrelStrawHalfLength : cluster_z-longBarrelStrawHalfLength;
806 ATH_MSG_WARNING (
"Long barrel straw cluster is outside the active gas volume z = +- 349.315 mm by " << d <<
" mm.");
810 if ( isShort && std::abs(cluster_z)>shortBarrelStrawHalfLength+30 ) {
811 double d = cluster_z<0 ? cluster_z+shortBarrelStrawHalfLength : cluster_z-shortBarrelStrawHalfLength;
812 ATH_MSG_WARNING (
"Short barrel straw cluster is outside the active gas volume z = +- 153.375 mm by " << d <<
" mm.");
816 if ( isEC && std::abs(cluster_z)>EndcapStrawHalfLength+30 ) {
817 double d = cluster_z<0 ? cluster_z+EndcapStrawHalfLength : cluster_z-EndcapStrawHalfLength;
818 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.
Class to hold different TRT detector elements structures.
const TRT_EndcapElement * getEndcapDetElement(unsigned int positive, unsigned int wheelIndex, unsigned int strawLayerIndex, unsigned int phiIndex) const
const TRT_BarrelElement * getBarrelDetElement(unsigned int positive, unsigned int moduleIndex, unsigned int phiIndex, unsigned int strawLayerIndex) const
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.
Amg::Vector3D getGlobalPosition(int hitID, const TimedHitPtr< TRTUncompressedHit > *theHit, const InDetDD::TRT_DetElementContainer *detElements)
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.
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
ITRT_PAITool * m_pPAItoolAr
double m_attenuationLength
double m_solenoidFieldStrength
void ProcessStraw(MagField::AtlasFieldCache &fieldCache, const InDetDD::TRT_DetElementContainer *detElements, 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.
~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