120 G4bool G4GoudsmitSaundersonMscModel::fgIsUseAccurate =
true;
122 G4bool G4GoudsmitSaundersonMscModel::fgIsOptimizationOn =
true;
128 currentMaterialIndex = -1;
130 lambdalimit = 1.*
mm ;
142 currentKinEnergy = 0.0;
145 tlimitminfix2 = 1.*
nm;
156 fIsUsePWATotalXsecData =
false;
164 fTheTrueStepLenght = 0.;
165 fTheTransportDistance = 0.;
166 fTheZPathLenght = 0.;
167 fTheDisplacementVector.
set(0.,0.,0.);
168 fTheNewDirection.
set(0.,0.,1.);
170 fIsEverythingWasDone =
false;
171 fIsMultipleSacettring =
false;
172 fIsSingleScattering =
false;
173 fIsEndedUpOnBoundary =
false;
174 fIsNoScatteringInMSC =
false;
175 fIsNoDisplace =
false;
176 fIsInsideSkin =
false;
177 fIsWasOnBoundary =
false;
178 fIsFirstRealStep =
false;
183 rndmEngineMod = G4Random::getTheEngine();
197 delete fgPWAXsecTable;
231 if(fIsUsePWATotalXsecData) {
250 if(efEnergy<lowKEnergy) efEnergy=lowKEnergy;
251 if(efEnergy>highKEnergy)efEnergy=highKEnergy;
261 if(fIsUsePWATotalXsecData) {
269 for(
G4int i=0;i<nelm;i++){
270 int zet =
G4lrint((*theElementVector)[i]->GetZ());
272 int indx = (
G4int)(1.5 + charge*1.5);
275 indx = (
G4int)(2.5 + charge*1.5);
277 fLambda0 += (theAtomNumDensityVector[i]*elxsec);
278 fLambda1 += (theAtomNumDensityVector[i]*t1xsec);
280 if(fLambda0>0.0) { fLambda0 =1./fLambda0; }
281 if(fLambda1>0.0) { fLambda1 =1./fLambda1; }
285 if(fLambda1>0.0) { fG1 = fLambda0/fLambda1; }
292 if(efEnergy<0.001) efEnergy = 0.001;
302 fG1 = 2.0*fScrA*((1.0+fScrA)*
G4Log(1.0/fScrA+1.0)-1.0);
303 fLambda1 = fLambda0/fG1;
315 if(efEnergy<lowKEnergy) efEnergy=lowKEnergy;
316 if(efEnergy>highKEnergy)efEnergy=highKEnergy;
326 if(fIsUsePWATotalXsecData) {
334 for(
G4int i=0;i<nelm;i++){
335 int zet =
G4lrint((*theElementVector)[i]->GetZ());
337 int indx = (
G4int)(2.5 + charge*1.5);
339 lambda1 += (theAtomNumDensityVector[i]*t1xsec);
341 if(lambda1>0.0) { lambda1 =1./lambda1; }
347 if(efEnergy<0.001) efEnergy = 0.001;
357 g1 = 2.0*scrA*((1.0+scrA)*
G4Log(1.0/scrA+1.0)-1.0);
358 lambda1 = lambda0/g1;
369 tlimit = tgeom = rangeinit = geombig;
386 currentMaterialIndex = currentCouple->
GetIndex();
388 currentRange =
GetRange(particle,currentKinEnergy,currentCouple);
399 fTheTrueStepLenght = currentMinimalStep;
400 fTheTransportDistance = currentMinimalStep;
401 fTheZPathLenght = currentMinimalStep;
402 fTheDisplacementVector.
set(0.,0.,0.);
403 fTheNewDirection.
set(0.,0.,1.);
406 fIsEverythingWasDone =
false;
408 fIsMultipleSacettring =
false;
410 fIsSingleScattering =
false;
412 fIsNoScatteringInMSC =
false;
415 fIsNoDisplace =
false;
425 distance *= (1.20-fZeff*(1.62e-2-9.22e-5*fZeff));
436 if( fgIsOptimizationOn && (distance < presafety) ) {
438 fIsMultipleSacettring =
true;
439 fIsNoDisplace =
true;
456 fIsWasOnBoundary =
true;
459 skindepth =
skin*fLambda0;
462 fIsInsideSkin =
false;
468 if( (stepStatus ==
fGeomBoundary) || (presafety < skindepth) || (fTheTrueStepLenght < skindepth)){
470 if( (stepStatus ==
fGeomBoundary) || (presafety < skindepth))
471 fIsInsideSkin =
true;
483 if(sslimit < fTheTrueStepLenght) {
484 fTheTrueStepLenght = sslimit;
485 fIsSingleScattering =
true;
489 fTheZPathLenght = fTheTrueStepLenght;
493 fIsEverythingWasDone =
true;
501 fIsMultipleSacettring =
true;
505 fIsFirstRealStep =
false;
509 if(fIsWasOnBoundary && !fIsInsideSkin){
511 fIsWasOnBoundary =
false;
512 fIsFirstRealStep =
true;
522 if(firstStep || fIsFirstRealStep){
523 rangeinit = currentRange;
534 if(geomlimit < geombig){
538 if((1.-geomlimit/fLambda1) > 0.)
539 geomlimit = -fLambda1*
G4Log(1.-geomlimit/fLambda1);
567 if(geomlimit < geombig)
568 tlimit =
std::min(tlimit, geomlimit-0.999*skindepth);
571 if(firstStep || fIsFirstRealStep) {
572 fTheTrueStepLenght =
std::min(fTheTrueStepLenght, Randomizetlimit());
574 fTheTrueStepLenght =
std::min(fTheTrueStepLenght, tlimit);
579 geomlimit = presafety;
582 skindepth =
skin*fLambda0;
588 if( (stepStatus ==
fGeomBoundary) || (presafety < skindepth) || (fTheTrueStepLenght < skindepth)){
600 if(sslimit < fTheTrueStepLenght) {
601 fTheTrueStepLenght = sslimit;
602 fIsSingleScattering =
true;
606 fTheZPathLenght = fTheTrueStepLenght;
610 fIsEverythingWasDone =
true;
615 fIsMultipleSacettring =
true;
616 fIsEverythingWasDone =
true;
623 if(fTheTrueStepLenght > presafety)
624 fTheTrueStepLenght =
std::min(fTheTrueStepLenght, presafety);
630 fTheTrueStepLenght =
std::min(fTheTrueStepLenght, fLambda1*0.4);
643 fIsMultipleSacettring =
true;
650 if( (distance < presafety) && (fgIsOptimizationOn)) {
651 fIsNoDisplace =
true;
655 rangeinit = currentRange;
671 fTheTrueStepLenght =
std::min(fTheTrueStepLenght, Randomizetlimit());
673 fTheTrueStepLenght =
std::min(fTheTrueStepLenght, tlimit);
682 if(fIsEverythingWasDone){
683 if(fIsSingleScattering){
688 sinPhi = std::sin(phi);
689 cosPhi = std::cos(phi);
690 fTheNewDirection.
set(sint*cosPhi,sint*sinPhi,cost);
691 }
else if(fIsMultipleSacettring){
715 if(!fIsEverythingWasDone) {
718 fTheTrueStepLenght =
std::min(fTheTrueStepLenght,currentRange);
721 fTheZPathLenght = fTheTrueStepLenght;
724 if(fTheTrueStepLenght < tlimitminfix2)
return fTheZPathLenght;
726 G4double tau = fTheTrueStepLenght/fLambda1;
728 if (tau <= tausmall) {
729 fTheZPathLenght =
std::min(fTheTrueStepLenght, fLambda1);
730 }
else if (fTheTrueStepLenght < currentRange*
dtrl) {
731 if(tau < taulim) fTheZPathLenght = fTheTrueStepLenght*(1.-0.5*tau) ;
732 else fTheZPathLenght = fLambda1*(1.-
G4Exp(-tau));
733 }
else if(currentKinEnergy < mass || fTheTrueStepLenght == currentRange) {
734 par1 = 1./currentRange ;
735 par2 = 1./(par1*fLambda1) ;
737 if(fTheTrueStepLenght < currentRange) {
738 fTheZPathLenght = 1./(par1*par3) * (1.-std::pow(1.-par1*fTheTrueStepLenght,par3));
740 fTheZPathLenght = 1./(par1*par3);
744 G4double rfin =
std::max(currentRange-fTheTrueStepLenght, 0.01*currentRange);
746 G4double lambda1 = GetTransportMeanFreePathOnly(particle,T1);
748 par1 = (fLambda1-lambda1)/(fLambda1*fTheTrueStepLenght);
749 par2 = 1./(par1*fLambda1);
752 fTheZPathLenght = 1./(par1*par3) * (1.-g4calc->
powA(1.-par1*fTheTrueStepLenght,par3));
755 fTheZPathLenght =
std::min(fTheZPathLenght, fLambda1);
757 return fTheZPathLenght;
764 fIsEndedUpOnBoundary =
false;
767 if(geomStepLength == fTheZPathLenght) {
768 return fTheTrueStepLenght;
774 fIsEndedUpOnBoundary =
true;
776 fTheZPathLenght = geomStepLength;
779 if(fIsEverythingWasDone && !fIsMultipleSacettring) {
780 fTheTrueStepLenght = geomStepLength;
781 return fTheTrueStepLenght;
785 if(geomStepLength < tlimitminfix2) {
786 fTheTrueStepLenght = geomStepLength;
790 if(geomStepLength > fLambda1*tausmall ) {
792 tlength = -fLambda1*
G4Log(1.-geomStepLength/fLambda1) ;
794 if(par1*par3*geomStepLength < 1.) {
796 tlength = (1.-g4calc->
powA( 1.-par1*par3*geomStepLength,1./par3))/par1;
798 tlength = currentRange;
801 if(tlength < geomStepLength) { tlength = geomStepLength; }
802 else if(tlength > fTheTrueStepLenght) { tlength = geomStepLength; }
804 fTheTrueStepLenght = tlength;
806 return fTheTrueStepLenght;
814 fTheNewDirection.
rotateUz(oldDirection);
817 return fTheDisplacementVector;
819 if(fIsEndedUpOnBoundary) {
821 return fTheDisplacementVector;
822 }
else if(fIsEverythingWasDone) {
824 if(fIsSingleScattering) {
825 fTheNewDirection.
rotateUz(oldDirection);
828 return fTheDisplacementVector;
832 if(fIsMultipleSacettring && !fIsNoScatteringInMSC){
833 fTheNewDirection.
rotateUz(oldDirection);
834 fTheDisplacementVector.
rotateUz(oldDirection);
840 return fTheDisplacementVector;
850 if(!fIsNoScatteringInMSC) {
851 fTheNewDirection.
rotateUz(oldDirection);
854 fTheDisplacementVector.
rotateUz(oldDirection);
856 return fTheDisplacementVector;
863 G4double dum0 = 2.0*fScrA*rand1/(1.0 - rand1 + fScrA);
865 if(dum0 < 0.0) dum0 = 0.0;
866 else if(dum0 > 2.0 ) dum0 = 2.0;
869 sint = std::sqrt(dum0*(2.0 - dum0));
875 fIsNoScatteringInMSC =
false;
877 G4double kineticEnergy = currentKinEnergy;
883 eloss = kineticEnergy -
884 GetEnergy(particle,currentRange-fTheTrueStepLenght,currentCouple);
898 G4double efStep = fTheTrueStepLenght;
900 G4double kineticEnergy0 = kineticEnergy;
901 if(fgIsUseAccurate) {
902 kineticEnergy -= 0.5*eloss;
907 eps0 = eloss/kineticEnergy0;
908 epsm = eloss/kineticEnergy;
910 efEnergy = kineticEnergy * (1. - epsm*epsm*(6.+10.*tau+5.*tau2)/(24.*tau2+48.*tau+72.));
911 G4double dum = 0.166666*(4.+tau*(6.+tau*(7.+tau*(4.+tau))))*
912 (epsm/((tau+1.)*(tau+2.)))*(epsm/((tau+1.)*(tau+2.)));
913 efStep =fTheTrueStepLenght*(1.-dum);
915 kineticEnergy -= 0.5*eloss;
916 efEnergy = kineticEnergy;
917 G4double factor = 1./(1. + 0.9784671*kineticEnergy);
918 eps0= eloss/kineticEnergy0;
919 epsm= eps0/(1.-0.5*eps0);
920 G4double temp = 0.3*(1. - factor*(1. - 0.333333*factor))*eps0*eps0;
921 efStep = fTheTrueStepLenght*(1. + temp);
930 if(fLambda0>0.0) { lambdan=efStep/fLambda0; }
931 if(lambdan<=1.0e-12) {
932 if(fIsEverythingWasDone)
933 fTheZPathLenght = fTheTrueStepLenght;
934 fIsNoScatteringInMSC =
true;
939 if(!fIsUsePWATotalXsecData)
940 lambdan = lambdan/(1.+fScrA);
947 G4double cosTheta1 =1.0,sinTheta1 =0.0, cosTheta2 =1.0, sinTheta2 =0.0;
948 G4double cosPhi1=1.0,sinPhi1=0.0, cosPhi2 =1.0, sinPhi2 =0.0;
949 G4double uss=0.0,vss=0.0,wss=1.0,x_coord=0.0,y_coord=0.0,z_coord=1.0;
957 cosTheta1 = 1.-2.*vrand[0];
958 sinTheta1 = std::sqrt((1.-cosTheta1)*(1.+cosTheta1));
959 cosTheta2 = 1.-2.*vrand[1];
960 sinTheta2 = std::sqrt((1.-cosTheta2)*(1.+cosTheta2));
963 fgGSTable->
Sampling(0.5*lambdan, 0.5*Qn1, fScrA, cosTheta1, sinTheta1);
964 fgGSTable->
Sampling(0.5*lambdan, 0.5*Qn1, fScrA, cosTheta2, sinTheta2);
965 if(cosTheta1 + cosTheta2 == 2.) {
966 if(fIsEverythingWasDone)
967 fTheZPathLenght = fTheTrueStepLenght;
968 fIsNoScatteringInMSC =
true;
976 sinPhi1 = std::sin(phi1);
977 cosPhi1 = std::cos(phi1);
979 sinPhi2 = std::sin(phi2);
980 cosPhi2 = std::cos(phi2);
983 u2 = sinTheta2*cosPhi2;
984 v2 = sinTheta2*sinPhi2;
985 G4double u2p = cosTheta1*u2 + sinTheta1*cosTheta2;
986 uss = u2p*cosPhi1 - v2*sinPhi1;
987 vss = u2p*sinPhi1 + v2*cosPhi1;
988 wss = cosTheta1*cosTheta2 - sinTheta1*u2;
991 fTheNewDirection.
set(uss,vss,wss);
995 if(fIsNoDisplace && fIsEverythingWasDone)
996 fTheZPathLenght = fTheTrueStepLenght;
1004 if(fgIsUseAccurate) {
1007 if(Qn1<0.7) par = 1.;
1008 else if (Qn1<7.0) par = -0.031376*Qn1+1.01356;
1015 G4double gamma = 6.0*fScrA*(1.0 + fScrA)*(loga*(1.0 + 2.0*fScrA) - 2.0)/fG1;
1023 G4double delta = 0.9082483-(0.1020621-0.0263747*gamma)*Qn1;
1027 G4double temp = (2.0+tau*temp1)/((tau+1.0)*temp1);
1029 temp = temp - (tau+1.0)/((tau+2.0)*(loga*(1.0+fScrA)-1.0));
1032 delta = delta + 0.40824829*(eps0*(tau+1.0)/((tau+2.0)*
1033 (loga*(1.0+fScrA)-1.0)*(loga*(1.0+2.0*fScrA)-2.0)) - 0.25*temp*temp);
1040 G4double ut = b*sinTheta1*cosPhi1 + c*(cosPhi1*u2 - sinPhi1*w1v2) + eta1*uss*temp1;
1041 G4double vt = b*sinTheta1*sinPhi1 + c*(sinPhi1*u2 + cosPhi1*w1v2) + eta1*vss*temp1;
1042 G4double wt = eta1*(1+temp) + b*cosTheta1 + c*cosTheta2 + eta1*wss*temp1;
1051 x_coord = ut*fTheTrueStepLenght;
1052 y_coord = vt*fTheTrueStepLenght;
1053 z_coord = wt*fTheTrueStepLenght;
1055 if(fIsEverythingWasDone){
1059 G4double transportDistance = std::sqrt(x_coord*x_coord+y_coord*y_coord+z_coord*z_coord);
1061 if(transportDistance>fTheTrueStepLenght)
1062 transportDistance = fTheTrueStepLenght;
1063 fTheZPathLenght = transportDistance;
1067 fTheDisplacementVector.
set(x_coord,y_coord,z_coord-fTheZPathLenght);
1074 if(fIsEverythingWasDone){
1078 zz = 1.0 - Qn1*(0.5 - Qn1*(0.166666667 - 0.041666667*Qn1));
1080 zz = (1.-
G4Exp(-Qn1))/Qn1;
1085 zz = fTheZPathLenght/fTheTrueStepLenght;
1088 G4double rr = (1.-zz*zz)/(1.-wss*wss);
1089 if(rr >= 0.25) rr = 0.25;
1090 G4double rperp = fTheTrueStepLenght*std::sqrt(rr);
1091 x_coord = rperp*uss;
1092 y_coord = rperp*vss;
1093 z_coord = zz*fTheTrueStepLenght;
1095 if(fIsEverythingWasDone){
1096 G4double transportDistance = std::sqrt(x_coord*x_coord + y_coord*y_coord + z_coord*z_coord);
1097 fTheZPathLenght = transportDistance;
1100 fTheDisplacementVector.
set(x_coord,y_coord,z_coord- fTheZPathLenght);
void set(double x, double y, double z)
static G4Pow * GetInstance()
G4GoudsmitSaundersonMscModel(const G4String &nam="GoudsmitSaunderson")
virtual G4double ComputeTrueStepLength(G4double geomStepLength)
G4double powA(G4double A, G4double y) const
G4IonisParamMat * GetIonisation() const
static G4LossTableManager * Instance()
static constexpr double mm
std::vector< G4Element * > G4ElementVector
G4double GetKineticEnergy() const
const G4DynamicParticle * GetDynamicParticle() const
G4StepStatus GetStepStatus() const
G4double ConvertTrueToGeom(G4double &tLength, G4double &gLength)
const G4MaterialCutsCouple * GetMaterialCutsCouple() const
G4ParticleDefinition * GetDefinition() const
const G4Step * GetStep() const
G4double ComputeSafety(const G4ThreeVector &position, G4double limit=DBL_MAX)
const G4ElementVector * GetElementVector() const
G4double GetZeffective() const
static constexpr double electron_mass_c2
G4int GetPWATotalXsecEnergyBinIndex(G4double energy) const
const G4PWATotalXsecZ * GetPWATotalXsecForZet(G4int Z) const
G4StepPoint * GetPreStepPoint() const
G4double GetEnergy(const G4ParticleDefinition *part, G4double range, const G4MaterialCutsCouple *couple)
void StartTracking(G4Track *)
virtual G4double ComputeTruePathLengthLimit(const G4Track &track, G4double ¤tMinimalStep)
const G4double * GetVecNbOfAtomsPerVolume() const
void SingleScattering(G4double &cost, G4double &sint)
const G4ThreeVector & GetPosition() const
G4double GetRange(const G4ParticleDefinition *part, G4double kineticEnergy, const G4MaterialCutsCouple *couple)
virtual void Initialise(const G4ParticleDefinition *, const G4DataVector &)
Hep3Vector & rotateUz(const Hep3Vector &)
void Sampling(G4double, G4double, G4double, G4double &, G4double &)
G4double ComputeGeomLimit(const G4Track &, G4double &presafety, G4double limit)
G4double G4Log(G4double x)
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
G4ParticleChangeForMSC * GetParticleChangeForMSC(const G4ParticleDefinition *p=nullptr)
void ProposeMomentumDirection(const G4ThreeVector &Pfinal)
G4double GetMoliereXc2(G4int matindx)
T max(const T t1, const T t2)
brief Return the largest of the two arguments
static constexpr double nm
void SetCurrentCouple(const G4MaterialCutsCouple *)
virtual ~G4GoudsmitSaundersonMscModel()
G4double GetMoliereBc(G4int matindx)
T min(const T t1, const T t2)
brief Return the smallest of the two arguments
static constexpr double GeV
G4double GetSafety() const
G4MscStepLimitType steppingAlgorithm
size_t GetNumberOfElements() const
G4double GetTransportMeanFreePath(const G4ParticleDefinition *, G4double)
virtual G4ThreeVector & SampleScattering(const G4ThreeVector &, G4double safety)
virtual void flatArray(const int size, double *vect)=0
static constexpr double keV
G4double GetScreeningParam(G4double)
static constexpr double twopi
const G4Material * GetMaterial() const
virtual G4double ComputeGeomPathLength(G4double truePathLength)