30#include "CLHEP/Units/SystemOfUnits.h"
31#include "CLHEP/Units/PhysicalConstants.h"
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"
103 ATH_MSG_FATAL (
"TRT_PAITool for Xenon not defined! no point in continuing!" );
106 ATH_MSG_ERROR (
"TRT_PAITool for Krypton is not defined!!! Xenon TRT_PAITool will be used for Krypton straws!" );
110 ATH_MSG_ERROR (
"TRT_PAITool for Argon is not defined!!! Xenon TRT_PAITool will be used for Argon straws!" );
120 const double intervalBetweenCrossings(
m_settings->timeInterval() / 3.);
128 for (
unsigned int k=0; k<150; k++) {
129 double dist = 10.0*(k+0.5);
140 for (
unsigned int iwheel = 0; iwheel < num->getNEndcapWheels(); ++iwheel)
142 for (
unsigned int iside = 0; iside < 2; ++iside)
144 for (
unsigned int ilayer = 0; ilayer < num->getNEndcapLayers(iwheel); ++ilayer)
154 ATH_MSG_VERBOSE (
"Failed to retrieve endcap element for (iside,iwheel,ilayer)=("
155 << iside<<
", "<<iwheel<<
", "<<ilayer<<
")." );
164 const double zcoordfrac((v.z()>0?v.z():-v.z())/v.mag());
165 if (zcoordfrac<0.98 || zcoordfrac > 1.02)
167 ATH_MSG_WARNING (
"Found endcap straw where the assumption that local x-direction"
168 <<
" is parallel to global z-direction is NOT valid."
169 <<
" Drift times will be somewhat off." );
176 for (
unsigned int phi_it = 0; phi_it < 32; phi_it++)
185 const double coordfrac(atan2(v.x(),v.y()));
186 if (coordfrac>0.2 || coordfrac < -0.2)
188 ATH_MSG_WARNING (
"Found barrel straw where the assumption that local y-direction"
189 <<
" is along the straw is NOT valid."
190 <<
" Drift times will be somewhat off." );
205 double prex,
double prey,
double prez,
206 double postx,
double posty,
double postz,
207 std::vector<cluster>& clusterlist,
int strawGasType,
208 CLHEP::HepRandomEngine* rndmEngine,
209 CLHEP::HepRandomEngine* paiRndmEngine)
215 else if (strawGasType==1) { activePAITool =
m_pPAItoolKr; }
216 else if (strawGasType==2) { activePAITool =
m_pPAItoolAr; }
220 const double deltaX(postx - prex);
221 const double deltaY(posty - prey);
222 const double deltaZ(postz - prez);
223 const double stepLength(sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ));
225 const double meanFreePath(activePAITool->
GetMeanFreePath( scaledKineticEnergy, particleCharge*particleCharge ));
228 const unsigned int numberOfClusters(CLHEP::RandPoisson::shoot(rndmEngine,stepLength / meanFreePath));
232 for (
unsigned int iclus(0); iclus<numberOfClusters; ++iclus)
235 const double lambda(CLHEP::RandFlat::shoot(rndmEngine));
238 double clusE(activePAITool->
GetEnergyTransfer(scaledKineticEnergy, paiRndmEngine));
239 clusterlist.emplace_back(clusE, timeOfHit,
240 prex + lambda * deltaX,
241 prey + lambda * deltaY,
242 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() );
405 double particleCharge =
MC::charge(particleEncoding);
406 double particleMass(0.);
408 const auto particleMassFromTable =
m_genData->particleMass(abs(particleEncoding));
409 if (particleMassFromTable) {
410 particleMass = particleMassFromTable.value();
415 ATH_MSG_WARNING (
"Data for sim. particle with pdgcode "<<particleEncoding <<
" is not a nucleus and could not be retrieved from GenData. Assuming mass of pion. Please investigate." );
423 particleMass = std::abs( Z*Mp+(
A-Z)*Mn );
425 if (!alreadyPrintedPDGcodeWarning) {
426 ATH_MSG_WARNING (
"Data for sim. particle with pdgcode "<<particleEncoding
427 <<
" could not be retrieved from GenData (unexpected ion)."
428 <<
" Please Investigate the PDGTABLE.MeV file."
429 <<
" Calculating mass and charge from pdg code."
430 <<
" The result is: Charge = "<<particleCharge<<
" Mass = "<<particleMass<<
"MeV" );
431 alreadyPrintedPDGcodeWarning =
true;
436 if (!particleCharge) {
continue; }
439 ATH_MSG_WARNING (
"Ignoring ionization from particle with pdg code "<<particleEncoding
440 <<
" since it appears to be a massless charged particle. Please investigate." );
448 const double scaledKineticEnergy(
static_cast<double>((*theHit)->GetKineticEnergy()) * ( CLHEP::proton_mass_c2 / particleMass ));
451 (*theHit)->GetPreStepX(),(*theHit)->GetPreStepY(),(*theHit)->GetPreStepZ(),
452 (*theHit)->GetPostStepX(),(*theHit)->GetPostStepY(),(*theHit)->GetPostStepZ(),
498 double lowthreshold, noiseamplitude;
502 lowthreshold = isBarrel ?
m_settings->lowThresholdBar(strawGasType) :
m_settings->lowThresholdEC(strawGasType);
503 noiseamplitude = 0.0;
512 const std::vector<cluster>& clusters,
513 std::vector<TRTElectronicsProcessing::Deposit>& deposits,
515 double cosmicEventPhase,
517 CLHEP::HepRandomEngine* rndmEngine)
527 const bool isBarrel(region<3 );
528 const bool isEC (!isBarrel);
529 const bool isShort (region==1);
530 const bool isLong (region==2);
540 double ionisationPotential =
m_settings->ionisationPotential(strawGasType);
541 double smearingFactor =
m_settings->smearingFactor(strawGasType);
543 std::vector<cluster>::const_iterator currentClusterIter(clusters.begin());
544 const std::vector<cluster>::const_iterator endOfClusterList(clusters.end());
556 double map_x2(0.),map_y2(0.),map_z2(0.);
557 double effectiveField2(0.);
562 globalPosition[0]=TRThitGlobalPos[0]*CLHEP::mm;
563 globalPosition[1]=TRThitGlobalPos[1]*CLHEP::mm;
564 globalPosition[2]=TRThitGlobalPos[2]*CLHEP::mm;
567 fieldCache.
getField (globalPosition.data(), mField.data());
569 map_x2 = mField.x()*mField.x();
570 map_y2 = mField.y()*mField.y();
571 map_z2 = mField.z()*mField.z();
598 for (;currentClusterIter!=endOfClusterList;++currentClusterIter)
601 const double cluster_x(currentClusterIter->xpos);
602 const double cluster_y(currentClusterIter->ypos);
603 const double cluster_z(this->
setClusterZ(currentClusterIter->zpos, isLong, isShort, isEC));
604 const double cluster_x2(cluster_x*cluster_x);
605 const double cluster_y2(cluster_y*cluster_y);
606 double cluster_r2(cluster_x2+cluster_y2);
609 if (cluster_r2<wire_r2) cluster_r2=wire_r2;
610 if (cluster_r2>straw_r2) cluster_r2=straw_r2;
612 const double cluster_r(std::sqrt(cluster_r2));
613 const double cluster_E(currentClusterIter->energy);
614 const unsigned int nprimaryelectrons(
static_cast<unsigned int>( cluster_E / ionisationPotential + 1.0 ) );
619 double depositEnergy(0.);
623 unsigned int nsurvivingprimaryelectrons =
static_cast<unsigned int>(randBinomial->
fire(rndmEngine,nprimaryelectrons) + 0.5);
624 if (nsurvivingprimaryelectrons==0)
continue;
625 const double meanElectronEnergy(ionisationPotential / smearingFactor);
626 for (
unsigned int ielec(0); ielec<nsurvivingprimaryelectrons; ++ielec) {
627 depositEnergy += CLHEP::RandExpZiggurat::shoot(rndmEngine, meanElectronEnergy);
632 const double fluctSigma(sqrt(cluster_E * ionisationPotential * (2 - smearingFactor) / smearingFactor));
634 depositEnergy = CLHEP::RandGaussZiggurat::shoot(rndmEngine, cluster_E, fluctSigma);
635 }
while(depositEnergy<0.0);
650 effectiveField2 = map_z2*cluster_y2/cluster_r2 + map_x2 + map_y2;
659 effectiveField2 = map_z2 + (map_x2+map_y2)*cluster_y2/cluster_r2;
675 double clusterTime(currentClusterIter->time);
680 clusterTime = clusterTime + cosmicEventPhase +
m_settings->jitterTimeOffset()*( CLHEP::RandFlat::shoot(rndmEngine) );
685 double timedirect(0.), timereflect(0.);
689 double expdirect(1.0), expreflect(1.0);
705 const unsigned int kdirect =
static_cast<unsigned int>(std::max(distdirect,0.0)/10);
706 const unsigned int kreflect =
static_cast<unsigned int>(distreflect/10);
712 double commondrifttime =
m_pSimDriftTimeTool->getAverageDriftTime(cluster_r,effectiveField2,strawGasType);
713 double dt = clusterTime + commondrifttime;
714 deposits.emplace_back(0.5*depositEnergy*expdirect, timedirect+dt);
715 deposits.emplace_back(0.5*depositEnergy*expreflect, timereflect+dt);
727 const int mask(0x0000001F);
729 int trtID, ringID, moduleID, layerID, strawID;
730 int wheelID, planeID, sectorID;
735 if ( !(hitID & 0x00200000) ) {
737 strawID = hitID & mask;
738 hitID >>= word_shift;
739 layerID = hitID & mask;
740 hitID >>= word_shift;
741 moduleID = hitID & mask;
742 hitID >>= word_shift;
743 ringID = hitID & mask;
744 trtID = hitID >> word_shift;
749 const Amg::Vector3D v( (*theHit)->GetPreStepX(),(*theHit)->GetPreStepY(),(*theHit)->GetPreStepZ());
755 strawID = hitID & mask;
756 hitID >>= word_shift;
757 planeID = hitID & mask;
758 hitID >>= word_shift;
759 sectorID = hitID & mask;
760 hitID >>= word_shift;
761 wheelID = hitID & mask;
762 trtID = hitID >> word_shift;
765 if (trtID == 3) trtID = 0;
770 if ( endcapElement ) {
771 const Amg::Vector3D v( (*theHit)->GetPreStepX(),(*theHit)->GetPreStepY(),(*theHit)->GetPreStepZ());
777 ATH_MSG_WARNING (
"Could not find global coordinate of a straw - drifttime calculation will be inaccurate" );
778 return {0.0,0.0,0.0};
784 double cluster_z(cluster_z_in);
789 const double longBarrelStrawHalfLength(349.315*CLHEP::mm);
790 const double shortBarrelStrawHalfLength(153.375*CLHEP::mm);
791 const double EndcapStrawHalfLength(177.150*CLHEP::mm);
792 if ( isLong && std::abs(cluster_z)>longBarrelStrawHalfLength+30 ) {
793 double d = cluster_z<0 ? cluster_z+longBarrelStrawHalfLength : cluster_z-longBarrelStrawHalfLength;
794 ATH_MSG_WARNING (
"Long barrel straw cluster is outside the active gas volume z = +- 349.315 mm by " << d <<
" mm.");
798 if ( isShort && std::abs(cluster_z)>shortBarrelStrawHalfLength+30 ) {
799 double d = cluster_z<0 ? cluster_z+shortBarrelStrawHalfLength : cluster_z-shortBarrelStrawHalfLength;
800 ATH_MSG_WARNING (
"Short barrel straw cluster is outside the active gas volume z = +- 153.375 mm by " << d <<
" mm.");
804 if ( isEC && std::abs(cluster_z)>EndcapStrawHalfLength+30 ) {
805 double d = cluster_z<0 ? cluster_z+EndcapStrawHalfLength : cluster_z-EndcapStrawHalfLength;
806 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.
GenData is a class for particle data access.
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
TRTDigCondBase * m_pDigConditions
std::unique_ptr< CLHEP::RandBinomialFixedP > m_randBinomialKr
std::vector< cluster > m_clusterlist
double m_innerRadiusOfStraw
unsigned int m_maxelectrons
std::unique_ptr< CLHEP::RandBinomialFixedP > m_randBinomialAr
void ClustersToDeposits(MagField::AtlasFieldCache &fieldCache, int hitID, const std::vector< cluster > &clusters, std::vector< TRTElectronicsProcessing::Deposit > &deposits, const 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....
TRTElectronicsProcessing * m_pElectronicsProcessing
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
void addClustersFromStep(double scaledKineticEnergy, double particleCharge, double timeOfHit, double prex, double prey, double prez, double postx, double posty, 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.
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
std::unique_ptr< GenData > m_genData
TRTTimeCorrection * m_pTimeCorrection
const TRTDigSettings * m_settings
TRTProcessingOfStraw(const TRTDigSettings *, const InDetDD::TRT_DetectorManager *, ITRT_PAITool *, ITRT_SimDriftTimeTool *, TRTElectronicsProcessing *ep, TRTNoise *noise, TRTDigCondBase *digcond, const TRT_ID *, ITRT_PAITool *=nullptr, ITRT_PAITool *=nullptr, const ITRT_CalDbTool *=nullptr)
Constructor: Calls Initialize method.
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