File indexing completed on 2025-02-23 09:22:34
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 #include "Par03EMShowerModel.hh"
0027
0028 #include "Par03EMShowerMessenger.hh"
0029
0030 #include "G4Electron.hh"
0031 #include "G4FastHit.hh"
0032 #include "G4FastSimHitMaker.hh"
0033 #include "G4Gamma.hh"
0034 #include "G4Positron.hh"
0035 #include "G4SystemOfUnits.hh"
0036 #include "G4UnitsTable.hh"
0037 #include "Randomize.hh"
0038
0039 Par03EMShowerModel::Par03EMShowerModel(G4String aModelName, G4Region* aEnvelope)
0040 : G4VFastSimulationModel(aModelName, aEnvelope),
0041 fMessenger(new Par03EMShowerMessenger(this)),
0042 fHitMaker(new G4FastSimHitMaker)
0043 {}
0044
0045
0046
0047 Par03EMShowerModel::Par03EMShowerModel(G4String aModelName)
0048 : G4VFastSimulationModel(aModelName),
0049 fMessenger(new Par03EMShowerMessenger(this)),
0050 fHitMaker(new G4FastSimHitMaker)
0051 {}
0052
0053
0054
0055 Par03EMShowerModel::~Par03EMShowerModel() = default;
0056
0057
0058
0059 G4bool Par03EMShowerModel::IsApplicable(const G4ParticleDefinition& aParticleType)
0060 {
0061 return &aParticleType == G4Electron::ElectronDefinition()
0062 || &aParticleType == G4Positron::PositronDefinition()
0063 || &aParticleType == G4Gamma::GammaDefinition();
0064 }
0065
0066
0067
0068 G4bool Par03EMShowerModel::ModelTrigger(const G4FastTrack& aFastTrack)
0069 {
0070
0071 if (aFastTrack.GetPrimaryTrack()->GetKineticEnergy() < 1 * GeV) {
0072 return false;
0073 }
0074
0075
0076
0077
0078 G4double X0 = aFastTrack.GetPrimaryTrack()->GetMaterial()->GetRadlen();
0079 auto particleDirection = aFastTrack.GetPrimaryTrackLocalDirection();
0080 auto particlePosition = aFastTrack.GetPrimaryTrackLocalPosition();
0081 G4double detectorDepthInMM =
0082 aFastTrack.GetEnvelopeSolid()->DistanceToOut(particlePosition, particleDirection);
0083 G4double detectorDepthInX0 = detectorDepthInMM / X0;
0084
0085 if (detectorDepthInX0 < fLongMaxDepth) {
0086 return false;
0087 }
0088 return true;
0089 }
0090
0091
0092
0093 void Par03EMShowerModel::DoIt(const G4FastTrack& aFastTrack, G4FastStep& aFastStep)
0094 {
0095
0096 aFastStep.KillPrimaryTrack();
0097 aFastStep.ProposePrimaryTrackPathLength(0.0);
0098 G4double energy = aFastTrack.GetPrimaryTrack()->GetKineticEnergy();
0099
0100
0101 aFastStep.ProposeTotalEnergyDeposited(0);
0102 auto particlePosition = aFastTrack.GetPrimaryTrackLocalPosition();
0103 auto particleDirection = aFastTrack.GetPrimaryTrackLocalDirection();
0104
0105
0106
0107
0108 auto material = aFastTrack.GetPrimaryTrack()->GetMaterial();
0109 G4double materialX0 = material->GetRadlen();
0110 G4double materialZ = material->GetZ();
0111
0112 G4double materialEc = 610 * MeV / (materialZ + 1.24);
0113
0114 G4double materialRM = 21.2052 * MeV * materialX0 / materialEc;
0115 G4double particleY = energy / materialEc;
0116
0117
0118
0119 if (fAlpha < 0) {
0120
0121 G4double particleTmax = std::log(particleY);
0122 if (aFastTrack.GetPrimaryTrack()->GetParticleDefinition() == G4Gamma::GammaDefinition()) {
0123 particleTmax += 0.5;
0124 }
0125 else {
0126 particleTmax -= 0.5;
0127 }
0128 fAlpha = particleTmax * fBeta + 1;
0129 }
0130
0131
0132 if (fSigma < 0) {
0133
0134
0135 fSigma = materialRM / 1.645;
0136 }
0137
0138
0139
0140 G4RotationMatrix rotMatrix = G4RotationMatrix();
0141 double particleTheta = particleDirection.theta();
0142 double particlePhi = particleDirection.phi();
0143 double epsilon = 1e-3;
0144 rotMatrix.rotateY(particleTheta);
0145
0146 if (!(std::fabs(particleDirection.x()) < epsilon && std::fabs(particleDirection.y()) < epsilon))
0147 rotMatrix.rotateZ(particlePhi);
0148
0149
0150
0151
0152
0153 G4ThreeVector position;
0154 G4double gammaMax = Gamma((fAlpha - 1) / fBeta, fAlpha, fBeta);
0155 G4int generatedHits = 0;
0156 while (generatedHits < fNbOfHits) {
0157 G4double random1 = G4UniformRand() * fLongMaxDepth;
0158 G4double random2 = G4UniformRand() * gammaMax;
0159 if (Gamma(random1, fAlpha, fBeta) >= random2) {
0160
0161 G4double phiPosition = G4UniformRand() * 2 * CLHEP::pi;
0162 G4double rhoPosition = G4RandGauss::shoot(0, fSigma);
0163 position = particlePosition
0164 + rotMatrix
0165 * G4ThreeVector(rhoPosition * std::sin(phiPosition),
0166 rhoPosition * std::cos(phiPosition), random1 * materialX0);
0167
0168
0169 fHitMaker->make(G4FastHit(position, energy / fNbOfHits), aFastTrack);
0170 generatedHits++;
0171 }
0172 }
0173 }
0174
0175
0176
0177 void Par03EMShowerModel::Print() const
0178 {
0179 G4cout << "Par03EMShowerModel: " << G4endl;
0180 G4cout << "Gaussian distribution (transverse plane): \tmu = 0, sigma = "
0181 << G4BestUnit(fSigma, "Length") << G4endl;
0182 if (fSigma < 0)
0183 G4cout << "Negative sigma value means that it will be recalculated "
0184 "from the value of the Moliere radius of the detector material, "
0185 "taking into account that 90% of the area below the Gaussian "
0186 "distribution (from mu - 1.645 sigma to mu + 1.645 sigma) "
0187 "corresponds to area within 1 Moliere radius."
0188 << G4endl;
0189 G4cout << "Gamma distribution (along shower axis): \talpha = " << fAlpha << ", beta = " << fBeta
0190 << ", max depth = " << fLongMaxDepth << " X0" << G4endl;
0191 if (fAlpha < 0)
0192 G4cout << "Negative alpha value means that it will be recalculated "
0193 "from the critical energy of the detector material, particle "
0194 "type, and beta parameter.\n alpha = beta * T_max, where T_max = "
0195 "ln(E/E_C) + C\n where E is particle energy, E_C is critical "
0196 "energy in the material, and constant C = -0.5 for electrons and "
0197 "0.5 for photons (Eq. (33.36) from PDG)."
0198 << G4endl;
0199 G4cout << "Number of created energy deposits: " << fNbOfHits << G4endl;
0200 }