File indexing completed on 2026-07-13 08:21:04
0001
0002 #include "G4HepEmElectronManager.hh"
0003
0004 #include "G4HepEmData.hh"
0005 #include "G4HepEmParameters.hh"
0006 #include "G4HepEmTLData.hh"
0007 #include "G4HepEmRandomEngine.hh"
0008
0009 #include "G4HepEmConstants.hh"
0010 #include "G4HepEmMatCutData.hh"
0011 #include "G4HepEmMaterialData.hh"
0012 #include "G4HepEmElectronData.hh"
0013
0014 #include "G4HepEmMath.hh"
0015
0016 #include "G4HepEmRunUtils.hh"
0017 #include "G4HepEmTrack.hh"
0018 #include "G4HepEmElectronTrack.hh"
0019 #include "G4HepEmMSCTrackData.hh"
0020 #include "G4HepEmGammaTrack.hh"
0021 #include "G4HepEmElectronInteractionIoni.hh"
0022 #include "G4HepEmElectronInteractionBrem.hh"
0023 #include "G4HepEmElectronEnergyLossFluctuation.hh"
0024 #include "G4HepEmElectronInteractionUMSC.hh"
0025 #include "G4HepEmPositronInteractionAnnihilation.hh"
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 void G4HepEmElectronManager::HowFar(struct G4HepEmData* hepEmData, struct G4HepEmParameters* hepEmPars, G4HepEmTLData* tlData) {
0036 G4HepEmElectronTrack* theElTrack = tlData->GetPrimaryElectronTrack();
0037 G4HepEmTrack* theTrack = theElTrack->GetTrack();
0038
0039 for (int ip=0; ip<4; ++ip) {
0040 if (theTrack->GetNumIALeft(ip)<=0.) {
0041 theTrack->SetNumIALeft(-G4HepEmLog(tlData->GetRNGEngine()->flat()), ip);
0042 }
0043 }
0044 HowFar(hepEmData, hepEmPars, theElTrack, tlData->GetRNGEngine());
0045 }
0046
0047
0048 void G4HepEmElectronManager::HowFarToDiscreteInteraction(struct G4HepEmData* hepEmData, struct G4HepEmParameters* hepEmPars, G4HepEmElectronTrack* theElTrack) {
0049 int indxWinnerProcess = -1;
0050
0051 double pStepLength = kALargeValue;
0052 G4HepEmTrack* theTrack = theElTrack->GetTrack();
0053 const double theEkin = theTrack->GetEKin();
0054 const double theLEkin = theTrack->GetLogEKin();
0055 const int theIMC = theTrack->GetMCIndex();
0056 const bool isElectron = (theTrack->GetCharge() < 0.0);
0057
0058 const G4HepEmElectronData* theElectronData = isElectron
0059 ? hepEmData->fTheElectronData
0060 : hepEmData->fThePositronData;
0061
0062 const double range = GetRestRange(theElectronData, theIMC, theEkin, theLEkin);
0063 theElTrack->SetRange(range);
0064 const int indxRegion = hepEmData->fTheMatCutData->fMatCutData[theIMC].fG4RegionIndex;
0065 const double frange = hepEmPars->fParametersPerRegion[indxRegion].fFinalRange;
0066 const double drange = hepEmPars->fParametersPerRegion[indxRegion].fDRoverRange;
0067 pStepLength = (range > frange)
0068 ? range*drange + frange*(1.0-drange)*(2.0-frange/range)
0069 : range;
0070
0071
0072 const int theImat = (hepEmData->fTheMatCutData->fMatCutData[theIMC]).fHepEmMatIndex;
0073 double mxSecs[4];
0074
0075 mxSecs[0] = GetRestMacXSecForStepping(theElectronData, theIMC, theEkin, theLEkin, true);
0076 mxSecs[1] = GetRestMacXSecForStepping(theElectronData, theIMC, theEkin, theLEkin, false);
0077 mxSecs[2] = (isElectron)
0078 ? 0.0
0079 : ComputeMacXsecAnnihilationForStepping(theEkin, hepEmData->fTheMaterialData->fMaterialData[theImat].fElectronDensity);
0080 mxSecs[3] = GetMacXSecNuclearForStepping(theElectronData, theImat, theEkin, theLEkin);
0081
0082
0083 for (int ip=0; ip<4; ++ip) {
0084 const double mxsec = mxSecs[ip];
0085 const double mfp = (mxsec>0.) ? 1./mxsec : kALargeValue;
0086
0087
0088
0089 theTrack->SetMFP(mfp, ip);
0090
0091 const double dStepLimit = mfp*theTrack->GetNumIALeft(ip);
0092 if (dStepLimit<pStepLength) {
0093 pStepLength = dStepLimit;
0094 indxWinnerProcess = ip;
0095 }
0096 }
0097
0098 theElTrack->SetPStepLength(pStepLength);
0099 theTrack->SetWinnerProcessIndex(indxWinnerProcess);
0100 theTrack->SetGStepLength(pStepLength);
0101 }
0102
0103 void G4HepEmElectronManager::HowFarToMSC(struct G4HepEmData* hepEmData, struct G4HepEmParameters* hepEmPars, G4HepEmElectronTrack* theElTrack, G4HepEmRandomEngine* rnge) {
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115 #ifndef NOMSC
0116 double pStepLength = theElTrack->GetPStepLength();
0117 const double range = theElTrack->GetRange();
0118 G4HepEmTrack* theTrack = theElTrack->GetTrack();
0119 const double theEkin = theTrack->GetEKin();
0120 const double theLEkin = theTrack->GetLogEKin();
0121 const int theIMC = theTrack->GetMCIndex();
0122 const bool isElectron = (theTrack->GetCharge() < 0.0);
0123
0124 const G4HepEmElectronData* theElectronData = isElectron
0125 ? hepEmData->fTheElectronData
0126 : hepEmData->fThePositronData;
0127
0128 const G4HepEmMCCData& theMatCutData = hepEmData->fTheMatCutData->fMatCutData[theIMC];
0129 const int theImat = theMatCutData.fHepEmMatIndex;
0130 const int theIreg = theMatCutData.fG4RegionIndex;
0131 G4HepEmMSCTrackData* mscData = theElTrack->GetMSCTrackData();
0132
0133 mscData->fTrueStepLength = pStepLength;
0134 mscData->fZPathLength = pStepLength;
0135 mscData->fIsActive = false;
0136 mscData->SetDisplacement(0., 0., 0.);
0137 mscData->SetNewDirection(0., 0., 1.);
0138
0139 const double kGeomMinLength = 5.E-8;
0140 if (pStepLength > kGeomMinLength && theEkin > 1.0E-3) {
0141 mscData->fIsActive = true;
0142
0143 mscData->fLambtr1 = GetTransportMFP(theElectronData, theImat, theEkin, theLEkin);
0144 G4HepEmElectronInteractionUMSC::StepLimit(hepEmData, hepEmPars, mscData, theEkin, theImat, theIreg, range,
0145 theTrack->GetSafety(), theTrack->GetOnBoundary(), isElectron, rnge);
0146
0147
0148
0149
0150
0151 ConvertTrueToGeometricLength(hepEmData, mscData, theEkin, range, theIMC, isElectron);
0152
0153 const double mscTruStepLength = mscData->fTrueStepLength;
0154 if (mscTruStepLength < pStepLength) {
0155
0156 theTrack->SetWinnerProcessIndex(-2);
0157 pStepLength = mscTruStepLength;
0158 theElTrack->SetPStepLength(pStepLength);
0159 }
0160
0161 theTrack->SetGStepLength(G4HepEmMin(mscData->fZPathLength, pStepLength));
0162 }
0163 #endif
0164 }
0165
0166 void G4HepEmElectronManager::HowFar(struct G4HepEmData* hepEmData, struct G4HepEmParameters* hepEmPars, G4HepEmElectronTrack* theElTrack, G4HepEmRandomEngine* rnge) {
0167 HowFarToDiscreteInteraction(hepEmData, hepEmPars, theElTrack);
0168 HowFarToMSC(hepEmData, hepEmPars, theElTrack, rnge);
0169 }
0170
0171 void G4HepEmElectronManager::UpdatePStepLength(G4HepEmElectronTrack* theElTrack) {
0172 G4HepEmTrack* theTrack = theElTrack->GetTrack();
0173 const double gStepLength = theTrack->GetGStepLength();
0174 double pStepLength = gStepLength;
0175
0176
0177
0178
0179 #ifndef NOMSC
0180 const double theRange = theElTrack->GetRange();
0181 G4HepEmMSCTrackData* mscData = theElTrack->GetMSCTrackData();
0182 if (mscData->fIsActive) {
0183 pStepLength = mscData->fTrueStepLength;
0184
0185 if (gStepLength < mscData->fZPathLength) {
0186
0187 ConvertGeometricToTrueLength(mscData, theRange, gStepLength);
0188
0189
0190 pStepLength = G4HepEmMin(pStepLength, mscData->fTrueStepLength);
0191
0192 mscData->fTrueStepLength = pStepLength;
0193 }
0194
0195 const double kGeomMinLength = 5.E-8;
0196 if (pStepLength <= kGeomMinLength || theRange <= pStepLength) {
0197 mscData->fIsActive = false;
0198 }
0199 }
0200 #endif
0201
0202 theElTrack->SetPStepLength(pStepLength);
0203 }
0204
0205 void G4HepEmElectronManager::UpdateNumIALeft(G4HepEmElectronTrack* theElTrack) {
0206 const double pStepLength = theElTrack->GetPStepLength();
0207 G4HepEmTrack* theTrack = theElTrack->GetTrack();
0208 double* numInterALeft = theTrack->GetNumIALeft();
0209 double* preStepMFP = theTrack->GetMFP();
0210 numInterALeft[0] -= pStepLength/preStepMFP[0];
0211 numInterALeft[1] -= pStepLength/preStepMFP[1];
0212 numInterALeft[2] -= pStepLength/preStepMFP[2];
0213 numInterALeft[3] -= pStepLength/preStepMFP[3];
0214 }
0215
0216 bool G4HepEmElectronManager::ApplyMeanEnergyLoss(struct G4HepEmData* hepEmData, struct G4HepEmParameters* hepEmPars, G4HepEmElectronTrack* theElTrack) {
0217 const double pStepLength = theElTrack->GetPStepLength();
0218
0219 G4HepEmTrack* theTrack = theElTrack->GetTrack();
0220 const bool isElectron = (theTrack->GetCharge() < 0.0);
0221 const double theEkin = theTrack->GetEKin();
0222 const double theRange = theElTrack->GetRange();
0223
0224
0225
0226 if (pStepLength >= theRange || theEkin <= hepEmPars->fMinLossTableEnergy) {
0227
0228 theTrack->SetEnergyDeposit(theEkin);
0229 theTrack->SetEKin(0.0);
0230 return true;
0231 }
0232
0233 const G4HepEmElectronData* elData = isElectron
0234 ? hepEmData->fTheElectronData
0235 : hepEmData->fThePositronData;
0236
0237 const int theIMC = theTrack->GetMCIndex();
0238 const double theLEkin = theTrack->GetLogEKin();
0239 double eloss = pStepLength*GetRestDEDX(elData, theIMC, theEkin, theLEkin);
0240
0241 const int indxRegion = hepEmData->fTheMatCutData->fMatCutData[theIMC].fG4RegionIndex;
0242 const double parLinELossLimit = hepEmPars->fParametersPerRegion[indxRegion].fLinELossLimit;
0243 if (eloss > theEkin*parLinELossLimit) {
0244 const double postStepRange = theRange - pStepLength;
0245 eloss = theEkin - GetInvRange(elData, theIMC, postStepRange);
0246 }
0247 eloss = G4HepEmMax(eloss, 0.0);
0248 if (eloss >= theEkin) {
0249 eloss = theEkin;
0250 theTrack->SetEKin(0);
0251 theTrack->SetEnergyDeposit(eloss);
0252 return true;
0253 }
0254
0255 double theEkinAfterMeanEloss = theEkin - eloss;
0256 theTrack->SetEKin(theEkinAfterMeanEloss);
0257 theTrack->SetEnergyDeposit(eloss);
0258 return false;
0259 }
0260
0261 void G4HepEmElectronManager::SampleMSC(struct G4HepEmData* hepEmData, struct G4HepEmParameters* hepEmPars, G4HepEmElectronTrack* theElTrack, G4HepEmRandomEngine* rnge) {
0262 #ifndef NOMSC
0263 const double pStepLength = theElTrack->GetPStepLength();
0264 G4HepEmTrack* theTrack = theElTrack->GetTrack();
0265 const bool isElectron = (theTrack->GetCharge() < 0.0);
0266 const int theIMC = theTrack->GetMCIndex();
0267 const double preStepEkin = theElTrack->GetPreStepEKin();
0268 const double theRange = theElTrack->GetRange();
0269
0270 const G4HepEmElectronData* elData = isElectron
0271 ? hepEmData->fTheElectronData
0272 : hepEmData->fThePositronData;
0273
0274
0275
0276
0277
0278
0279
0280
0281 const double kTLimitMinfix = 1.0E-8;
0282 const double kTauSmall = 1.0e-16;
0283 G4HepEmMSCTrackData* mscData = theElTrack->GetMSCTrackData();
0284 if (mscData->fIsActive && (pStepLength > G4HepEmMax(kTLimitMinfix, kTauSmall*mscData->fLambtr1))) {
0285
0286 double postStepEkin = preStepEkin;
0287 double postStepLEkin = theElTrack->GetPreStepLogEKin();
0288 #if G4VERSION_NUM >= 1100
0289 if (pStepLength > theRange*0.01)
0290 #endif
0291 {
0292
0293
0294
0295 postStepEkin = theTrack->GetEKin();
0296 postStepLEkin = theTrack->GetLogEKin();
0297 }
0298
0299
0300 const int theImat = (hepEmData->fTheMatCutData->fMatCutData[theIMC]).fHepEmMatIndex;
0301 const double postStepTr1mfp = GetTransportMFP(elData, theImat, postStepEkin, postStepLEkin);
0302
0303
0304 const bool isPosCor = hepEmPars->fIsMSCPositronCor;
0305 const bool isDisplace = hepEmPars->fIsMSCDisplacement;
0306 G4HepEmElectronInteractionUMSC::SampleScattering(hepEmData, mscData, pStepLength, preStepEkin, mscData->fLambtr1, postStepEkin, postStepTr1mfp,
0307 theImat, isElectron, isPosCor, isDisplace, rnge);
0308
0309
0310
0311
0312 if (!(mscData->fIsNoScatteringInMSC)) {
0313 RotateToReferenceFrame(mscData->fDirection, theTrack->GetDirection());
0314 if (mscData->fIsDisplace) {
0315 RotateToReferenceFrame(mscData->fDisplacement, theTrack->GetDirection());
0316 }
0317
0318 theTrack->SetDirection(mscData->fDirection);
0319 }
0320 }
0321 #endif
0322 }
0323
0324 bool G4HepEmElectronManager::SampleLossFluctuations(struct G4HepEmData* hepEmData, struct G4HepEmParameters* hepEmPars, G4HepEmElectronTrack* theElTrack, G4HepEmRandomEngine* rnge) {
0325 const double pStepLength = theElTrack->GetPStepLength();
0326 G4HepEmTrack* theTrack = theElTrack->GetTrack();
0327 const bool isElectron = (theTrack->GetCharge() < 0.0);
0328 const int theIMC = theTrack->GetMCIndex();
0329
0330 const double thePreStepEkin = theElTrack->GetPreStepEKin();
0331
0332
0333
0334 double finalEkin = theTrack->GetEKin();
0335 double eloss = theTrack->GetEnergyDeposit();
0336
0337 #ifndef NOFLUCTUATION
0338 const int iregion = hepEmData->fTheMatCutData->fMatCutData[theIMC].fG4RegionIndex;;
0339 const int isFluctuation = hepEmPars->fParametersPerRegion[iregion].fIsELossFluctuation;
0340 const double kFluctParMinEnergy = 1.E-5;
0341 if (isFluctuation && eloss > kFluctParMinEnergy) {
0342 const G4HepEmMCCData& theMatCutData = hepEmData->fTheMatCutData->fMatCutData[theIMC];
0343 const double elCut = theMatCutData.fSecElProdCutE;
0344 const int theImat = theMatCutData.fHepEmMatIndex;
0345 const double meanExE = hepEmData->fTheMaterialData->fMaterialData[theImat].fMeanExEnergy;
0346
0347 const double tmax = isElectron ? 0.5*thePreStepEkin : thePreStepEkin;
0348 const double tcut = G4HepEmMin(elCut, tmax);
0349 eloss = G4HepEmElectronEnergyLossFluctuation::SampleEnergyLossFLuctuation(thePreStepEkin, tcut, tmax,
0350 meanExE, pStepLength, eloss, rnge);
0351 eloss = G4HepEmMax(eloss, 0.0);
0352
0353 finalEkin = thePreStepEkin - eloss;
0354 }
0355 #endif
0356
0357
0358 if (finalEkin <= hepEmPars->fElectronTrackingCut) {
0359 eloss = thePreStepEkin;
0360 finalEkin = 0.0;
0361 theTrack->SetEKin(finalEkin);
0362 theTrack->SetEnergyDeposit(eloss);
0363 return true;
0364 }
0365 theTrack->SetEKin(finalEkin);
0366 theTrack->SetEnergyDeposit(eloss);
0367 return false;
0368 }
0369
0370
0371
0372
0373
0374
0375 bool G4HepEmElectronManager::PerformContinuous(struct G4HepEmData* hepEmData, struct G4HepEmParameters* hepEmPars, G4HepEmElectronTrack* theElTrack, G4HepEmRandomEngine* rnge) {
0376 theElTrack->SavePreStepEKin();
0377
0378
0379 UpdatePStepLength(theElTrack);
0380 const double pStepLength = theElTrack->GetPStepLength();
0381
0382 if (pStepLength<=0.0) {
0383 return false;
0384 }
0385
0386
0387
0388
0389
0390
0391
0392 UpdateNumIALeft(theElTrack);
0393
0394
0395 bool stopped = ApplyMeanEnergyLoss(hepEmData, hepEmPars, theElTrack);
0396 if (stopped) {
0397 return true;
0398 }
0399
0400
0401 SampleMSC(hepEmData, hepEmPars, theElTrack, rnge);
0402
0403
0404 return SampleLossFluctuations(hepEmData, hepEmPars, theElTrack, rnge);
0405 }
0406
0407
0408 bool G4HepEmElectronManager::CheckDelta(struct G4HepEmData* hepEmData, G4HepEmTrack* theTrack, double rand) {
0409 const bool isElectron = (theTrack->GetCharge() < 0.0);
0410 const G4HepEmElectronData* elData = isElectron
0411 ? hepEmData->fTheElectronData
0412 : hepEmData->fThePositronData;
0413 const int iDProc = theTrack->GetWinnerProcessIndex();
0414 const int theIMC = theTrack->GetMCIndex();
0415 const int theMatIndex = hepEmData->fTheMatCutData->fMatCutData[theIMC].fHepEmMatIndex;
0416 const double theEkin = theTrack->GetEKin();
0417 const double theLEkin = theTrack->GetLogEKin();
0418 const double mxsec = (iDProc<2 ? GetRestMacXSec(elData, theIMC, theEkin, theLEkin, iDProc==0) :
0419 (iDProc<3 ? ComputeMacXsecAnnihilation(theEkin, hepEmData->fTheMaterialData->fMaterialData[theMatIndex].fElectronDensity)
0420 : GetMacXSecNuclear(elData, theMatIndex, theEkin, theLEkin))
0421 );
0422 return mxsec <= 0.0 || rand > mxsec*theTrack->GetMFP(iDProc);
0423 }
0424
0425 void G4HepEmElectronManager::PerformDiscrete(struct G4HepEmData* hepEmData, struct G4HepEmParameters* hepEmPars, G4HepEmTLData* tlData) {
0426 G4HepEmElectronTrack* theElTrack = tlData->GetPrimaryElectronTrack();
0427 G4HepEmTrack* theTrack = theElTrack->GetTrack();
0428 const bool isElectron = (theTrack->GetCharge() < 0.0);
0429
0430
0431
0432 const int iDProc = theTrack->GetWinnerProcessIndex();
0433 if (iDProc < 0 || theTrack->GetOnBoundary()) {
0434 return;
0435 }
0436
0437 theTrack->SetNumIALeft(-1.0, iDProc);
0438
0439
0440 if (CheckDelta(hepEmData, theTrack, tlData->GetRNGEngine()->flat())) {
0441 return;
0442 }
0443
0444
0445 const double theEkin = theTrack->GetEKin();
0446 switch (iDProc) {
0447 case 0:
0448 G4HepEmElectronInteractionIoni::Perform(tlData, hepEmData, isElectron);
0449 break;
0450 case 1:
0451 G4HepEmElectronInteractionBrem::Perform(tlData, hepEmData, isElectron, theEkin < hepEmPars->fElectronBremModelLim);
0452 break;
0453 case 2:
0454 G4HepEmPositronInteractionAnnihilation::Perform(tlData, false);
0455 break;
0456 case 3:
0457 break;
0458 }
0459 }
0460
0461 void G4HepEmElectronManager::Perform(struct G4HepEmData* hepEmData, struct G4HepEmParameters* hepEmPars, G4HepEmTLData* tlData) {
0462 G4HepEmElectronTrack* theElTrack = tlData->GetPrimaryElectronTrack();
0463 G4HepEmTrack* theTrack = theElTrack->GetTrack();
0464
0465
0466 theTrack->SetEnergyDeposit(0);
0467 theElTrack->SetPStepLength(theTrack->GetGStepLength());
0468 const bool isElectron = (theTrack->GetCharge() < 0.0);
0469
0470 if (theTrack->GetGStepLength()<=0.) return;
0471
0472 bool stopped = PerformContinuous(hepEmData, hepEmPars, theElTrack, tlData->GetRNGEngine());
0473 if (stopped) {
0474
0475 if (!isElectron) {
0476 G4HepEmPositronInteractionAnnihilation::Perform(tlData, true);
0477 }
0478 return;
0479 }
0480
0481
0482 PerformDiscrete(hepEmData, hepEmPars, tlData);
0483 }
0484
0485
0486 double G4HepEmElectronManager::GetRestRange(const struct G4HepEmElectronData* elData, const int imc, const double ekin, const double lekin) {
0487 const int numELossData = elData->fELossEnergyGridSize;
0488 const int iRangeStarts = 5*numELossData*imc;
0489
0490 const double range = GetSplineLog(numELossData, elData->fELossEnergyGrid, &(elData->fELossData[iRangeStarts]), ekin, lekin, elData->fELossLogMinEkin, elData->fELossEILDelta);
0491 return G4HepEmMax(0.0, range);
0492 }
0493
0494
0495 double G4HepEmElectronManager::GetRestDEDX(const struct G4HepEmElectronData* elData, const int imc, const double ekin, const double lekin) {
0496 const int numELossData = elData->fELossEnergyGridSize;
0497 const int iDEDXStarts = numELossData*(5*imc + 2);
0498
0499 const double dedx = GetSplineLog(numELossData, elData->fELossEnergyGrid, &(elData->fELossData[iDEDXStarts]), ekin, lekin, elData->fELossLogMinEkin, elData->fELossEILDelta);
0500 return G4HepEmMax(0.0, dedx);
0501 }
0502
0503
0504 double G4HepEmElectronManager::GetInvRange(const struct G4HepEmElectronData* elData, int imc, double range) {
0505 const int numELossData = elData->fELossEnergyGridSize;
0506 const int iRangeStarts = 5*numELossData*imc;
0507
0508 const double minRange = elData->fELossData[iRangeStarts];
0509 if (range<minRange) {
0510 const double dum = range/minRange;
0511 return G4HepEmMax(0.0, elData->fELossEnergyGrid[0]*dum*dum);
0512 }
0513
0514
0515 const int iRlow = FindLowerBinIndex(&(elData->fELossData[iRangeStarts]), numELossData, range, 2);
0516
0517 const double energy = GetSpline(&(elData->fELossData[iRangeStarts]), elData->fELossEnergyGrid, &(elData->fELossData[iRangeStarts+4*numELossData]), range, iRlow, 2);
0518 return G4HepEmMax(0.0, energy);
0519 }
0520
0521
0522 double G4HepEmElectronManager::GetRestMacXSec(const struct G4HepEmElectronData* elData, const int imc, const double ekin, const double lekin, bool isioni) {
0523 const int iIoniStarts = elData->fResMacXSecStartIndexPerMatCut[imc];
0524 const int numIoniData = elData->fResMacXSecData[iIoniStarts];
0525 const int iStart = (isioni) ? iIoniStarts : iIoniStarts + 3*numIoniData + 5;
0526 const int numData = elData->fResMacXSecData[iStart];
0527 const double minEKin = elData->fResMacXSecData[iStart+5];
0528 if (ekin<minEKin) {return 0.0; }
0529
0530 const double mxsec = GetSplineLog(numData, &(elData->fResMacXSecData[iStart+5]), ekin, lekin, elData->fResMacXSecData[iStart+3],elData->fResMacXSecData[iStart+4]);
0531 return G4HepEmMax(0.0, mxsec);
0532 }
0533
0534 double G4HepEmElectronManager::GetMacXSecNuclear(const struct G4HepEmElectronData* elData, const int imat, const double ekin, const double lekin) {
0535 if (ekin < elData->fENucEnergyGrid[0]) { return 0.0; }
0536 const int numEKin = elData->fENucEnergyGridSize;
0537 const int iStartMat = imat*2*numEKin;
0538
0539 const double mxsec = GetSplineLog(numEKin, elData->fENucEnergyGrid, &(elData->fENucMacXsecData[iStartMat]), ekin, lekin, elData->fENucLogMinEkin, elData->fENucEILDelta);
0540 return G4HepEmMax(0.0, mxsec);
0541 }
0542
0543
0544 double G4HepEmElectronManager::GetRestMacXSecForStepping(const struct G4HepEmElectronData* elData, const int imc, double ekin, double lekin, bool isioni) {
0545 constexpr double log08 = -0.22314355131420971;
0546 const int iIoniStarts = elData->fResMacXSecStartIndexPerMatCut[imc];
0547 const int numIoniData = elData->fResMacXSecData[iIoniStarts];
0548 const int iStart = (isioni) ? iIoniStarts : iIoniStarts + 3*numIoniData + 5;
0549 const int numData = elData->fResMacXSecData[iStart];
0550 const double mxsecMinE = elData->fResMacXSecData[iStart+5];
0551 const double mxsecMaxE = elData->fResMacXSecData[iStart+1];
0552 const double mxsecMaxV = elData->fResMacXSecData[iStart+2];
0553 if (ekin > mxsecMaxE) {
0554
0555 const double ekinReduced = 0.8 * ekin;
0556 if (ekinReduced < mxsecMaxE) {
0557 return G4HepEmMax(0.0, mxsecMaxV);
0558 } else {
0559
0560 ekin = ekinReduced;
0561 lekin += log08;
0562 }
0563 }
0564 if (ekin<mxsecMinE) {return 0.0; }
0565
0566 const double mxsec = GetSplineLog(numData, &(elData->fResMacXSecData[iStart+5]), ekin, lekin, elData->fResMacXSecData[iStart+3], elData->fResMacXSecData[iStart+4]);
0567 return G4HepEmMax(0.0, mxsec);
0568 }
0569
0570 double G4HepEmElectronManager::GetMacXSecNuclearForStepping(const struct G4HepEmElectronData* elData, const int imat, const double ekin, const double lekin) {
0571
0572 return GetMacXSecNuclear(elData, imat, ekin, lekin);
0573 }
0574
0575
0576 double G4HepEmElectronManager::GetTransportMFP(const struct G4HepEmElectronData* elData, const int im, const double ekin, const double lekin) {
0577 const int numEkin = elData->fELossEnergyGridSize;
0578 const int iStarts = 2*numEkin*im;
0579
0580 const double tr1mxsec = G4HepEmMax(0.0, GetSplineLog(numEkin, elData->fELossEnergyGrid, &(elData->fTr1MacXSecData[iStarts]), ekin, lekin, elData->fELossLogMinEkin, elData->fELossEILDelta));
0581 return tr1mxsec > 0. ? 1./tr1mxsec : kALargeValue;
0582 }
0583
0584
0585 double G4HepEmElectronManager::ComputeMacXsecAnnihilation(const double ekin, const double electronDensity) {
0586
0587 const double tau = ekin*kInvElectronMassC2;
0588 const double gam = tau + 1.0;
0589 const double gam2 = gam*gam;
0590 const double bg2 = tau * (tau+2.0);
0591 const double bg = std::sqrt(bg2);
0592 return electronDensity*kPir02*((gam2+4.*gam+1.)*G4HepEmLog(gam+bg) - (gam+3.)*bg) / (bg2*(gam+1.));
0593 }
0594
0595
0596 double G4HepEmElectronManager::ComputeMacXsecAnnihilationForStepping(const double ekin, const double electronDensity) {
0597
0598 return ComputeMacXsecAnnihilation(0.8*ekin, electronDensity);
0599 }
0600
0601
0602 void G4HepEmElectronManager::ConvertTrueToGeometricLength(const G4HepEmData* hepEmData, G4HepEmMSCTrackData* mscData,
0603 double ekin, double range, int imc, bool iselectron) {
0604 mscData->fPar1 = -1.;
0605 mscData->fPar2 = 0.;
0606 mscData->fPar3 = 0.;
0607
0608
0609
0610
0611 mscData->fTrueStepLength = G4HepEmMin(mscData->fTrueStepLength, range);
0612
0613 mscData->fZPathLength = mscData->fTrueStepLength;
0614
0615 const double kTlimitMinfix2 = 1.0E-6;
0616 if (mscData->fTrueStepLength < kTlimitMinfix2) {
0617 return;
0618 }
0619
0620 const double kTauSmall = 1.0e-16;
0621 const double kDtrl = 0.05;
0622 const double tau = mscData->fTrueStepLength / mscData->fLambtr1;
0623 if (tau < kTauSmall) {
0624 mscData->fZPathLength = G4HepEmMin(mscData->fTrueStepLength, mscData->fLambtr1);
0625 } else if (mscData->fTrueStepLength < range * kDtrl) {
0626 const double kTauLim = 1.0e-6;
0627 mscData->fZPathLength = (tau < kTauLim)
0628 ? mscData->fTrueStepLength * (1. - 0.5 * tau)
0629 : mscData->fLambtr1 * (1. - G4HepEmExp(-tau));
0630 } else if (ekin < kElectronMassC2 || mscData->fTrueStepLength == range) {
0631 mscData->fPar1 = 1. / range;
0632 mscData->fPar2 = 1. / (mscData->fPar1 * mscData->fLambtr1);
0633 mscData->fPar3 = 1. + mscData->fPar2;
0634 mscData->fZPathLength = 1. / (mscData->fPar1 * mscData->fPar3);
0635 if (mscData->fTrueStepLength < range) {
0636 mscData->fZPathLength *= (1. - G4HepEmPow(1. - mscData->fTrueStepLength/range, mscData->fPar3));
0637 }
0638 } else {
0639 const double rfin = G4HepEmMax(range - mscData->fTrueStepLength, 0.01 * range);
0640 const G4HepEmElectronData* elData = iselectron ? hepEmData->fTheElectronData : hepEmData->fThePositronData;
0641 const double t1 = GetInvRange(elData, imc, rfin);
0642 const int imat = (hepEmData->fTheMatCutData->fMatCutData[imc]).fHepEmMatIndex;
0643 const double lambda1 = GetTransportMFP(elData, imat, t1, G4HepEmLog(t1));
0644 mscData->fPar1 = (mscData->fLambtr1 - lambda1) / (mscData->fLambtr1 * mscData->fTrueStepLength);
0645 mscData->fPar2 = 1. / (mscData->fPar1 * mscData->fLambtr1);
0646 mscData->fPar3 = 1. + mscData->fPar2;
0647 mscData->fZPathLength = (1. - G4HepEmPow(lambda1/mscData->fLambtr1, mscData->fPar3))/(mscData->fPar1 * mscData->fPar3);
0648 }
0649 mscData->fZPathLength = G4HepEmMin(mscData->fZPathLength, mscData->fLambtr1);
0650 }
0651
0652
0653 void G4HepEmElectronManager::ConvertGeometricToTrueLength(G4HepEmMSCTrackData* mscData, double range, double gStepToConvert) {
0654
0655
0656
0657
0658
0659
0660
0661
0662
0663 mscData->fZPathLength = gStepToConvert;
0664
0665 const double kTLimitMinfix2 = 1.0E-6;
0666 if (gStepToConvert < kTLimitMinfix2) {
0667 mscData->fTrueStepLength = gStepToConvert;
0668 } else {
0669
0670 const double kTauSmall = 1.0e-16;
0671 double tlength = gStepToConvert;
0672 if (gStepToConvert > mscData->fLambtr1 * kTauSmall) {
0673 if (mscData->fPar1 < 0.) {
0674 tlength = -mscData->fLambtr1 * G4HepEmLog(1. - gStepToConvert / mscData->fLambtr1);
0675 } else {
0676 const double dum = mscData->fPar1 * mscData->fPar3 * gStepToConvert;
0677 if (dum < 1.) {
0678 tlength = (1. - G4HepEmPow(1.-dum, 1./mscData->fPar3)) / mscData->fPar1;
0679 } else {
0680 tlength = range;
0681 }
0682 }
0683 if (tlength < gStepToConvert) {
0684 tlength = gStepToConvert;
0685 }
0686 }
0687
0688
0689 mscData->fTrueStepLength = tlength;
0690 }
0691 }