File indexing completed on 2026-07-13 08:21:04
0001 #include "G4HepEmElectronInteractionUMSC.hh"
0002
0003 #include "G4HepEmRandomEngine.hh"
0004
0005 #include "G4HepEmMSCTrackData.hh"
0006
0007 #include "G4HepEmConstants.hh"
0008 #include "G4HepEmMath.hh"
0009
0010 #include "G4HepEmData.hh"
0011 #include "G4HepEmParameters.hh"
0012
0013 #include "G4HepEmMaterialData.hh"
0014
0015
0016
0017
0018
0019 void G4HepEmElectronInteractionUMSC::StepLimit(G4HepEmData* hepEmData, G4HepEmParameters* hepEmPars,
0020 G4HepEmMSCTrackData* mscData, double ekin, int imat, int iregion, double range, double presafety,
0021 bool onBoundary, bool iselectron, G4HepEmRandomEngine* rnge) {
0022
0023
0024
0025
0026 mscData->fIsNoScatteringInMSC = false;
0027 mscData->fIsDisplace = true;
0028
0029
0030
0031
0032
0033 const double kTLimitMinfix = 1.0E-8;
0034 const struct G4HepEmMatData& matData = hepEmData->fTheMaterialData->fMaterialData[imat];
0035 if (mscData->fTrueStepLength < kTLimitMinfix || range*(matData.fUMSCPar) < presafety) {
0036 mscData->fIsDisplace = false;
0037 return;
0038 }
0039 const double mscRangeFactor = hepEmPars->fParametersPerRegion[iregion].fMSCRangeFactor;
0040 const double mscSafetyFactor = hepEmPars->fParametersPerRegion[iregion].fMSCSafetyFactor;
0041 const bool mscIsUseSafety = !hepEmPars->fParametersPerRegion[iregion].fIsMSCMinimalStepLimit;
0042
0043 double tlimit = 0.0;
0044 if (mscIsUseSafety) {
0045
0046
0047
0048
0049
0050 if (mscData->fIsFirstStep || onBoundary) {
0051 const double lambdaTr1 = mscData->fLambtr1;
0052 mscData->fInitialRange = G4HepEmMax(range, lambdaTr1);
0053
0054
0055 mscData->fDynamicRangeFactor = lambdaTr1 > 1.0
0056 ? mscRangeFactor*(0.75 + 0.25*lambdaTr1)
0057 : mscRangeFactor;
0058
0059 const double stepMin = lambdaTr1*1.0E-3/(2.0E-3 + ekin*(matData.fUMSCStepMinPars[0] + ekin*matData.fUMSCStepMinPars[1]));
0060
0061
0062
0063
0064
0065
0066 #if G4VERSION_NUM < 1070
0067
0068 mscData->fTlimitMin = G4HepEmMax(0.70*matData.fZeffSqrt*stepMin, kTLimitMinfix);
0069 #else
0070
0071 const double dum0 = iselectron ? 0.87*matData.fZeff23 : 0.70*matData.fZeffSqrt;
0072
0073 const double dum1 = ekin > 5.0E-3 ? dum0*stepMin : dum0*stepMin*0.5*(1.0 + ekin*200.0);
0074 mscData->fTlimitMin = G4HepEmMax(dum1, kTLimitMinfix);
0075 #endif
0076
0077
0078 mscData->fIsFirstStep = false;
0079 }
0080
0081 const double tlimitmin = mscData->fTlimitMin;
0082 tlimit = range > presafety
0083 ? G4HepEmMax(G4HepEmMax(mscData->fInitialRange*mscData->fDynamicRangeFactor, mscSafetyFactor*presafety), tlimitmin)
0084 : G4HepEmMax(range, tlimitmin);
0085 } else {
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095 if (onBoundary) {
0096 const double lambdaTr1 = mscData->fLambtr1;
0097 const double tmpTlimit = range > lambdaTr1
0098 ? mscRangeFactor*range
0099 : mscRangeFactor*lambdaTr1;
0100
0101
0102
0103 mscData->fInitialRange = G4HepEmMax(tmpTlimit, 10*kTLimitMinfix);
0104 }
0105 tlimit = mscData->fInitialRange;
0106 }
0107
0108
0109
0110
0111 const double tlimitmin = mscData->fTlimitMin;
0112
0113 if (tlimit < mscData->fTrueStepLength) {
0114 const double dum0 = tlimit > tlimitmin
0115 ? G4HepEmMax(rnge->Gauss(tlimit, 0.1*(tlimit - tlimitmin)), tlimitmin)
0116 : tlimitmin;
0117 mscData->fTrueStepLength = G4HepEmMin(dum0, mscData->fTrueStepLength);
0118 }
0119
0120
0121
0122
0123
0124
0125
0126 }
0127
0128
0129 void G4HepEmElectronInteractionUMSC::SampleScattering(G4HepEmData* hepEmData, G4HepEmMSCTrackData* mscData,
0130 double pStepLength, double preStepEkin, double preStepTr1mfp, double postStepEkin, double postStepTr1mfp,
0131 int imat, bool isElectron, bool isPosCor, bool isDisplace, G4HepEmRandomEngine* rnge) {
0132 const struct G4HepEmMatData& matData = hepEmData->fTheMaterialData->fMaterialData[imat];
0133 const double cost = SampleCosineTheta(pStepLength, preStepEkin, preStepTr1mfp, postStepEkin, postStepTr1mfp, mscData->fTlimitMin,
0134 matData.fRadiationLength, matData.fZeff, matData.fUMSCTailCoeff, matData.fUMSCThetaCoeff, isElectron, isPosCor, rnge);
0135
0136 if (std::abs(cost) >= 1.0) {
0137 mscData->fIsNoScatteringInMSC = true;
0138
0139 return;
0140 }
0141 const double sth = std::sqrt((1.0 - cost)*(1.0 + cost));
0142 const double phi = k2Pi*rnge->flat();
0143 mscData->SetNewDirection(sth*std::cos(phi), sth*std::sin(phi), cost);
0144
0145 mscData->fIsDisplace = mscData->fIsDisplace && isDisplace;
0146 if (mscData->fIsDisplace && pStepLength > mscData->fZPathLength) {
0147 SampleDisplacement(pStepLength, phi, mscData, rnge);
0148 }
0149 }
0150
0151
0152 double G4HepEmElectronInteractionUMSC::SampleCosineTheta(double pStepLength, double preStepEkin, double preStepTr1mfp,
0153 double postStepEkin, double postStepTr1mfp, double umscTlimitMin, double radLength, double zeff,
0154 const double* umscTailCoeff, const double* umscThetaCoeff, bool isElectron, bool isPosCor, G4HepEmRandomEngine* rnge) {
0155
0156
0157
0158 const double iPreStepTr1mfp = 1.0/preStepTr1mfp;
0159 const double deltaR1mfp = preStepTr1mfp - postStepTr1mfp;
0160 const double tau = std::abs(deltaR1mfp) > 0.01*preStepTr1mfp
0161 ? pStepLength*G4HepEmLog(preStepTr1mfp/postStepTr1mfp)/deltaR1mfp
0162 : pStepLength*iPreStepTr1mfp;
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173 const double kTauBig = 8.0;
0174 if (tau > kTauBig) {
0175 return 2.0*rnge->flat() - 1.0;
0176 }
0177
0178
0179 const double kTauSmall = 1.0E-16;
0180 if (tau < kTauSmall) {
0181 return 1.0;
0182 }
0183
0184
0185 double xmeanth, x2meanth;
0186 if (tau < 0.01) {
0187
0188 xmeanth = 1.0 - tau*(1.0 - 0.5*tau);
0189 x2meanth = 1.0 - tau*(5.0 - 6.25*tau)*0.333333;
0190 } else {
0191 xmeanth = G4HepEmExp(-tau);
0192 x2meanth = (1.0 + 2.0*G4HepEmExp(-2.5*tau))*0.333333;
0193 }
0194
0195 if (postStepEkin < 0.5*preStepEkin) {
0196 return SimpleScattering(xmeanth, x2meanth, rnge);
0197 }
0198
0199
0200 const double tsmall = G4HepEmMin(umscTlimitMin, 1.0);
0201 const bool stpNotExSmall = pStepLength > tsmall;
0202 const double theta0 = stpNotExSmall
0203 ? ComputeTheta0(pStepLength/radLength, postStepEkin, preStepEkin, zeff, umscThetaCoeff, isElectron, isPosCor)
0204 : ComputeTheta0(tsmall/radLength, postStepEkin, preStepEkin, zeff, umscThetaCoeff, isElectron, isPosCor)*std::sqrt(pStepLength/tsmall);
0205
0206 if (theta0 > kPi*0.166666) {
0207 return SimpleScattering(xmeanth, x2meanth, rnge);
0208 }
0209
0210 const double theta2 = theta0*theta0;
0211 if (theta2 < kTauSmall) {
0212
0213 return 1.0;
0214 }
0215
0216
0217 const double dumtau = stpNotExSmall ? tau : tsmall*iPreStepTr1mfp;
0218 const double parU = G4HepEmPow(dumtau, 0.1666666);
0219 const double dumxsi = umscTailCoeff[0] + parU*(umscTailCoeff[1] + parU*umscTailCoeff[2])
0220 + umscTailCoeff[3]*G4HepEmLog(pStepLength/(tau*radLength));
0221
0222 const double parXsi = G4HepEmMax(dumxsi, 1.9);
0223
0224 const double parC = std::abs(parXsi - 3.) < 0.001 ? 3.001
0225 : std::abs(parXsi - 2.) < 0.001 ? 2.001
0226 : parXsi;
0227 const double dumC1 = parC - 1.;
0228 const double dumEa = G4HepEmExp(-parXsi);
0229 const double dumEaa = 1./(1. - dumEa);
0230 double thex = theta2*(1.0 - theta2*0.0833333);
0231 if (theta2 > 0.01) {
0232 const double dum = 2.0*std::sin(0.5*theta0);
0233 thex = dum*dum;
0234 }
0235 const double xmean1 = 1. - (1. - (1. + parXsi)*dumEa)*thex*dumEaa;
0236
0237 if (xmean1 <= 0.999*xmeanth) {
0238 return SimpleScattering(xmeanth, x2meanth, rnge);
0239 }
0240
0241 const double x0 = 1. - parXsi*thex;
0242 const double bx = parC*thex;
0243
0244 const double b = bx + x0;
0245 const double b1 = b + 1.;
0246
0247 const double eb1 = G4HepEmPow(b1, dumC1);
0248 const double ebx = G4HepEmPow(bx, dumC1);
0249 const double d = ebx/eb1;
0250
0251 const double xmean2 = (x0 + d - (bx - b1*d)/(parC - 2.))/(1. - d);
0252
0253 const double f1x0 = dumEa*dumEaa;
0254 const double f2x0 = dumC1/(parC*(1. - d));
0255 const double prob = f2x0/(f1x0 + f2x0);
0256
0257 const double qprb = xmeanth/(prob*xmean1 + (1. - prob)*xmean2);
0258
0259
0260 double rndArray[3];
0261 rnge->flatArray(3, rndArray);
0262 if (rndArray[0] < qprb) {
0263 if (rndArray[1] < prob) {
0264 return 1. + G4HepEmLog(dumEa + rndArray[2]/dumEaa)*thex;
0265 } else {
0266 const double var0 = (1.0 - d)*rndArray[2];
0267 if (var0 < 0.01*d) {
0268 const double var = var0/(d*dumC1);
0269 return -1.0 + var*(1.0 - var*0.5*parC)*b1;
0270 } else {
0271 return 1.0 + thex*(parC - parXsi - parC*G4HepEmPow(var0 + d, -1./dumC1));
0272 }
0273 }
0274 } else {
0275 return 2.0*rndArray[1] - 1.0;
0276 }
0277 }
0278
0279
0280 double G4HepEmElectronInteractionUMSC::SimpleScattering(double xmeanth, double x2meanth, G4HepEmRandomEngine* rnge) {
0281
0282
0283 const double dum0 = 3.*x2meanth - 1;
0284 const double dum1 = 2.*xmeanth - dum0;
0285 const double a = 1. + 4.*dum0/dum1;
0286 const double prob = (2. + a)*xmeanth/a;
0287
0288 double rndArray[2];
0289 rnge->flatArray(2, rndArray);
0290 return (rndArray[0] < prob)
0291 ? -1. + 2.*G4HepEmPow(rndArray[1],1./(1. + a))
0292 : -1. + 2.*rndArray[1];
0293 }
0294
0295
0296
0297 double G4HepEmElectronInteractionUMSC::ComputeTheta0(double stepInRadLength, double postStepEkin, double preStepEkin, double zeff,
0298 const double* umscThetaCoeff, bool isElectron, bool isPosCor) {
0299
0300 const double kHighland = 13.6;
0301 const double postInvBetaPc = (postStepEkin + kElectronMassC2)/(postStepEkin*(postStepEkin + 2.*kElectronMassC2));
0302 const double invBetaPc = preStepEkin != postStepEkin
0303 ? std::sqrt(postInvBetaPc*(preStepEkin + kElectronMassC2)/(preStepEkin*(preStepEkin + 2.*kElectronMassC2)))
0304 : postInvBetaPc;
0305 const double y = (isElectron || !isPosCor)
0306 ? stepInRadLength
0307 : stepInRadLength * Theta0PositronCorrection(preStepEkin*postStepEkin, zeff);
0308 return kHighland*std::sqrt(y)*invBetaPc*(umscThetaCoeff[0] + umscThetaCoeff[1]*G4HepEmLog(y));
0309 }
0310
0311
0312
0313 double G4HepEmElectronInteractionUMSC::Theta0PositronCorrection(double eekin, double zeff) {
0314 const double ff = 1. + zeff*(1.84035E-4*zeff - 1.86427E-2) + 0.41125;
0315 const double a = 0.994 - 4.08E-3*zeff;
0316 const double b = 7.16 + (52.6 + 365./zeff)/zeff;
0317 const double tu = std::sqrt(eekin)*kInvElectronMassC2;
0318 const double x = std::sqrt(tu*(tu + 2.)/((tu + 1.)*(tu + 1.)));
0319
0320 const double xl = 0.6;
0321 if (x < xl) {
0322 return ff*a*(1. - G4HepEmExp(-b*x));
0323 }
0324
0325 const double c = 1.00 - 4.47E-3*zeff;
0326 const double d = 1.21E-3*zeff;
0327 const double e = 113.0;
0328 const double xh = 0.9;
0329 if(x > xh) {
0330 return ff*(c + d*G4HepEmExp(e*(x - 1.)));
0331 }
0332
0333 const double yl = a*(1. - G4HepEmExp(-b*xl));
0334 const double yh = c + d*G4HepEmExp(e*(xh -1.));
0335 const double y0 = (yh - yl)/(xh - xl);
0336 const double y1 = yl - y0*xl;
0337 return ff*(y0*x + y1);
0338 }
0339
0340
0341
0342 void G4HepEmElectronInteractionUMSC::SampleDisplacement(double pStepLength, double thePhi, G4HepEmMSCTrackData* mscData, G4HepEmRandomEngine* rnge) {
0343
0344
0345
0346 const double r = 0.73*std::sqrt((pStepLength - mscData->fZPathLength)*(pStepLength + mscData->fZPathLength));
0347
0348
0349
0350 const double cbeta = 2.16;
0351 const double cbeta1 = 1. - G4HepEmExp(-cbeta*kPi);
0352 double rndArray[2];
0353 rnge->flatArray(2, rndArray);
0354 const double psi = -G4HepEmLog(1. - rndArray[0]*cbeta1)/cbeta;
0355 const double phi = (rndArray[1] < 0.5) ? thePhi + psi : thePhi - psi;
0356 mscData->SetDisplacement(r*std::cos(phi), r*std::sin(phi), 0.0);
0357 }