// // ******************************************************************** // * License and Disclaimer * // * * // * The Geant4 software is copyright of the Copyright Holders of * // * the Geant4 Collaboration. It is provided under the terms and * // * conditions of the Geant4 Software License, included in the file * // * LICENSE and available at http://cern.ch/geant4/license . These * // * include a list of copyright holders. * // * * // * Neither the authors of this software system, nor their employing * // * institutes,nor the agencies providing financial support for this * // * work make any representation or warranty, express or implied, * // * regarding this software system or assume any liability for its * // * use. Please see the license in the file LICENSE and URL above * // * for the full disclaimer and the limitation of liability. * // * * // * This code implementation is the result of the scientific and * // * technical work of the GEANT4 collaboration. * // * By using, copying, modifying or distributing the software (or * // * any work based on the software) you agree to acknowledge its * // * use in resulting scientific publications, and indicate your * // * acceptance of all terms of the Geant4 Software license. * // ******************************************************************** // // $Id: G4GoudsmitSaundersonMscModel.cc,v 1.24 2010/05/17 15:11:30 vnivanch Exp $ // GEANT4 tag $Name: geant4-09-04-beta-cand-01 $ // // ------------------------------------------------------------------- // // GEANT4 Class file // // File name: G4GoudsmitSaundersonMscModel // // Author: Omrane Kadri // // Creation date: 20.02.2009 // // Modifications: // 04.03.2009 V.Ivanchenko cleanup and format according to Geant4 EM style // // 15.04.2009 O.Kadri: cleanup: discard no scattering and single scattering theta // sampling from SampleCosineTheta() which means the splitting // step into two sub-steps occur only for msc regime // // 12.06.2009 O.Kadri: linear log-log extrapolation of lambda0 & lambda1 between 1 GeV - 100 TeV // adding a theta min limit due to screening effect of the atomic nucleus // 26.08.2009 O.Kadri: Cubic Spline interpolation was replaced with polynomial method // within CalculateIntegrals method // 05.10.2009 O.Kadri: tuning small angle theta distributions // assuming the case of lambdan<1 as single scattering regime // tuning theta sampling for theta below the screening angle // 08.02.2010 O.Kadri: bugfix in compound xsection calculation and small angle computation // adding a rejection condition to hard collision angular sampling // ComputeTruePathLengthLimit was taken from G4WentzelVIModel // 26.03.2010 O.Kadri: direct xsection calculation not inverse of the inverse // angular sampling without large angle rejection method // longitudinal displacement is computed exactly from // 12.05.2010 O.Kadri: exchange between target and projectile has as a condition the particle type (e-/e-) // some cleanup to minimize time consuming (adding lamdan12 & Qn12, changing the error to 1.0e-12 for scrA) // // //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... //REFERENCES: //Ref.1:E. Benedito et al.,"Mixed simulation ... cross-sections", NIMB 174 (2001) pp 91-110; //Ref.2:I. Kawrakow et al.,"On the condensed ... transport",NIMB 142 (1998) pp 253-280; //Ref.3:I. Kawrakow et al.,"On the representation ... calculations",NIMB 134 (1998) pp 325-336; //Ref.4:Bielajew et al.,".....", NIMB 173 (2001) 332-343; //Ref.5:F. Salvat et al.,"ELSEPA--Dirac partial ...molecules", Comp.Phys.Comm.165 (2005) pp 157-190; //Ref.6:G4UrbanMscModel G4 9.2; //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... #include "G4GoudsmitSaundersonMscModel.hh" #include "G4GoudsmitSaundersonTable.hh" #include "G4ParticleChangeForMSC.hh" #include "G4MaterialCutsCouple.hh" #include "G4DynamicParticle.hh" #include "G4Electron.hh" #include "G4Positron.hh" #include "G4LossTableManager.hh" #include "G4Track.hh" #include "G4PhysicsTable.hh" #include "Randomize.hh" using namespace std; G4double G4GoudsmitSaundersonMscModel::ener[] = {-1.}; G4double G4GoudsmitSaundersonMscModel::TCSE[103][106] ; G4double G4GoudsmitSaundersonMscModel::FTCSE[103][106] ; G4double G4GoudsmitSaundersonMscModel::TCSP[103][106] ; G4double G4GoudsmitSaundersonMscModel::FTCSP[103][106] ; //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... G4GoudsmitSaundersonMscModel::G4GoudsmitSaundersonMscModel(const G4String& nam) : G4VMscModel(nam),lowKEnergy(0.1*keV),highKEnergy(100.*TeV),isInitialized(false) { fr=0.02,rangeinit=0.,masslimite=0.6*MeV, particle=0;tausmall=1.e-16;taulim=1.e-6;tlimit=1.e10*mm; tlimitmin=10.e-6*mm;geombig=1.e50*mm;geommin=1.e-3*mm,tgeom=geombig; tlimitminfix=1.e-6*mm;stepmin=tlimitminfix;lambdalimit=1.*mm;smallstep=1.e10; theManager=G4LossTableManager::Instance(); inside=false;insideskin=false; samplez=false; GSTable = new G4GoudsmitSaundersonTable(); if(ener[0] < 0.0){ G4cout << "### G4GoudsmitSaundersonMscModel loading ELSEPA data" << G4endl; LoadELSEPAXSections(); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... G4GoudsmitSaundersonMscModel::~G4GoudsmitSaundersonMscModel() { delete GSTable; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... void G4GoudsmitSaundersonMscModel::Initialise(const G4ParticleDefinition* p, const G4DataVector&) { skindepth=skin*stepmin; SetParticle(p); if(isInitialized) return; fParticleChange = GetParticleChangeForMSC(); InitialiseSafetyHelper(); isInitialized=true; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... G4double G4GoudsmitSaundersonMscModel::ComputeCrossSectionPerAtom(const G4ParticleDefinition* p, G4double kineticEnergy,G4double Z, G4double, G4double, G4double) { G4double cs=0.0; G4double kinEnergy = kineticEnergy; if(kinEnergyhighKEnergy)kinEnergy=highKEnergy; G4double cs0; CalculateIntegrals(p,Z,kinEnergy,cs0,cs); return cs; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... void G4GoudsmitSaundersonMscModel::SampleScattering(const G4DynamicParticle* dynParticle, G4double safety) { G4double kineticEnergy = dynParticle->GetKineticEnergy(); if((kineticEnergy <= 0.0) || (tPathLength <= tlimitminfix)|| (tPathLength/tausmall < lambda1)) return ; /////////////////////////////////////////// // Effective energy G4double eloss = theManager->GetEnergy(particle,tPathLength,currentCouple); if(eloss>0.5*kineticEnergy) {if((dynParticle->GetCharge())==-eplus)eloss=kineticEnergy-eloss;//exchange between target and projectile if they are electrons else eloss=0.5*kineticEnergy; } G4double ee = kineticEnergy - 0.5*eloss; G4double ttau = ee/electron_mass_c2; G4double ttau2 = ttau*ttau; G4double epsilonpp= eloss/ee; G4double cst1=epsilonpp*epsilonpp*(6+10*ttau+5*ttau2)/(24*ttau2+48*ttau+72); kineticEnergy *= (1 - cst1); /////////////////////////////////////////// // additivity rule for mixture and compound xsection's const G4Material* mat = currentCouple->GetMaterial(); const G4ElementVector* theElementVector = mat->GetElementVector(); const G4double* theAtomNumDensityVector = mat->GetVecNbOfAtomsPerVolume(); G4int nelm = mat->GetNumberOfElements(); G4double s0,s1; lambda0=0.; for(G4int i=0;iGetZ(),kineticEnergy,s0,s1); lambda0 += (theAtomNumDensityVector[i]*s0); } if(lambda0>DBL_MIN) lambda0 =1./lambda0; // Newton-Raphson root's finding method of scrA from: // Sig1(PWA)/Sig0(PWA)=g1=2*scrA*((1+scrA)*log(1+1/scrA)-1) G4double g1=0.0; if(lambda1>DBL_MIN) g1 = lambda0/lambda1; G4double logx0,x1,delta; G4double x0=g1/2.; do { logx0=std::log(1.+1./x0); x1 = x0-(x0*((1.+x0)*logx0-1.0)-g1/2.)/( (1.+2.*x0)*logx0-2.0); delta = std::abs( x1 - x0 ); x0 = x1; } while (delta > 1.0e-12); G4double scrA = x1; G4double lambdan=0.; if(lambda0>0.)lambdan=tPathLength/lambda0; if(lambdan<=1.0e-12)return; G4double lambdan12=0.5*lambdan; Qn1 = lambdan *g1;//2.* lambdan *scrA*((1.+scrA)*log(1.+1./scrA)-1.); Qn12 = 0.5*Qn1; G4double cosTheta1,sinTheta1,cosTheta2,sinTheta2; G4double cosPhi1=1.0,sinPhi1=0.0,cosPhi2=1.0,sinPhi2=0.0; G4double us=0.0,vs=0.0,ws=1.0,wss=0.,x_coord=0.0,y_coord=0.0,z_coord=1.0; G4double epsilon1=G4UniformRand(); G4double expn = std::exp(-lambdan); if(epsilon12.)xi=2.; ws=1.-xi; wss=std::sqrt(xi*(2.-xi)); G4double phi0=CLHEP::twopi*G4UniformRand(); us=wss*cos(phi0); vs=wss*sin(phi0); } else // multiple scattering { // Ref.2 subsection 4.4 "The best solution found" // Sample first substep scattering angle SampleCosineTheta(lambdan12,scrA,cosTheta1,sinTheta1); G4double phi1 = CLHEP::twopi*G4UniformRand(); cosPhi1 = cos(phi1); sinPhi1 = sin(phi1); // Sample second substep scattering angle SampleCosineTheta(lambdan12,scrA,cosTheta2,sinTheta2); G4double phi2 = CLHEP::twopi*G4UniformRand(); cosPhi2 = cos(phi2); sinPhi2 = sin(phi2); // Overall scattering direction us = sinTheta2*(cosTheta1*cosPhi1*cosPhi2 - sinPhi1*sinPhi2) + cosTheta2*sinTheta1*cosPhi1; vs = sinTheta2*(cosTheta1*sinPhi1*cosPhi2 + cosPhi1*sinPhi2) + cosTheta2*sinTheta1*sinPhi1; ws = cosTheta1*cosTheta2 - sinTheta1*sinTheta2*cosPhi2; G4double sqrtA=sqrt(scrA); if(acos(ws)1.)&&(i<20));//i<20 to avoid time consuming during the run if(i>=19)ws=cos(sqrtA); wss=std::sqrt((1.-ws)*(1.0+ws)); us=wss*cos(phi1); vs=wss*sin(phi1); } } G4ThreeVector oldDirection = dynParticle->GetMomentumDirection(); G4ThreeVector newDirection(us,vs,ws); newDirection.rotateUz(oldDirection); fParticleChange->ProposeMomentumDirection(newDirection); if((safety > tlimitminfix)&&latDisplasment) { if(Qn1<0.02)// corresponding to error less than 1% in the exact formula of z_coord = 1.0 - Qn1*(0.5 - Qn1/6.); else z_coord = (1.-std::exp(-Qn1))/Qn1; G4double rr=std::sqrt((1.- z_coord*z_coord)/(1.-ws*ws)); x_coord = rr*us; y_coord = rr*vs; // displacement is computed relatively to the end point z_coord -= 1.0; rr = std::sqrt(x_coord*x_coord+y_coord*y_coord+z_coord*z_coord); G4double r = rr*zPathLength; /* G4cout << "G4GS::SampleSecondaries: e(MeV)= " << kineticEnergy << " sinTheta= " << sqrt(1.0 - ws*ws) << " r(mm)= " << r << " trueStep(mm)= " << tPathLength << " geomStep(mm)= " << zPathLength << G4endl; */ if(tPathLength<=zPathLength)return; if(r > tlimitminfix) { G4ThreeVector Direction(x_coord/rr,y_coord/rr,z_coord/rr); Direction.rotateUz(oldDirection); ComputeDisplacement(fParticleChange, Direction, r, safety); } } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... void G4GoudsmitSaundersonMscModel::SampleCosineTheta(G4double lambdan, G4double scrA, G4double &cost, G4double &sint) { G4double xi=0.; if (Qn12<0.001) {G4double r1,tet; do{ r1=G4UniformRand(); xi=-Qn12*log(G4UniformRand()); tet=acos(1.-xi); }while(tet*r1*r1>sin(tet)); } else if(Qn12>0.5)xi=2.*G4UniformRand(); else xi=2.*(GSTable->SampleTheta(lambdan,scrA,G4UniformRand())); if(xi<0.)xi=0.; else if(xi>2.)xi=2.; cost=(1. - xi); sint=sqrt(xi*(2.-xi)); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... // Polynomial log-log interpolation of Lambda0 and Lambda1 between 100 eV - 1 GeV // linear log-log extrapolation between 1 GeV - 100 TeV void G4GoudsmitSaundersonMscModel::CalculateIntegrals(const G4ParticleDefinition* p,G4double Z, G4double kinEnergy,G4double &Sig0, G4double &Sig1) { G4double x1,x2,y1,y2,acoeff,bcoeff; G4double kineticE = kinEnergy; if(kineticEhighKEnergy)kineticE=highKEnergy; kineticE /= eV; G4double logE=std::log(kineticE); G4int iZ = G4int(Z); if(iZ > 103) iZ = 103; G4int enerInd=0; for(G4int i=0;i<105;i++) { if((logE>=ener[i])&&(logEg->t step transformations taken from Ref.6 G4double G4GoudsmitSaundersonMscModel::ComputeTruePathLengthLimit(const G4Track& track, G4PhysicsTable* theTable, G4double currentMinimalStep) { tPathLength = currentMinimalStep; G4StepPoint* sp = track.GetStep()->GetPreStepPoint(); G4StepStatus stepStatus = sp->GetStepStatus(); const G4DynamicParticle* dp = track.GetDynamicParticle(); if(stepStatus == fUndefined) { inside = false; insideskin = false; tlimit = geombig; SetParticle( dp->GetDefinition() ); } theLambdaTable = theTable; currentCouple = track.GetMaterialCutsCouple(); currentMaterialIndex = currentCouple->GetIndex(); currentKinEnergy = dp->GetKineticEnergy(); currentRange = theManager->GetRangeFromRestricteDEDX(particle,currentKinEnergy,currentCouple); lambda1 = GetLambda(currentKinEnergy); // stop here if small range particle if(inside) return tPathLength; if(tPathLength > currentRange) tPathLength = currentRange; G4double presafety = sp->GetSafety(); //G4cout << "G4GS::StepLimit tPathLength= " // < 0.0) aRead = log(aRead); else aRead = 0.0; ener[i]=aRead; } for(G4int j=0;j<103;j++){ for(G4int i=0;i<106;i++){ fscanf(infile,"%f\t",&aRead); if(aRead > 0.0) aRead = log(aRead); else aRead = 0.0; TCSE[j][i]=aRead; } } for(G4int j=0;j<103;j++){ for(G4int i=0;i<106;i++){ fscanf(infile,"%f\t",&aRead); if(aRead > 0.0) aRead = log(aRead); else aRead = 0.0; FTCSE[j][i]=aRead; } } for(G4int j=0;j<103;j++){ for(G4int i=0;i<106;i++){ fscanf(infile,"%f\t",&aRead); if(aRead > 0.0) aRead = log(aRead); else aRead = 0.0; TCSP[j][i]=aRead; } } for(G4int j=0;j<103;j++){ for(G4int i=0;i<106;i++){ fscanf(infile,"%f\t",&aRead); if(aRead > 0.0) aRead = log(aRead); else aRead = 0.0; FTCSP[j][i]=aRead; } } fclose(infile); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......