158G4bool G4GoudsmitSaundersonMscModel::gIsUseAccurate =
true;
160G4bool G4GoudsmitSaundersonMscModel::gIsOptimizationOn =
true;
166 currentMaterialIndex = -1;
179 currentKinEnergy = 0.0;
182 tlimitminfix2 = 1.*nm;
184 mass = electron_mass_c2;
187 currentCouple =
nullptr;
188 fParticleChange =
nullptr;
201 fIsUsePWACorrection =
true;
203 fIsUseMottCorrection =
false;
214 fTheTrueStepLenght = 0.;
215 fTheTransportDistance = 0.;
216 fTheZPathLenght = 0.;
218 fTheDisplacementVector.
set(0.,0.,0.);
219 fTheNewDirection.
set(0.,0.,1.);
221 fIsEverythingWasDone =
false;
222 fIsMultipleSacettring =
false;
223 fIsSingleScattering =
false;
224 fIsEndedUpOnBoundary =
false;
225 fIsNoScatteringInMSC =
false;
226 fIsNoDisplace =
false;
227 fIsInsideSkin =
false;
228 fIsWasOnBoundary =
false;
229 fIsFirstRealStep =
false;
230 rndmEngineMod = G4Random::getTheEngine();
233 fPWACorrection =
nullptr;
243 if (fPWACorrection) {
244 delete fPWACorrection;
245 fPWACorrection =
nullptr;
259 fIsUseMottCorrection =
true;
263 if (fIsUseMottCorrection) {
264 fIsUsePWACorrection =
false;
272 if (fPWACorrection) {
273 delete fPWACorrection;
274 fPWACorrection =
nullptr;
291 if (fIsUsePWACorrection) {
321 G4double efEnergy = std::max(kineticEnergy, 10.*CLHEP::eV);
323 G4double pt2 = efEnergy*(efEnergy+2.0*electron_mass_c2);
325 G4double beta2 = pt2/(pt2+electron_mass_c2*electron_mass_c2);
335 if (fIsUseMottCorrection) {
339 }
else if (fIsUsePWACorrection) {
348 fScrA = fGSTable->
GetMoliereXc2(matindx)/(4.0*pt2*bc)*fMCtoScrA;
352 fLambda0 = beta2*(1.+fScrA)*fMCtoScrA/bc/scpCor;
355 fG1 = 2.0*fScrA*((1.0+fScrA)*
G4Log(1.0/fScrA+1.0)-1.0);
357 fLambda1 = fLambda0/fG1;
358 xsecTr1 = 1./fLambda1;
378 if (efEnergy<10.*CLHEP::eV) efEnergy = 10.*CLHEP::eV;
380 G4double pt2 = efEnergy*(efEnergy+2.0*electron_mass_c2);
382 G4double beta2 = pt2/(pt2+electron_mass_c2*electron_mass_c2);
392 if (fIsUseMottCorrection) {
395 }
else if (fIsUsePWACorrection) {
404 fScrA = fGSTable->
GetMoliereXc2(matindx)/(4.0*pt2*bc)*fMCtoScrA;
408 fLambda0 = beta2*(1.+fScrA)*fMCtoScrA/bc/scpCor;
411 fG1 = 2.0*fScrA*((1.0+fScrA)*
G4Log(1.0/fScrA+1.0)-1.0);
413 fLambda1 = fLambda0/fG1;
433 if (efEnergy<10.*CLHEP::eV) efEnergy = 10.*CLHEP::eV;
435 G4double pt2 = efEnergy*(efEnergy+2.0*electron_mass_c2);
436 G4double beta2 = pt2/(pt2+electron_mass_c2*electron_mass_c2);
444 if (fIsUseMottCorrection) {
447 }
else if (fIsUsePWACorrection) {
451 scrA = fGSTable->
GetMoliereXc2(matindx)/(4.0*pt2*bc)*mctoScrA;
453 lambda0 = beta2*(1.+scrA)*mctoScrA/bc/scpCor;
454 g1 = 2.0*scrA*((1.0+scrA)*
G4Log(1.0/scrA+1.0)-1.0);
455 lambda1 = lambda0/g1;
464 tlimit = tgeom = rangeinit = geombig;
480 currentRange =
GetRange(particle,currentKinEnergy,currentCouple,
488 fTheTrueStepLenght = currentMinimalStep;
489 fTheTransportDistance = currentMinimalStep;
490 fTheZPathLenght = currentMinimalStep;
491 fTheDisplacementVector.
set(0.,0.,0.);
492 fTheNewDirection.
set(0.,0.,1.);
495 fIsEverythingWasDone =
false;
497 fIsMultipleSacettring =
false;
499 fIsSingleScattering =
false;
501 fIsNoScatteringInMSC =
false;
504 fIsNoDisplace =
false;
506 presafety = sp->GetSafety();
511 distance *= (1.20-fZeff*(1.62e-2-9.22e-5*fZeff));
519 if (gIsOptimizationOn && (distance<presafety)) {
521 fIsMultipleSacettring =
true;
522 fIsNoDisplace =
true;
538 fIsWasOnBoundary =
true;
541 skindepth =
skin*fLambda0;
544 fIsInsideSkin =
false;
550 if ((stepStatus==
fGeomBoundary) || (presafety<skindepth) || (fTheTrueStepLenght<skindepth)) {
552 if ((stepStatus ==
fGeomBoundary) || (presafety < skindepth)) {
553 fIsInsideSkin =
true;
554 fIsWasOnBoundary =
true;
567 if (sslimit<fTheTrueStepLenght) {
568 fTheTrueStepLenght = sslimit;
569 fIsSingleScattering =
true;
572 fTheZPathLenght = fTheTrueStepLenght;
576 fIsEverythingWasDone =
true;
584 fIsMultipleSacettring =
true;
587 fIsFirstRealStep =
false;
591 if (fIsWasOnBoundary && !fIsInsideSkin) {
593 fIsWasOnBoundary =
false;
594 fIsFirstRealStep =
true;
603 if (firstStep || fIsFirstRealStep || rangeinit>1.e+20) {
604 rangeinit = currentRange;
615 if (geomlimit<geombig) {
619 if ((1.-geomlimit/fLambda1)> 0.) {
620 geomlimit = -fLambda1*
G4Log(1.-geomlimit/fLambda1);
638 tlimit = std::min(tlimit,tgeom);
648 if (geomlimit<geombig) {
649 tlimit = std::min(tlimit, geomlimit-0.999*skindepth);
652 if (firstStep || fIsFirstRealStep) {
653 fTheTrueStepLenght = std::min(fTheTrueStepLenght, Randomizetlimit());
655 fTheTrueStepLenght = std::min(fTheTrueStepLenght, tlimit);
659 presafety =
ComputeSafety(sp->GetPosition(),fTheTrueStepLenght);
660 geomlimit = presafety;
662 skindepth =
skin*fLambda0;
668 if ((stepStatus==
fGeomBoundary) || (presafety<skindepth) || (fTheTrueStepLenght<skindepth)) {
680 if (sslimit<fTheTrueStepLenght) {
681 fTheTrueStepLenght = sslimit;
682 fIsSingleScattering =
true;
685 fTheZPathLenght = fTheTrueStepLenght;
689 fIsEverythingWasDone =
true;
694 fIsMultipleSacettring =
true;
695 fIsEverythingWasDone =
true;
697 fTheTrueStepLenght = std::min(fTheTrueStepLenght,
facrange*currentRange);
700 if (fTheTrueStepLenght>presafety) {
701 fTheTrueStepLenght = std::min(fTheTrueStepLenght, presafety);
707 fTheTrueStepLenght = std::min(fTheTrueStepLenght, fLambda1*0.5);
719 fIsMultipleSacettring =
true;
721 presafety =
ComputeSafety(sp->GetPosition(),fTheTrueStepLenght);
724 if ((distance<presafety) && (gIsOptimizationOn)) {
725 fIsNoDisplace =
true;
728 if (firstStep || (stepStatus==
fGeomBoundary) || rangeinit>1.e+20) {
729 rangeinit = currentRange;
740 tlimit = std::max(fr*rangeinit,
facsafety*presafety);
743 fTheTrueStepLenght = std::min(fTheTrueStepLenght, Randomizetlimit());
745 fTheTrueStepLenght = std::min(fTheTrueStepLenght, tlimit);
753 if (fIsEverythingWasDone) {
754 if (fIsSingleScattering) {
758 G4double pt2 = currentKinEnergy*(currentKinEnergy+2.0*CLHEP::electron_mass_c2);
759 G4double beta2 = pt2/(pt2+CLHEP::electron_mass_c2*CLHEP::electron_mass_c2);
762 if (cost<-1.) cost = -1.;
763 if (cost> 1.) cost = 1.;
766 G4double sint = std::sqrt(dum*(2.-dum));
770 fTheNewDirection.
set(sint*cosPhi,sint*sinPhi,cost);
771 }
else if (fIsMultipleSacettring) {
790 if (!fIsEverythingWasDone) {
793 fTheTrueStepLenght = std::min(fTheTrueStepLenght,currentRange);
795 fTheZPathLenght = fTheTrueStepLenght;
797 if (fTheTrueStepLenght<tlimitminfix2) {
798 return fTheZPathLenght;
800 G4double tau = fTheTrueStepLenght/fLambda1;
802 fTheZPathLenght = std::min(fTheTrueStepLenght, fLambda1);
803 }
else if (fTheTrueStepLenght<currentRange*
dtrl) {
804 if (tau<taulim) fTheZPathLenght = fTheTrueStepLenght*(1.-0.5*tau) ;
805 else fTheZPathLenght = fLambda1*(1.-
G4Exp(-tau));
806 }
else if (currentKinEnergy<mass || fTheTrueStepLenght==currentRange) {
807 par1 = 1./currentRange ;
808 par2 = 1./(par1*fLambda1) ;
810 if (fTheTrueStepLenght<currentRange) {
811 fTheZPathLenght = 1./(par1*par3) * (1.-std::pow(1.-par1*fTheTrueStepLenght,par3));
813 fTheZPathLenght = 1./(par1*par3);
816 G4double rfin = std::max(currentRange-fTheTrueStepLenght, 0.01*currentRange);
818 G4double lambda1 = GetTransportMeanFreePathOnly(particle,T1);
820 par1 = (fLambda1-lambda1)/(fLambda1*fTheTrueStepLenght);
821 par2 = 1./(par1*fLambda1);
824 fTheZPathLenght = 1./(par1*par3) * (1.-g4calc->
powA(1.-par1*fTheTrueStepLenght,par3));
827 fTheZPathLenght = std::min(fTheZPathLenght, fLambda1);
829 return fTheZPathLenght;
835 fIsEndedUpOnBoundary =
false;
837 if (geomStepLength==fTheZPathLenght) {
838 return fTheTrueStepLenght;
843 fIsEndedUpOnBoundary =
true;
844 fTheZPathLenght = geomStepLength;
846 if (fIsEverythingWasDone && !fIsMultipleSacettring) {
847 fTheTrueStepLenght = geomStepLength;
848 return fTheTrueStepLenght;
851 if (geomStepLength<tlimitminfix2) {
852 fTheTrueStepLenght = geomStepLength;
856 if (geomStepLength>fLambda1*tausmall) {
858 tlength = -fLambda1*
G4Log(1.-geomStepLength/fLambda1) ;
860 if (par1*par3*geomStepLength<1.) {
862 tlength = (1.-g4calc->
powA( 1.-par1*par3*geomStepLength,1./par3))/par1;
864 tlength = currentRange;
867 if (tlength<geomStepLength || tlength>fTheTrueStepLenght) {
868 tlength = geomStepLength;
871 fTheTrueStepLenght = tlength;
874 return fTheTrueStepLenght;
881 fTheNewDirection.
rotateUz(oldDirection);
883 return fTheDisplacementVector;
885 if (fIsEndedUpOnBoundary) {
886 return fTheDisplacementVector;
887 }
else if (fIsEverythingWasDone) {
889 if (fIsSingleScattering) {
890 fTheNewDirection.
rotateUz(oldDirection);
892 return fTheDisplacementVector;
895 if (fIsMultipleSacettring && !fIsNoScatteringInMSC) {
896 fTheNewDirection.
rotateUz(oldDirection);
897 fTheDisplacementVector.
rotateUz(oldDirection);
903 return fTheDisplacementVector;
911 if (!fIsNoScatteringInMSC) {
912 fTheNewDirection.
rotateUz(oldDirection);
914 if (!fIsNoDisplace) {
915 fTheDisplacementVector.
rotateUz(oldDirection);
919 return fTheDisplacementVector;
924 fIsNoScatteringInMSC =
false;
926 G4double kineticEnergy = currentKinEnergy;
931 eloss = kineticEnergy -
GetEnergy(particle,currentRange-fTheTrueStepLenght,currentCouple);
943 G4double efStep = fTheTrueStepLenght;
945 G4double kineticEnergy0 = kineticEnergy;
946 if (gIsUseAccurate) {
947 kineticEnergy -= 0.5*eloss;
949 tau = kineticEnergy/electron_mass_c2;
951 eps0 = eloss/kineticEnergy0;
952 epsm = eloss/kineticEnergy;
954 efEnergy = kineticEnergy * (1.-epsm*epsm*(6.+10.*tau+5.*tau2)/(24.*tau2+48.*tau+72.));
955 G4double dum = 0.166666*(4.+tau*(6.+tau*(7.+tau*(4.+tau))))*(epsm/((tau+1.)*(tau+2.)))*(epsm/((tau+1.)*(tau+2.)));
956 efStep = fTheTrueStepLenght*(1.-dum);
958 kineticEnergy -= 0.5*eloss;
959 efEnergy = kineticEnergy;
960 G4double factor = 1./(1.+0.9784671*kineticEnergy);
961 eps0 = eloss/kineticEnergy0;
962 epsm = eps0/(1.-0.5*eps0);
963 G4double temp = 0.3*(1 -factor*(1.-0.333333*factor))*eps0*eps0;
964 efStep = fTheTrueStepLenght*(1.+temp);
973 lambdan=efStep/fLambda0;
975 if (lambdan<=1.0e-12) {
976 if (fIsEverythingWasDone) {
977 fTheZPathLenght = fTheTrueStepLenght;
979 fIsNoScatteringInMSC =
true;
986 G4double cosTheta1 = 1.0, sinTheta1 = 0.0, cosTheta2 = 1.0, sinTheta2 = 0.0;
987 G4double cosPhi1 = 1.0, sinPhi1 = 0.0, cosPhi2 = 1.0, sinPhi2 = 0.0;
988 G4double uss = 0.0, vss = 0.0, wss = 1.0;
989 G4double x_coord = 0.0, y_coord = 0.0, z_coord = 1.0;
995 sinTheta1 = std::sqrt((1.-cosTheta1)*(1.+cosTheta1));
997 sinTheta2 = std::sqrt((1.-cosTheta2)*(1.+cosTheta2));
1001 G4double pt2 = efEnergy*(efEnergy+2.0*CLHEP::electron_mass_c2);
1002 G4double beta2 = pt2/(pt2+CLHEP::electron_mass_c2*CLHEP::electron_mass_c2);
1006 G4int mcEkinIdx = -1;
1007 G4int mcDeltIdx = -1;
1009 G4bool isMsc = fGSTable->
Sampling(0.5*lambdan, 0.5*Qn1, fScrA, cosTheta1, sinTheta1, lekin, beta2,
1010 currentMaterialIndex, &gsDtr, mcEkinIdx, mcDeltIdx, transfPar,
1012 fGSTable->
Sampling(0.5*lambdan, 0.5*Qn1, fScrA, cosTheta2, sinTheta2, lekin, beta2,
1013 currentMaterialIndex, &gsDtr, mcEkinIdx, mcDeltIdx, transfPar, !isMsc);
1014 if (cosTheta1+cosTheta2==2.) {
1015 if (fIsEverythingWasDone)
1016 fTheZPathLenght = fTheTrueStepLenght;
1017 fIsNoScatteringInMSC =
true;
1023 sinPhi1 = std::sin(phi1);
1024 cosPhi1 = std::cos(phi1);
1026 sinPhi2 = std::sin(phi2);
1027 cosPhi2 = std::cos(phi2);
1030 u2 = sinTheta2*cosPhi2;
1031 v2 = sinTheta2*sinPhi2;
1032 G4double u2p = cosTheta1*u2 + sinTheta1*cosTheta2;
1033 uss = u2p*cosPhi1 - v2*sinPhi1;
1034 vss = u2p*sinPhi1 + v2*cosPhi1;
1035 wss = cosTheta1*cosTheta2 - sinTheta1*u2;
1038 fTheNewDirection.
set(uss,vss,wss);
1042 if(fIsNoDisplace && fIsEverythingWasDone)
1043 fTheZPathLenght = fTheTrueStepLenght;
1052 if (gIsUseAccurate) {
1055 if(Qn1<0.7) par = 1.;
1056 else if (Qn1<7.0) par = -0.031376*Qn1+1.01356;
1063 G4double gamma = 6.0*fScrA*(1.0 + fScrA)*(loga*(1.0 + 2.0*fScrA) - 2.0)/fG1;
1064 gamma *= fMCtoG2PerG1;
1072 G4double delta = 0.9082483-(0.1020621-0.0263747*gamma)*Qn1;
1076 G4double temp = (2.0+tau*temp1)/((tau+1.0)*temp1);
1078 temp = temp - (tau+1.0)/((tau+2.0)*(loga*(1.0+fScrA)-1.0));
1081 delta = delta + 0.40824829*(eps0*(tau+1.0)/((tau+2.0)*
1082 (loga*(1.0+fScrA)-1.0)*(loga*(1.0+2.0*fScrA)-2.0)) - 0.25*temp*temp);
1089 G4double ut = b*sinTheta1*cosPhi1 + c*(cosPhi1*u2 - sinPhi1*w1v2) + eta1*uss*temp1;
1090 G4double vt = b*sinTheta1*sinPhi1 + c*(sinPhi1*u2 + cosPhi1*w1v2) + eta1*vss*temp1;
1091 G4double wt = eta1*(1+temp) + b*cosTheta1 + c*cosTheta2 + eta1*wss*temp1;
1100 x_coord = ut*fTheTrueStepLenght;
1101 y_coord = vt*fTheTrueStepLenght;
1102 z_coord = wt*fTheTrueStepLenght;
1104 if(fIsEverythingWasDone){
1108 G4double transportDistance = std::sqrt(x_coord*x_coord+y_coord*y_coord+z_coord*z_coord);
1110 if(transportDistance>fTheTrueStepLenght)
1111 transportDistance = fTheTrueStepLenght;
1112 fTheZPathLenght = transportDistance;
1116 fTheDisplacementVector.
set(x_coord,y_coord,z_coord-fTheZPathLenght);
1123 if(fIsEverythingWasDone){
1127 zz = 1.0 - Qn1*(0.5 - Qn1*(0.166666667 - 0.041666667*Qn1));
1129 zz = (1.-
G4Exp(-Qn1))/Qn1;
1134 zz = fTheZPathLenght/fTheTrueStepLenght;
1137 G4double rr = (1.-zz*zz)/(1.-wss*wss);
1138 if(rr >= 0.25) rr = 0.25;
1139 G4double rperp = fTheTrueStepLenght*std::sqrt(rr);
1140 x_coord = rperp*uss;
1141 y_coord = rperp*vss;
1142 z_coord = zz*fTheTrueStepLenght;
1144 if(fIsEverythingWasDone){
1145 G4double transportDistance = std::sqrt(x_coord*x_coord + y_coord*y_coord + z_coord*z_coord);
1146 fTheZPathLenght = transportDistance;
1149 fTheDisplacementVector.
set(x_coord,y_coord,z_coord- fTheZPathLenght);
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
G4double G4Log(G4double x)
void set(double x, double y, double z)
Hep3Vector & rotateUz(const Hep3Vector &)
G4double GetLogKineticEnergy() const
G4ParticleDefinition * GetDefinition() const
G4double GetKineticEnergy() const
static G4EmParameters * Instance()
void GetPWACorrectionFactors(G4double logekin, G4double beta2, G4int matindx, G4double &corToScr, G4double &corToQ1, G4double &corToG2PerG1)
G4double ComputeTruePathLengthLimit(const G4Track &track, G4double ¤tMinimalStep) override
G4ThreeVector & SampleScattering(const G4ThreeVector &, G4double safety) override
G4double ComputeGeomPathLength(G4double truePathLength) override
void StartTracking(G4Track *) override
G4GSPWACorrections * GetPWACorrection()
G4GoudsmitSaundersonMscModel(const G4String &nam="GoudsmitSaunderson")
void Initialise(const G4ParticleDefinition *, const G4DataVector &) override
G4GoudsmitSaundersonTable * GetGSTable()
~G4GoudsmitSaundersonMscModel() override
G4double ComputeTrueStepLength(G4double geomStepLength) override
G4bool GetOptionMottCorrection() const
G4bool GetOptionPWACorrection() const
void InitialiseLocal(const G4ParticleDefinition *p, G4VEmModel *masterModel) override
G4double GetTransportMeanFreePath(const G4ParticleDefinition *, G4double)
G4double CrossSectionPerVolume(const G4Material *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy=0.0, G4double maxEnergy=DBL_MAX) override
G4double ComputeScatteringPowerCorrection(const G4MaterialCutsCouple *matcut, G4double ekin)
void GetMottCorrectionFactors(G4double logekin, G4double beta2, G4int matindx, G4double &mcToScr, G4double &mcToQ1, G4double &mcToG2PerG1)
G4double SingleScattering(G4double lambdaval, G4double scra, G4double lekin, G4double beta2, G4int matindx)
G4bool Sampling(G4double lambdaval, G4double qval, G4double scra, G4double &cost, G4double &sint, G4double lekin, G4double beta2, G4int matindx, GSMSCAngularDtr **gsDtr, G4int &mcekini, G4int &mcdelti, G4double &transfPar, G4bool isfirst)
void SetOptionPWACorrection(G4bool val)
G4double GetMoliereBc(G4int matindx)
void Initialise(G4double lownergylimit, G4double highenergylimit)
G4double GetMoliereXc2(G4int matindx)
void SetOptionMottCorrection(G4bool val)
G4double GetZeffective() const
static G4LossTableManager * Instance()
const G4Material * GetMaterial() const
G4IonisParamMat * GetIonisation() const
void ProposeMomentumDirection(const G4ThreeVector &Pfinal)
G4double GetPDGCharge() const
static G4Pow * GetInstance()
G4double powA(G4double A, G4double y) const
G4StepPoint * GetPreStepPoint() const
const G4DynamicParticle * GetDynamicParticle() const
const G4MaterialCutsCouple * GetMaterialCutsCouple() const
const G4Step * GetStep() const
G4double LowEnergyLimit() const
void SetCurrentCouple(const G4MaterialCutsCouple *)
G4double HighEnergyLimit() const
G4double ComputeGeomLimit(const G4Track &, G4double &presafety, G4double limit)
G4ParticleChangeForMSC * GetParticleChangeForMSC(const G4ParticleDefinition *p=nullptr)
G4double GetEnergy(const G4ParticleDefinition *part, G4double range, const G4MaterialCutsCouple *couple)
G4double GetRange(const G4ParticleDefinition *part, G4double kineticEnergy, const G4MaterialCutsCouple *couple)
G4MscStepLimitType steppingAlgorithm
G4double ConvertTrueToGeom(G4double &tLength, G4double &gLength)
G4double ComputeSafety(const G4ThreeVector &position, G4double limit=DBL_MAX)
void InitialiseParameters(const G4ParticleDefinition *)