File indexing completed on 2026-07-13 08:21:04
0001 #include "G4HepEmGammaInteractionConversion.hh"
0002
0003 #include "G4HepEmTLData.hh"
0004 #include "G4HepEmRandomEngine.hh"
0005 #include "G4HepEmData.hh"
0006 #include "G4HepEmMatCutData.hh"
0007 #include "G4HepEmMaterialData.hh"
0008 #include "G4HepEmElementData.hh"
0009 #include "G4HepEmGammaData.hh"
0010
0011 #include "G4HepEmConstants.hh"
0012 #include "G4HepEmInteractionUtils.hh"
0013 #include "G4HepEmRunUtils.hh"
0014
0015 #include "G4HepEmMath.hh"
0016
0017 #include <iostream>
0018
0019 void G4HepEmGammaInteractionConversion::Perform(G4HepEmTLData* tlData, struct G4HepEmData* hepEmData) {
0020 G4HepEmTrack* thePrimaryTrack = tlData->GetPrimaryGammaTrack()->GetTrack();
0021 const double thePrimGmE = thePrimaryTrack->GetEKin();
0022
0023
0024
0025 if (thePrimGmE < 2.*kElectronMassC2) {
0026 return;
0027 }
0028
0029
0030 const double theLogPrimGmE = thePrimaryTrack->GetLogEKin();
0031 const int theMCIndx = thePrimaryTrack->GetMCIndex();
0032 double elKinEnergy;
0033 double posKinEnergy;
0034 SampleKinEnergies(hepEmData, thePrimGmE, theLogPrimGmE, theMCIndx, elKinEnergy, posKinEnergy, tlData->GetRNGEngine());
0035
0036
0037
0038 G4HepEmTrack* theSecElTrack = tlData->AddSecondaryElectronTrack()->GetTrack();
0039 G4HepEmTrack* theSecPosTrack = tlData->AddSecondaryElectronTrack()->GetTrack();
0040 SampleDirections(thePrimaryTrack->GetDirection(), theSecElTrack->GetDirection(), theSecPosTrack->GetDirection(),
0041 elKinEnergy, posKinEnergy, tlData->GetRNGEngine());
0042
0043
0044 theSecElTrack->SetEKin(elKinEnergy);
0045 theSecElTrack->SetParentID(thePrimaryTrack->GetID());
0046 theSecPosTrack->SetEKin(posKinEnergy);
0047 theSecPosTrack->SetParentID(thePrimaryTrack->GetID());
0048 theSecPosTrack->SetCharge(+1.0);
0049
0050
0051
0052 thePrimaryTrack->SetEKin(0.0);
0053 }
0054
0055
0056 void G4HepEmGammaInteractionConversion::SampleKinEnergies(struct G4HepEmData* hepEmData, double thePrimEkin,
0057 double theLogEkin, int theMCIndx, double& eKinEnergy,
0058 double& pKinEnergy, G4HepEmRandomEngine* rnge) {
0059
0060 const int matIndx = (hepEmData->fTheMatCutData->fMatCutData[theMCIndx]).fHepEmMatIndex;
0061 const G4HepEmMatData& theMData = hepEmData->fTheMaterialData->fMaterialData[matIndx];
0062
0063 const int elemIndx = (theMData.fNumOfElement > 1)
0064 ? SelectTargetAtom(hepEmData->fTheGammaData, matIndx, thePrimEkin, theLogEkin, rnge->flat())
0065 : 0;
0066 const int iZet = theMData.fElementVect[elemIndx];
0067 const double lpmEnr = kLPMconstant * theMData.fRadiationLength;
0068
0069
0070 const G4HepEmElemData& theElemData = hepEmData->fTheElementData->fElementData[G4HepEmMin(iZet, hepEmData->fTheElementData->fMaxZet)];
0071
0072
0073
0074 const double eps0 = kElectronMassC2/thePrimEkin;
0075 double eps = 0.0;
0076 if (thePrimEkin < 2.0) {
0077
0078
0079 eps = eps0 + (0.5-eps0)*rnge->flat();
0080 } else {
0081
0082 const double deltaFactor = eps0*136./theElemData.fZet13;
0083 const double deltaMin = 4.*deltaFactor;
0084 const double deltaMax = (thePrimEkin < 50.0) ? theElemData.fDeltaMaxLow : theElemData.fDeltaMaxHigh;
0085 const double logZ13 = 0.333333*theElemData.fLogZ;
0086 const double FZ = (thePrimEkin < 50.0) ? 8.*logZ13 : 8.*(logZ13 + theElemData.fCoulomb);
0087
0088 const double epsp = 0.5 - 0.5*std::sqrt(1. - deltaMin/deltaMax) ;
0089 const double epsMin = G4HepEmMax(eps0, epsp);
0090 const double epsRange = 0.5 - epsMin;
0091
0092
0093 double F10, F20;
0094 ScreenFunction12(deltaMin, F10, F20);
0095 F10 -= FZ;
0096 F20 -= FZ;
0097 const double NormF1 = G4HepEmMax(F10 * epsRange * epsRange, 0.);
0098 const double NormF2 = G4HepEmMax(1.5 * F20 , 0.);
0099 const double NormCond = NormF1/(NormF1 + NormF2);
0100
0101 eps = (thePrimEkin < 100000.0)
0102 ? SampleEnergyRateNoLPM (NormCond, epsMin, epsRange, deltaFactor, 1./F10, 1./F20, FZ, rnge)
0103 : SampleEnergyRateWithLPM(NormCond, epsMin, epsRange, deltaFactor, 1./F10, 1./F20, FZ, rnge,
0104 thePrimEkin, lpmEnr, &theElemData);
0105 }
0106
0107
0108 double eTotEnergy, pTotEnergy;
0109 if (rnge->flat() > 0.5) {
0110 eTotEnergy = (1.-eps)*thePrimEkin;
0111 pTotEnergy = eps*thePrimEkin;
0112 } else {
0113 pTotEnergy = (1.-eps)*thePrimEkin;
0114 eTotEnergy = eps*thePrimEkin;
0115 }
0116
0117
0118 eKinEnergy = G4HepEmMax(0.,eTotEnergy - kElectronMassC2);
0119 pKinEnergy = G4HepEmMax(0.,pTotEnergy - kElectronMassC2);
0120 }
0121
0122
0123 void G4HepEmGammaInteractionConversion::SampleDirections(const double* orgGammaDir, double* secElDir,
0124 double* secPosDir, const double secElEkin,
0125 const double secPosEkin, G4HepEmRandomEngine* rnge) {
0126
0127 const double phi = k2Pi*rnge->flat();
0128 const double cosPhi = std::cos(phi);
0129 const double sinPhi = std::sin(phi);
0130
0131 const double costEl = SampleCostModifiedTsai(secElEkin, rnge);
0132 const double sintEl = std::sqrt((1.0-costEl)*(1.0+costEl));
0133 secElDir[0] = sintEl * cosPhi;
0134 secElDir[1] = sintEl * sinPhi;
0135 secElDir[2] = costEl;
0136
0137 RotateToReferenceFrame(secElDir, orgGammaDir);
0138
0139 const double costPos = SampleCostModifiedTsai(secPosEkin, rnge);
0140 const double sintPos = std::sqrt((1.0-costPos)*(1.0+costPos));
0141 secPosDir[0] = -sintPos * cosPhi;
0142 secPosDir[1] = -sintPos * sinPhi;
0143 secPosDir[2] = costPos;
0144
0145 RotateToReferenceFrame(secPosDir, orgGammaDir);
0146 }
0147
0148
0149
0150
0151 int G4HepEmGammaInteractionConversion::SelectTargetAtom(const struct G4HepEmGammaData* gmData, const int imat,
0152 const double ekin, const double lekin, const double urndn) {
0153
0154 const int indxStart = gmData->fElemSelectorConvStartIndexPerMat[imat];
0155 const double* theData = &(gmData->fElemSelectorConvData[indxStart]);
0156 const int numData = gmData->fElemSelectorConvEgridSize;
0157 const int numElem = theData[0];
0158 const double logE0 = gmData->fElemSelectorConvLogMinEkin;
0159 const double invLD = gmData->fElemSelectorConvEILDelta;
0160 const double* xdata = gmData->fElemSelectorConvEgrid;
0161
0162 const double xv = G4HepEmMax(xdata[0], G4HepEmMin(xdata[numData-1], ekin));
0163
0164 const int idxEkin = G4HepEmMax(0.0, G4HepEmMin((lekin-logE0)*invLD, numData-2.0));
0165
0166 const double x1 = xdata[idxEkin];
0167 const double x2 = xdata[idxEkin+1];
0168 const double dl = x2-x1;
0169 const double b = G4HepEmMax(0., G4HepEmMin(1., (xv - x1)/dl));
0170
0171 const int indx0 = idxEkin*(numElem-1) + 1;
0172 const int indx1 = indx0 + (numElem-1);
0173 int theElemIndex = 0;
0174 while (theElemIndex<numElem-1 && urndn > theData[indx0+theElemIndex]+b*(theData[indx1+theElemIndex]-theData[indx0+theElemIndex])) { ++theElemIndex; }
0175 return theElemIndex;
0176 }
0177
0178
0179 double G4HepEmGammaInteractionConversion::SampleEnergyRateNoLPM(
0180 const double normCond, const double epsMin, const double epsRange, const double deltaFactor,
0181 const double invF10, const double invF20, const double fz, G4HepEmRandomEngine* rnge) {
0182 double rndmv[3];
0183 double greject = 0.;
0184 double eps = 0.;
0185 do {
0186 rnge->flatArray(3, rndmv);
0187 if (normCond > rndmv[0]) {
0188 eps = 0.5 - epsRange * std::pow(rndmv[1], 1./3.);
0189 const double delta = deltaFactor/(eps*(1.-eps));
0190 greject = (ScreenFunction1(delta)-fz)*invF10;
0191 } else {
0192 eps = epsMin + epsRange*rndmv[1];
0193 const double delta = deltaFactor/(eps*(1.-eps));
0194 greject = (ScreenFunction2(delta)-fz)*invF20;
0195 }
0196
0197 } while (greject < rndmv[2]);
0198
0199 return eps;
0200 }
0201
0202
0203 double G4HepEmGammaInteractionConversion::SampleEnergyRateWithLPM(
0204 const double normCond, const double epsMin, const double epsRange, const double deltaFactor,
0205 const double invF10, const double invF20, const double fz, G4HepEmRandomEngine* rnge,
0206 const double eGamma, const double lpmEnergy, const struct G4HepEmElemData* elemData) {
0207 const double z23 = elemData->fZet23;
0208 const double ilVarS1 = elemData->fILVarS1;
0209 const double ilVarS1Cond = elemData->fILVarS1Cond;
0210 double rndmv[3];
0211 double greject = 0.;
0212 double eps = 0.;
0213 do {
0214 rnge->flatArray(3, rndmv);
0215 if (normCond > rndmv[0]) {
0216 eps = 0.5 - epsRange * std::pow(rndmv[1], 1./3.);
0217 const double delta = deltaFactor/(eps*(1.-eps));
0218 double funcXiS, funcGS, funcPhiS, phi1, phi2;
0219 ComputePhi12(delta, phi1, phi2);
0220
0221
0222
0223 EvaluateLPMFunctions(funcXiS, funcGS, funcPhiS, eGamma, eps*eGamma, lpmEnergy, z23, ilVarS1, ilVarS1Cond, 0.0, -1.0);
0224 greject = funcXiS*((2.*funcPhiS+funcGS)*phi1-funcGS*phi2-funcPhiS*fz)*invF10;
0225 } else {
0226 eps = epsMin + epsRange*rndmv[1];
0227 const double delta = deltaFactor/(eps*(1.-eps));
0228 double funcXiS, funcGS, funcPhiS, phi1, phi2;
0229 ComputePhi12(delta, phi1, phi2);
0230 EvaluateLPMFunctions(funcXiS, funcGS, funcPhiS, eGamma, eps*eGamma, lpmEnergy, z23, ilVarS1, ilVarS1Cond, 0.0, -1.0);
0231 greject = funcXiS*( (funcPhiS+0.5*funcGS)*phi1 + 0.5*funcGS*phi2
0232 -0.5*(funcGS+funcPhiS)*fz)*invF20;
0233 }
0234 } while (greject < rndmv[2]);
0235
0236 return eps;
0237 }
0238
0239
0240 void G4HepEmGammaInteractionConversion::ComputePhi12(const double delta, double &phi1, double &phi2) {
0241 if (delta > 1.4) {
0242 phi1 = 21.0190 - 4.145*G4HepEmLog(delta + 0.958);
0243 phi2 = phi1;
0244 } else {
0245 phi1 = 20.806 - delta*(3.190 - 0.5710*delta);
0246 phi2 = 20.234 - delta*(2.126 - 0.0903*delta);
0247 }
0248 }
0249
0250
0251
0252 double G4HepEmGammaInteractionConversion::ScreenFunction1(const double delta) {
0253 return (delta > 1.4) ? 42.038 - 8.29*G4HepEmLog(delta + 0.958)
0254 : 42.184 - delta*(7.444 - 1.623*delta);
0255 }
0256
0257
0258
0259 double G4HepEmGammaInteractionConversion::ScreenFunction2(const double delta) {
0260 return (delta > 1.4) ? 42.038 - 8.29*G4HepEmLog(delta + 0.958)
0261 : 41.326 - delta*(5.848 - 0.902*delta);
0262 }
0263
0264
0265
0266 void G4HepEmGammaInteractionConversion::ScreenFunction12(const double delta, double &f1, double &f2) {
0267 if (delta > 1.4) {
0268 f1 = 42.038 - 8.29*G4HepEmLog(delta + 0.958);
0269 f2 = f1;
0270 } else {
0271 f1 = 42.184 - delta*(7.444 - 1.623*delta);
0272 f2 = 41.326 - delta*(5.848 - 0.902*delta);
0273 }
0274 }