// // ******************************************************************** // * 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. * // ******************************************************************** // // Author: Alexei Sytov // Co-author: Gianfranco PaternĂ² (modifications & testing) // On the base of the CRYSTALRAD realization of scattering model: // A. I. Sytov, V. V. Tikhomirov, and L. Bandiera PRAB 22, 064601 (2019) #include "G4VChannelingFastSimCrystalData.hh" #include "G4SystemOfUnits.hh" #include "G4PhysicalConstants.hh" #include "G4Log.hh" G4VChannelingFastSimCrystalData::G4VChannelingFastSimCrystalData() { } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4VChannelingFastSimCrystalData::~G4VChannelingFastSimCrystalData(){;} //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VChannelingFastSimCrystalData::SetGeometryParameters (const G4LogicalVolume *crystallogic) { G4int crystalID = crystallogic->GetInstanceID(); //set bending angle if the it exists in the list, otherwise default = 0 (fMapBendingAngle.count(crystalID) > 0) ? SetBendingAngle(fMapBendingAngle[crystalID],crystallogic) : SetBendingAngle(0.,crystallogic); //set miscut angle if the it exists in the list, otherwise default = 0 (fMapMiscutAngle.count(crystalID) > 0) ? SetMiscutAngle(fMapMiscutAngle[crystalID],crystallogic) : SetMiscutAngle(0.,crystallogic); //set crystalline undulator parameters if they exist in the list, //otherwise default = G4ThreeVector(0,0,0). (fMapCUAmplitudePeriodPhase.count(crystalID) > 0) ? SetCUParameters(fMapCUAmplitudePeriodPhase[crystalID],crystallogic) : SetCUParameters(G4ThreeVector(0.,0.,0.),crystallogic); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VChannelingFastSimCrystalData::SetBendingAngle(G4double tetab, const G4LogicalVolume* crystallogic) { G4int crystalID = crystallogic->GetInstanceID(); //set the bending angle for this logical volume fMapBendingAngle[crystalID]=tetab; G4ThreeVector limboxmin;//minimal limits of the box bounding the logical volume G4ThreeVector limboxmax;//maximal limits of the box bounding the logical volume //save the limits of the box bounding the logical volume crystallogic->GetSolid()->BoundingLimits(limboxmin,limboxmax); //bounding box half dimensions fHalfDimBoundingBox = (limboxmax-limboxmin)/2.; G4double lcr = limboxmax.getZ()-limboxmin.getZ();//crystal thickness fBendingAngle=std::abs(tetab); if (fBendingAngle<0.000001)//no bending less then 1 urad { if(fBendingAngle>DBL_EPSILON) { G4cout << "Channeling model: volume " << crystallogic->GetName() << G4endl; G4cout << "Warning: bending angle is lower than 1 urad => set to 0" << G4endl; } fBent=0; fBendingAngle=0.; fBendingR=0.;//just for convenience (infinity in reality) fBending2R=0.; fBendingRsquare=0.; fCurv=0.; fCorrectionZ = 1.; } else { fBent=1; fBendingR=lcr/fBendingAngle; fBending2R=2.*fBendingR; fBendingRsquare=fBendingR*fBendingR; fCurv=1./fBendingR; if (tetab<0.) { G4cout << "Channeling model: volume " << crystallogic->GetName() << G4endl; G4cout << "Warning: bending angle is negative => set to be positive" << G4endl; } } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VChannelingFastSimCrystalData::SetMiscutAngle(G4double tetam, const G4LogicalVolume *crystallogic) { G4int crystalID = crystallogic->GetInstanceID(); //set the bending angle for this logical volume fMapMiscutAngle[crystalID]=tetam; // fMiscutAngle>0: rotation of xz coordinate planes clockwise in the xz plane fMiscutAngle=tetam; if (std::abs(tetam)>1.*mrad) { G4cout << "Channeling model: volume " << crystallogic->GetName() << G4endl; G4cout << "Warning: miscut angle is higher than 1 mrad => " << G4endl; G4cout << "coordinate transformation routines may be unstable" << G4endl; } fCosMiscutAngle=std::cos(fMiscutAngle); fSinMiscutAngle=std::sin(fMiscutAngle); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VChannelingFastSimCrystalData::SetCrystallineUndulatorParameters( G4double amplitude, G4double period, G4double phase, const G4LogicalVolume *crystallogic) { if (amplitudeGetName() << G4endl; G4cout << "Warning: The crystalline undulator parameters are out of range " "=> the crystalline undulator mode switched off" << G4endl; } SetCUParameters(G4ThreeVector(amplitude,period,phase),crystallogic); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VChannelingFastSimCrystalData::SetCUParameters( const G4ThreeVector &litudePeriodPhase, const G4LogicalVolume *crystallogic) { G4int crystalID = crystallogic->GetInstanceID(); //set the crystalline undulator parameters for this logical volume fMapCUAmplitudePeriodPhase[crystalID]=amplitudePeriodPhase; fCUAmplitude=amplitudePeriodPhase.x(); G4double period = amplitudePeriodPhase.y(); fCUPhase = amplitudePeriodPhase.z(); //if the amplidude of the crystalline undulator is 0 => no undulator if(fCUAmplitude>DBL_EPSILON&&period>DBL_EPSILON) { //crystalline undulator flag fCU = true; fCUK = CLHEP::twopi/period; if(fBendingAngle>DBL_EPSILON) { //bent and periodically bent crystal are not compatible SetBendingAngle(0,crystallogic); G4cout << "Channeling model: volume " << crystallogic->GetName() << G4endl; G4cout << "Warning: crystalline undulator is not compatible with " "a bent crystal mode => setting bending angle to 0." << G4endl; } } else { fCU = false; fCUAmplitude = 0.; fCUK = 0.; fCUPhase = 0.; fMapCUAmplitudePeriodPhase[crystalID] = G4ThreeVector(0.,0.,0.); } fCUK2 = fCUK*fCUK; fCUAmplitudeK = fCUAmplitude*fCUK; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VChannelingFastSimCrystalData::SetParticleProperties(G4double etotal, G4double mass, G4double charge, const G4String& particleName) { G4double teta1; fZ2=charge; G4double zz22=fZ2*fZ2; fParticleName=particleName; // particle momentum and energy G4double t=etotal*etotal-mass*mass; // economy of operations fPz=std::sqrt(t); // momentum of particle fPV=t/etotal; // pv fBeta=fPz/etotal; // velocity/c fTetaL = std::sqrt(std::abs(fZ2)*fVmax2/fPV); //Lindhard angle fChannelingStep = fChangeStep/fTetaL; //standard simulation step // Energy losses fV2 = fBeta*fBeta; // particle (velocity/c)^2 fGamma = etotal/mass; // Lorentz factor fMe2Gamma = 2*CLHEP::electron_mass_c2*fGamma; // max ionization losses fTmax = fMe2Gamma*fGamma*fV2/ (CLHEP::electron_mass_c2/mass*CLHEP::electron_mass_c2/mass + 1. + fMe2Gamma/mass); // max ionization losses for electrons if(fParticleName=="e-"){fTmax/=2;} for(G4int i=0; ino scattering fPzu11[i]=fPu11[i]*fPz*fPz; teta1=teta1/fPz; // fTeta12[i]=teta1*teta1; // maximal scattering angle by coulomb scattering on nuclei // defining by nucleus radius // tetamax=hc/(fPz*1.D-6*fR0*fAN**(1.D0/3.D0))// {Mev*fermi/(MeV*fermi)} G4double tetamax=fTetamax0[i]/fPz; fTetamax2[i]=tetamax*tetamax; fTetamax12[i]=fTeta12[i]+fTetamax2[i]; // a coefficient in a formula for scattering (for high speed of simulation) // fK2=(fZ2)**2*alphahbarc2*4.*pi*fN0*(fZ1/fPV)**2 fK2[i]=fK20[i]*zz22/fPV/fPV; } // fK3=(fZ2)**2*alphahbarc2*pi/electron_mass_c2/(fV2)**2 fK3=fK30*zz22/fV2; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VChannelingFastSimCrystalData::GetLindhardAngle(G4double etotal, G4double mass, G4double charge) { G4double pv0 = etotal-mass*mass/etotal; return std::sqrt(2*std::abs(charge)*fVmax/pv0); //Calculate the value of the Lindhard angle //(!!! the value for a straight crystal) } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VChannelingFastSimCrystalData::GetLindhardAngle() { return fTetaL; //return the Lindhard angle value calculated in SetParticleProperties } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VChannelingFastSimCrystalData::GetSimulationStep(G4double tx,G4double ty) { G4double simulationstep; //find angle of particle w.r.t. the plane or axis G4double angle=0.; if (iModel==1)//1D model { angle = std::abs(tx); } else if (iModel==2)//2D model { angle = std::sqrt(tx*tx+ty*ty); } //compare this angle with the Lindhard angle if (angle 0.0) { simulationstep /= angle; } } return simulationstep; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VChannelingFastSimCrystalData::GetMaxSimulationStep(G4double etotal, G4double mass, G4double charge) { //standard value of step for channeling particles which is the maximal possible step return fChangeStep/GetLindhardAngle(etotal, mass, charge); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4ThreeVector G4VChannelingFastSimCrystalData::CoulombAtomicScattering( G4double effectiveStep, G4double step, G4int ielement) { G4double tx = 0.;//horizontal scattering angle G4double ty = 0.;//vertical scattering angle G4double ksi=0.1; // calculation of the teta2-minimal possible angle of a single scattering G4double e1=fK2[ielement]*effectiveStep; //for high speed of a program // (real formula is (4*pi*fN0*wpl(x)*dz*fZ1*zz2*alpha*hdc/fPV)**2) G4double teta122=fTetamax12[ielement]/(ksi*fTetamax12[ielement]/e1+1.); // teta122=fTeta12+teta22=teta1^2+teta2^2 G4double teta22; G4double t; // if the angle of a single scattering is less teta1 - minimal possible // angle of coulomb scattering defining by the electron shielding than // multiple scattering by both nuclei and electrons and electrons will not // occur => minimal possible angle of a single scattering is equal to teta1 if (teta122<=fTeta12[ielement]*1.000125) { teta22=0.; teta122=fTeta12[ielement]; } else { teta22=teta122-fTeta12[ielement]; G4double aa=teta22/fTeta12[ielement]; G4double aa1=1.+aa; // crystal, with scattering suppression G4double tetamsi=e1*(G4Log(aa1)+ (1.-std::exp(-aa*fBB[ielement]))/aa1+ fBBDEXP[ielement]* (expint(fBB[ielement]*aa1)-fE1XBbb[ielement])); // sumilation of multiple coulomb scattering by nuclei and electrons // for high speed of a program, real formula is // 4*pi*fN0*wpl(x)*dz*(fZ1*zz2*alpha*hdc/fPV)**2* // *(ln(1+a)+(1-exp(-a*b))/(1+a)+(1+b)*exp(b)*(E1XB(b*(1+a))-E1XB(b))) ksi=G4UniformRand(); t=std::sqrt(-tetamsi*G4Log(ksi)); ksi=G4UniformRand(); tx+=t*std::cos(CLHEP::twopi*ksi); ty+=t*std::sin(CLHEP::twopi*ksi); } // simulation of single coulomb scattering by nuclei (with screened potential) G4double zss=0.; G4double dzss=step; // (calculation of a distance, at which another single scattering can happen) ksi=G4UniformRand(); zss=-G4Log(ksi)*step/(e1*(1./teta122-1./fTetamax12[ielement])); G4double tt; // At some step several single scattering can occur. // So,if the distance of the next scattering is less than the step, // another scattering can occur. If the distance of the next scattering // is less than the difference between the step and the distance of // the previous scattering, another scattering can occur. And so on, and so on. // In the cycle we simulate each of them. The cycle is finished, when // the remaining part of step is less than a distance of the next single scattering. //******************************************** // if at a step a single scattering occurs while (zssDBL_EPSILON)) { // (calculation of a distance, at which another single scattering can happen) // simulation of scattering length (by the same way single scattering by nucleus ksi=G4UniformRand(); zss=-1.0*G4Log(ksi)/(fK3*electronDensity)/(1./eMinIonization-1./fTmax); //******************************************** // if at a step a single scattering occur while (zssDBL_EPSILON) //to be sure e1=1; K--) { T0=K/(1.0+K/(X+T0)); } T=1.0/(X+T0); E1=std::exp(-X)*T; } return E1; }