File indexing completed on 2025-01-31 09:22:05
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
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 #include "G4LowEnergyCompton.hh"
0046 #include "Randomize.hh"
0047 #include "G4PhysicalConstants.hh"
0048 #include "G4SystemOfUnits.hh"
0049 #include "G4ParticleDefinition.hh"
0050 #include "G4Track.hh"
0051 #include "G4Step.hh"
0052 #include "G4ForceCondition.hh"
0053 #include "G4Gamma.hh"
0054 #include "G4Electron.hh"
0055 #include "G4DynamicParticle.hh"
0056 #include "G4VParticleChange.hh"
0057 #include "G4ThreeVector.hh"
0058 #include "G4EnergyLossTables.hh"
0059 #include "G4RDVCrossSectionHandler.hh"
0060 #include "G4RDCrossSectionHandler.hh"
0061 #include "G4RDVEMDataSet.hh"
0062 #include "G4RDCompositeEMDataSet.hh"
0063 #include "G4RDVDataSetAlgorithm.hh"
0064 #include "G4RDLogLogInterpolation.hh"
0065 #include "G4RDVRangeTest.hh"
0066 #include "G4RDRangeTest.hh"
0067 #include "G4RDRangeNoTest.hh"
0068 #include "G4MaterialCutsCouple.hh"
0069
0070
0071 G4LowEnergyCompton::G4LowEnergyCompton(const G4String& processName)
0072 : G4VDiscreteProcess(processName),
0073 lowEnergyLimit(250*eV),
0074 highEnergyLimit(100*GeV),
0075 intrinsicLowEnergyLimit(10*eV),
0076 intrinsicHighEnergyLimit(100*GeV)
0077 {
0078 if (lowEnergyLimit < intrinsicLowEnergyLimit ||
0079 highEnergyLimit > intrinsicHighEnergyLimit)
0080 {
0081 G4Exception("G4LowEnergyCompton::G4LowEnergyCompton()",
0082 "OutOfRange", FatalException,
0083 "Energy outside intrinsic process validity range!");
0084 }
0085
0086 crossSectionHandler = new G4RDCrossSectionHandler;
0087
0088 G4RDVDataSetAlgorithm* scatterInterpolation = new G4RDLogLogInterpolation;
0089 G4String scatterFile = "comp/ce-sf-";
0090 scatterFunctionData = new G4RDCompositeEMDataSet(scatterInterpolation, 1., 1.);
0091 scatterFunctionData->LoadData(scatterFile);
0092
0093 meanFreePathTable = 0;
0094
0095 rangeTest = new G4RDRangeNoTest;
0096
0097
0098 shellData.SetOccupancyData();
0099
0100 if (verboseLevel > 0)
0101 {
0102 G4cout << GetProcessName() << " is created " << G4endl
0103 << "Energy range: "
0104 << lowEnergyLimit / keV << " keV - "
0105 << highEnergyLimit / GeV << " GeV"
0106 << G4endl;
0107 }
0108 }
0109
0110 G4LowEnergyCompton::~G4LowEnergyCompton()
0111 {
0112 delete meanFreePathTable;
0113 delete crossSectionHandler;
0114 delete scatterFunctionData;
0115 delete rangeTest;
0116 }
0117
0118 void G4LowEnergyCompton::BuildPhysicsTable(const G4ParticleDefinition& )
0119 {
0120
0121 crossSectionHandler->Clear();
0122 G4String crossSectionFile = "comp/ce-cs-";
0123 crossSectionHandler->LoadData(crossSectionFile);
0124
0125 delete meanFreePathTable;
0126 meanFreePathTable = crossSectionHandler->BuildMeanFreePathForMaterials();
0127
0128
0129 G4String file = "/doppler/shell-doppler";
0130 shellData.LoadData(file);
0131 }
0132
0133 G4VParticleChange* G4LowEnergyCompton::PostStepDoIt(const G4Track& aTrack,
0134 const G4Step& aStep)
0135 {
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150 aParticleChange.Initialize(aTrack);
0151
0152
0153 const G4DynamicParticle* incidentPhoton = aTrack.GetDynamicParticle();
0154 G4double photonEnergy0 = incidentPhoton->GetKineticEnergy();
0155
0156 if (photonEnergy0 <= lowEnergyLimit)
0157 {
0158 aParticleChange.ProposeTrackStatus(fStopAndKill);
0159 aParticleChange.ProposeEnergy(0.);
0160 aParticleChange.ProposeLocalEnergyDeposit(photonEnergy0);
0161 return G4VDiscreteProcess::PostStepDoIt(aTrack,aStep);
0162 }
0163
0164 G4double e0m = photonEnergy0 / electron_mass_c2 ;
0165 G4ParticleMomentum photonDirection0 = incidentPhoton->GetMomentumDirection();
0166 G4double epsilon0 = 1. / (1. + 2. * e0m);
0167 G4double epsilon0Sq = epsilon0 * epsilon0;
0168 G4double alpha1 = -std::log(epsilon0);
0169 G4double alpha2 = 0.5 * (1. - epsilon0Sq);
0170 G4double wlPhoton = h_Planck*c_light/photonEnergy0;
0171
0172
0173 const G4MaterialCutsCouple* couple = aTrack.GetMaterialCutsCouple();
0174 G4int Z = crossSectionHandler->SelectRandomAtom(couple,photonEnergy0);
0175
0176
0177 G4double epsilon;
0178 G4double epsilonSq;
0179 G4double oneCosT;
0180 G4double sinT2;
0181 G4double gReject;
0182 do
0183 {
0184 if ( alpha1/(alpha1+alpha2) > G4UniformRand())
0185 {
0186 epsilon = std::exp(-alpha1 * G4UniformRand());
0187 epsilonSq = epsilon * epsilon;
0188 }
0189 else
0190 {
0191 epsilonSq = epsilon0Sq + (1. - epsilon0Sq) * G4UniformRand();
0192 epsilon = std::sqrt(epsilonSq);
0193 }
0194
0195 oneCosT = (1. - epsilon) / ( epsilon * e0m);
0196 sinT2 = oneCosT * (2. - oneCosT);
0197 G4double x = std::sqrt(oneCosT/2.) / (wlPhoton/cm);
0198 G4double scatteringFunction = scatterFunctionData->FindValue(x,Z-1);
0199 gReject = (1. - epsilon * sinT2 / (1. + epsilonSq)) * scatteringFunction;
0200
0201 } while(gReject < G4UniformRand()*Z);
0202
0203 G4double cosTheta = 1. - oneCosT;
0204 G4double sinTheta = std::sqrt (sinT2);
0205 G4double phi = twopi * G4UniformRand() ;
0206 G4double dirX = sinTheta * std::cos(phi);
0207 G4double dirY = sinTheta * std::sin(phi);
0208 G4double dirZ = cosTheta ;
0209
0210
0211
0212
0213
0214
0215
0216 G4int maxDopplerIterations = 1000;
0217 G4double bindingE = 0.;
0218 G4double photonEoriginal = epsilon * photonEnergy0;
0219 G4double photonE = -1.;
0220 G4int iteration = 0;
0221 G4double eMax = photonEnergy0;
0222 do
0223 {
0224 iteration++;
0225
0226 G4int shell = shellData.SelectRandomShell(Z);
0227 bindingE = shellData.BindingEnergy(Z,shell);
0228
0229 eMax = photonEnergy0 - bindingE;
0230
0231
0232 G4double pSample = profileData.RandomSelectMomentum(Z,shell);
0233
0234 G4double pDoppler = pSample * fine_structure_const;
0235 G4double pDoppler2 = pDoppler * pDoppler;
0236 G4double var2 = 1. + oneCosT * e0m;
0237 G4double var3 = var2*var2 - pDoppler2;
0238 G4double var4 = var2 - pDoppler2 * cosTheta;
0239 G4double var = var4*var4 - var3 + pDoppler2 * var3;
0240 if (var > 0.)
0241 {
0242 G4double varSqrt = std::sqrt(var);
0243 G4double scale = photonEnergy0 / var3;
0244
0245 if (G4UniformRand() < 0.5) photonE = (var4 - varSqrt) * scale;
0246 else photonE = (var4 + varSqrt) * scale;
0247 }
0248 else
0249 {
0250 photonE = -1.;
0251 }
0252 } while ( iteration <= maxDopplerIterations &&
0253 (photonE < 0. || photonE > eMax || photonE < eMax*G4UniformRand()) );
0254
0255
0256
0257 if (iteration >= maxDopplerIterations)
0258 {
0259 photonE = photonEoriginal;
0260 bindingE = 0.;
0261 }
0262
0263
0264
0265 G4ThreeVector photonDirection1(dirX,dirY,dirZ);
0266 photonDirection1.rotateUz(photonDirection0);
0267 aParticleChange.ProposeMomentumDirection(photonDirection1);
0268
0269 G4double photonEnergy1 = photonE;
0270
0271
0272 if (photonEnergy1 > 0.)
0273 {
0274 aParticleChange.ProposeEnergy(photonEnergy1) ;
0275 }
0276 else
0277 {
0278 aParticleChange.ProposeEnergy(0.) ;
0279 aParticleChange.ProposeTrackStatus(fStopAndKill);
0280 }
0281
0282
0283 G4double eKineticEnergy = photonEnergy0 - photonEnergy1 - bindingE;
0284 G4double eTotalEnergy = eKineticEnergy + electron_mass_c2;
0285
0286 G4double electronE = photonEnergy0 * (1. - epsilon) + electron_mass_c2;
0287 G4double electronP2 = electronE*electronE - electron_mass_c2*electron_mass_c2;
0288 G4double sinThetaE = -1.;
0289 G4double cosThetaE = 0.;
0290 if (electronP2 > 0.)
0291 {
0292 cosThetaE = (eTotalEnergy + photonEnergy1 )* (1. - epsilon) / std::sqrt(electronP2);
0293 sinThetaE = -1. * std::sqrt(1. - cosThetaE * cosThetaE);
0294 }
0295
0296 G4double eDirX = sinThetaE * std::cos(phi);
0297 G4double eDirY = sinThetaE * std::sin(phi);
0298 G4double eDirZ = cosThetaE;
0299
0300
0301
0302 G4double safety = aStep.GetPostStepPoint()->GetSafety();
0303
0304 if (rangeTest->Escape(G4Electron::Electron(),couple,eKineticEnergy,safety))
0305 {
0306 G4ThreeVector eDirection(eDirX,eDirY,eDirZ);
0307 eDirection.rotateUz(photonDirection0);
0308
0309 G4DynamicParticle* electron = new G4DynamicParticle (G4Electron::Electron(),eDirection,eKineticEnergy) ;
0310 aParticleChange.SetNumberOfSecondaries(1);
0311 aParticleChange.AddSecondary(electron);
0312
0313 aParticleChange.ProposeLocalEnergyDeposit(bindingE);
0314 }
0315 else
0316 {
0317 aParticleChange.SetNumberOfSecondaries(0);
0318 aParticleChange.ProposeLocalEnergyDeposit(eKineticEnergy + bindingE);
0319 }
0320
0321 return G4VDiscreteProcess::PostStepDoIt( aTrack, aStep);
0322 }
0323
0324 G4bool G4LowEnergyCompton::IsApplicable(const G4ParticleDefinition& particle)
0325 {
0326 return ( &particle == G4Gamma::Gamma() );
0327 }
0328
0329 G4double G4LowEnergyCompton::GetMeanFreePath(const G4Track& track,
0330 G4double,
0331 G4ForceCondition*)
0332 {
0333 const G4DynamicParticle* photon = track.GetDynamicParticle();
0334 G4double energy = photon->GetKineticEnergy();
0335 const G4MaterialCutsCouple* couple = track.GetMaterialCutsCouple();
0336 size_t materialIndex = couple->GetIndex();
0337
0338 G4double meanFreePath;
0339 if (energy > highEnergyLimit) meanFreePath = meanFreePathTable->FindValue(highEnergyLimit,materialIndex);
0340 else if (energy < lowEnergyLimit) meanFreePath = DBL_MAX;
0341 else meanFreePath = meanFreePathTable->FindValue(energy,materialIndex);
0342 return meanFreePath;
0343 }