File indexing completed on 2026-07-13 08:21:04
0001
0002 #include "G4HepEmElectronInteractionBrem.hh"
0003
0004 #include "G4HepEmTLData.hh"
0005 #include "G4HepEmData.hh"
0006 #include "G4HepEmMatCutData.hh"
0007 #include "G4HepEmMaterialData.hh"
0008 #include "G4HepEmElementData.hh"
0009 #include "G4HepEmElectronData.hh"
0010 #include "G4HepEmSBTableData.hh"
0011
0012 #include "G4HepEmElectronTrack.hh"
0013 #include "G4HepEmGammaTrack.hh"
0014 #include "G4HepEmConstants.hh"
0015 #include "G4HepEmRunUtils.hh"
0016
0017 #include "G4HepEmInteractionUtils.hh"
0018
0019 #include "G4HepEmMath.hh"
0020
0021 #include <cmath>
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 void G4HepEmElectronInteractionBrem::Perform(G4HepEmTLData* tlData, struct G4HepEmData* hepEmData,
0036 bool iselectron, bool isSBmodel) {
0037
0038 G4HepEmElectronTrack* thePrimaryElTrack = tlData->GetPrimaryElectronTrack();
0039 G4HepEmTrack* thePrimaryTrack = thePrimaryElTrack->GetTrack();
0040
0041 double thePrimEkin = thePrimaryTrack->GetEKin();
0042 const double theLogEkin = thePrimaryTrack->GetLogEKin();
0043 const int theMCIndx = thePrimaryTrack->GetMCIndex();
0044 const G4HepEmMCCData& theMCData = hepEmData->fTheMatCutData->fMatCutData[theMCIndx];
0045 const double theGamCut = theMCData.fSecGamProdCutE;
0046
0047 if (thePrimEkin <= theGamCut) return;
0048
0049
0050 const double eGamma = isSBmodel
0051 ? SampleETransferSB(hepEmData, thePrimEkin, theLogEkin, theMCIndx, tlData->GetRNGEngine(), iselectron)
0052 : SampleETransferRB(hepEmData, thePrimEkin, theLogEkin, theMCIndx, tlData->GetRNGEngine(), iselectron);
0053
0054 G4HepEmTrack* theSecTrack = tlData->AddSecondaryGammaTrack()->GetTrack();
0055 double* theSecGammaDir = theSecTrack->GetDirection();
0056 double* thePrimElecDir = thePrimaryTrack->GetDirection();
0057
0058
0059 SampleDirections(thePrimEkin, eGamma, theSecGammaDir, thePrimElecDir, tlData->GetRNGEngine());
0060
0061
0062
0063 thePrimaryTrack->SetEKin(thePrimEkin - eGamma);
0064 theSecTrack->SetEKin(eGamma);
0065 theSecTrack->SetParentID(thePrimaryTrack->GetID());
0066
0067
0068
0069
0070 }
0071
0072
0073 double G4HepEmElectronInteractionBrem::SampleETransferSB(struct G4HepEmData* hepEmData, double thePrimEkin,
0074 double theLogEkin, int theMCIndx,
0075 G4HepEmRandomEngine* rnge, bool iselectron) {
0076 const G4HepEmMCCData& theMCData = hepEmData->fTheMatCutData->fMatCutData[theMCIndx];
0077 const double theGamCut = theMCData.fSecGamProdCutE;
0078 const double theLogGamCut = theMCData.fLogSecGamCutE;
0079 const G4HepEmMatData& theMData = hepEmData->fTheMaterialData->fMaterialData[theMCData.fHepEmMatIndex];
0080
0081 const G4HepEmElectronData* theElData = iselectron ? hepEmData->fTheElectronData : hepEmData->fThePositronData;
0082 const int elemIndx = (theMData.fNumOfElement > 1)
0083 ? SelectTargetAtom(theElData, theMCIndx, thePrimEkin, theLogEkin, rnge->flat(), true)
0084 : 0;
0085 const int iZet = theMData.fElementVect[elemIndx];
0086 const double dZet = (double)iZet;
0087
0088
0089
0090 const G4HepEmSBTableData* theSBTables = hepEmData->fTheSBTableData;
0091
0092 const int iStart = theSBTables->fSBTablesStartPerZ[iZet];
0093
0094 const int iGamCut = theSBTables->fGammaCutIndices[theSBTables->fGammaCutIndxStartIndexPerMC[theMCIndx]+elemIndx];
0095
0096
0097 bool isCorner = false;
0098 bool isSimply = false;
0099 int elEnergyIndx = (int)(theSBTables->fSBTableData[iStart+2]);
0100
0101 if (thePrimEkin < theSBTables->fElEnergyVect[elEnergyIndx]) {
0102 const double val = (theLogEkin-theSBTables->fLogMinElEnergy)*theSBTables->fILDeltaElEnergy;
0103 elEnergyIndx = (int)val;
0104 double pIndxH = val-elEnergyIndx;
0105
0106 if (theSBTables->fElEnergyVect[elEnergyIndx] <= theGamCut) {
0107
0108 pIndxH = (theLogEkin-theLogGamCut)/(theSBTables->fLElEnergyVect[elEnergyIndx+1]-theLogGamCut);
0109 isCorner = true;
0110 }
0111
0112 if (rnge->flat()<pIndxH) {
0113 ++elEnergyIndx;
0114 } else if (isCorner) {
0115
0116
0117 isSimply = true;
0118 }
0119 }
0120
0121 const int minEIndx = (int)(theSBTables->fSBTableData[iStart+1]);
0122 const int numGamCuts = (int)(theSBTables->fSBTableData[iStart+3]);
0123 const int sizeOneE = (int)(numGamCuts + 3*theSBTables->fNumKappa);
0124 const int iSTStart = iStart + 4 + (elEnergyIndx-minEIndx)*sizeOneE;
0125
0126 const double minV = theSBTables->fSBTableData[iSTStart+iGamCut];
0127
0128 const double* stData = &(theSBTables->fSBTableData[iSTStart+numGamCuts]);
0129
0130
0131
0132 const double lKTrans = (theLogGamCut-theLogEkin)/(theLogGamCut-theSBTables->fLElEnergyVect[elEnergyIndx]);
0133
0134 const double primETot = thePrimEkin + kElectronMassC2;
0135 const double dielSupConst = theMData.fDensityCorFactor*primETot*primETot;
0136 double suppression = 1.0;
0137 double rndm[2];
0138
0139 double eGamma = 0.0;
0140 do {
0141 rnge->flatArray(2, rndm);
0142 double kappa = 1.0;
0143 if (!isSimply) {
0144 const double cumRV = rndm[0]*(1.0-minV)+minV;
0145
0146
0147
0148 const int cumLIndx3 = LinSearch(stData, theSBTables->fNumKappa, cumRV) - 3;
0149 const int cumLIndx = cumLIndx3/3;
0150 const double cumL = stData[cumLIndx3];
0151 const double pA = stData[cumLIndx3+1];
0152 const double pB = stData[cumLIndx3+2];
0153 const double cumH = stData[cumLIndx3+3];
0154 const double lKL = theSBTables->fLKappaVect[cumLIndx];
0155 const double lKH = theSBTables->fLKappaVect[cumLIndx+1];
0156 const double dm1 = (cumRV-cumL)/(cumH-cumL);
0157 const double dm2 = (1.0+pA+pB)*dm1;
0158 const double dm3 = 1.0+dm1*(pA+pB*dm1);
0159
0160 const double lKappa = lKL+dm2/dm3*(lKH-lKL);
0161
0162 kappa = G4HepEmExp(lKappa*lKTrans);
0163 } else {
0164 kappa = 1.0-rndm[0]*(1.0-theGamCut/thePrimEkin);
0165 }
0166
0167 eGamma = kappa*thePrimEkin;
0168 const double invEGamma = 1.0/eGamma;
0169
0170 suppression = 1.0/(1.0+dielSupConst*invEGamma*invEGamma);
0171
0172 if (!iselectron) {
0173 const double e1 = thePrimEkin - theGamCut;
0174 const double iBeta1 = (e1 + kElectronMassC2) / std::sqrt(e1*(e1 + 2.0*kElectronMassC2));
0175 const double e2 = thePrimEkin - eGamma;
0176 const double iBeta2 = (e2 + kElectronMassC2) / std::sqrt(e2*(e2 + 2.0*kElectronMassC2));
0177 const double dum = kAlpha*k2Pi*dZet*(iBeta1 - iBeta2);
0178 suppression = (dum > -12.) ? suppression*G4HepEmExp(dum) : 0.;
0179 }
0180 } while (rndm[1] > suppression);
0181 return eGamma;
0182 }
0183
0184 double G4HepEmElectronInteractionBrem::SampleETransferRB(struct G4HepEmData* hepEmData, double thePrimEkin,
0185 double theLogEkin, int theMCIndx,
0186 G4HepEmRandomEngine* rnge, bool iselectron) {
0187 const G4HepEmMCCData& theMCData = hepEmData->fTheMatCutData->fMatCutData[theMCIndx];
0188 const double theGamCut = theMCData.fSecGamProdCutE;
0189
0190
0191
0192 const G4HepEmMatData& theMData = hepEmData->fTheMaterialData->fMaterialData[theMCData.fHepEmMatIndex];
0193
0194 const G4HepEmElectronData* theElData = iselectron ? hepEmData->fTheElectronData : hepEmData->fThePositronData;
0195 const int elemIndx = (theMData.fNumOfElement > 1)
0196 ? SelectTargetAtom(theElData, theMCIndx, thePrimEkin, theLogEkin, rnge->flat(), false)
0197 : 0;
0198 const int iZet = theMData.fElementVect[elemIndx];
0199 const double dZet = (double)iZet;
0200 const G4HepEmElemData& theElemData = hepEmData->fTheElementData->fElementData[G4HepEmMin(iZet, hepEmData->fTheElementData->fMaxZet)];
0201
0202
0203
0204 const double densityFactor = kMigdalConst * theMData.fElectronDensity;
0205 const double lpmEnergy = kLPMconstant * theMData.fRadiationLength;
0206
0207 const double lpmEnergyLim = std::sqrt(densityFactor) * lpmEnergy;
0208
0209 const double thePrimTotalE = thePrimEkin + kElectronMassC2;
0210 const double densityCorr = densityFactor * thePrimTotalE * thePrimTotalE;
0211
0212 const bool isLPMActive = (thePrimTotalE > lpmEnergyLim) ;
0213
0214 const double zFactor1 = theElemData.fZFactor1;
0215 const double zFactor2 = (1.+1./dZet)/12.;
0216 const double rejFuncMax = zFactor1 + zFactor2;
0217
0218 const double xmin = G4HepEmLog( theGamCut*theGamCut + densityCorr );
0219 const double xrange = G4HepEmLog( thePrimEkin*thePrimEkin + densityCorr ) - xmin;
0220
0221 double rndm[2];
0222 double eGamma, funcVal;
0223 do {
0224 rnge->flatArray(2, rndm);
0225 eGamma = std::sqrt( G4HepEmMax( G4HepEmExp( xmin + rndm[0] * xrange ) - densityCorr, 0.0 ) );
0226
0227 const double y = eGamma / thePrimTotalE;
0228 const double onemy = 1.-y;
0229 const double dum0 = 0.25*y*y;
0230 if ( isLPMActive ) {
0231
0232 double funcGS, funcPhiS, funcXiS;
0233 EvaluateLPMFunctions(funcXiS, funcGS, funcPhiS, eGamma, thePrimTotalE, lpmEnergy, theElemData.fZet23, theElemData.fILVarS1, theElemData.fILVarS1Cond, densityCorr, 1.0);
0234 const double term1 = funcXiS * ( dum0 * funcGS + (onemy+2.0*dum0) * funcPhiS );
0235 funcVal = term1*zFactor1 + onemy*zFactor2;
0236 } else {
0237 const double dum1 = onemy + 3.*dum0;
0238 if ( iZet < 5 ) {
0239 funcVal = dum1 * zFactor1 + onemy * zFactor2;
0240 } else {
0241 const double dum2 = y / ( thePrimTotalE - eGamma );
0242 const double gam = dum2 * 100.*kElectronMassC2 / theElemData.fZet13;
0243 const double eps = gam / theElemData.fZet13;
0244
0245
0246 const double gam2 = gam*gam;
0247 const double phi1 = 16.863-2.0*G4HepEmLog(1.0+0.311877*gam2)+2.4*G4HepEmExp(-0.9*gam)+1.6*G4HepEmExp(-1.5*gam);
0248 const double phi2 = 2.0/(3.0+19.5*gam+18.0*gam2);
0249 const double eps2 = eps*eps;
0250 const double psi1 = 24.34-2.0*G4HepEmLog(1.0+13.111641*eps2)+2.8*G4HepEmExp(-8.0*eps)+1.2*G4HepEmExp(-29.2*eps);
0251 const double psi2 = 2.0/(3.0+120.0*eps+1200.0*eps2);
0252
0253 const double logZ = theElemData.fLogZ;
0254 const double Fz = logZ/3. + theElemData.fCoulomb;
0255 const double invZ = 1./dZet;
0256 funcVal = dum1*((0.25*phi1-Fz) + (0.25*psi1-2.*logZ/3.)*invZ) + 0.125*onemy*(phi2 + psi2*invZ);
0257 }
0258 }
0259 funcVal = G4HepEmMax( 0.0, funcVal);
0260 } while ( funcVal < rejFuncMax * rndm[1] );
0261 return eGamma;
0262 }
0263
0264
0265
0266 int G4HepEmElectronInteractionBrem::SelectTargetAtom(const struct G4HepEmElectronData* elData, const int imc,
0267 const double ekin, const double lekin, const double urndn,
0268 const bool isbremSB) {
0269
0270 const int indxStart = isbremSB
0271 ? elData->fElemSelectorBremSBStartIndexPerMatCut[imc]
0272 : elData->fElemSelectorBremRBStartIndexPerMatCut[imc];
0273 const double* theData = isbremSB
0274 ? &(elData->fElemSelectorBremSBData[indxStart])
0275 : &(elData->fElemSelectorBremRBData[indxStart]);
0276 const int numData = theData[0];
0277 const int numElem = theData[1];
0278 const double logE0 = theData[2];
0279 const double invLD = theData[3];
0280 const double* xdata = &(theData[4]);
0281
0282 const double xv = G4HepEmMax(xdata[0], G4HepEmMin(xdata[numElem*(numData-1)], ekin));
0283
0284 const int idxEkin = G4HepEmMax(0.0, G4HepEmMin((lekin-logE0)*invLD, numData-2.0));
0285
0286 int indx0 = idxEkin*numElem;
0287 int indx1 = indx0+numElem;
0288
0289 const double x1 = xdata[indx0++];
0290 const double x2 = xdata[indx1++];
0291 const double dl = x2-x1;
0292 const double b = G4HepEmMax(0., G4HepEmMin(1., (xv - x1)/dl));
0293 int theElemIndex = 0;
0294 while (theElemIndex<numElem-1 && urndn > xdata[indx0+theElemIndex]+b*(xdata[indx1+theElemIndex]-xdata[indx0+theElemIndex])) { ++theElemIndex; }
0295 return theElemIndex;
0296 }
0297
0298
0299 void G4HepEmElectronInteractionBrem::SampleDirections(const double thePrimEkin, const double theSecGammaEkin,
0300 double* theSecGammaDir, double* thePrimElecDir,
0301 G4HepEmRandomEngine* rnge) {
0302
0303 const double cost = SampleCostModifiedTsai(thePrimEkin, rnge);
0304 const double sint = std::sqrt((1.0-cost)*(1.0+cost));
0305 const double phi = k2Pi*rnge->flat();
0306 theSecGammaDir[0] = sint * std::cos(phi);
0307 theSecGammaDir[1] = sint * std::sin(phi);
0308 theSecGammaDir[2] = cost;
0309
0310 RotateToReferenceFrame(theSecGammaDir, thePrimElecDir);
0311
0312 const double primETot = thePrimEkin + kElectronMassC2;
0313 const double primPTot = std::sqrt(thePrimEkin * (primETot + kElectronMassC2));
0314 thePrimElecDir[0] = primPTot * thePrimElecDir[0] - theSecGammaEkin * theSecGammaDir[0];
0315 thePrimElecDir[1] = primPTot * thePrimElecDir[1] - theSecGammaEkin * theSecGammaDir[1];
0316 thePrimElecDir[2] = primPTot * thePrimElecDir[2] - theSecGammaEkin * theSecGammaDir[2];
0317
0318 const double norm = 1.0 / std::sqrt(thePrimElecDir[0] * thePrimElecDir[0] + thePrimElecDir[1] * thePrimElecDir[1] + thePrimElecDir[2] * thePrimElecDir[2]);
0319 thePrimElecDir[0] *= norm;
0320 thePrimElecDir[1] *= norm;
0321 thePrimElecDir[2] *= norm;
0322 }
0323
0324
0325
0326
0327
0328 int G4HepEmElectronInteractionBrem::LinSearch(const double* vect, const int size, const double val) {
0329 int i = 0;
0330 const int size3 = 3*size;
0331 while (i + 9 < size3) {
0332 if (vect [i + 0] > val) return i + 0;
0333 if (vect [i + 3] > val) return i + 3;
0334 if (vect [i + 6] > val) return i + 6;
0335 if (vect [i + 9] > val) return i + 9;
0336 i += 12;
0337 }
0338 while (i < size3) {
0339 if (vect [i] > val)
0340 break;
0341 i += 3;
0342 }
0343 return i;
0344 }