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