// // ******************************************************************** // * 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: G4VXTRenergyLoss.cc,v 1.45 2010/06/16 15:34:15 gcosmo Exp $ // GEANT4 tag $Name: geant4-09-04-beta-01 $ // // History: // 2001-2002 R&D by V.Grichine // 19.06.03 V. Grichine, modifications in BuildTable for the integration // in respect of angle: range is increased, accuracy is // improved // 28.07.05, P.Gumplinger add G4ProcessType to constructor // 28.09.07, V.Ivanchenko general cleanup without change of algorithms // #include "G4Timer.hh" #include "G4VXTRenergyLoss.hh" #include "G4Poisson.hh" #include "G4MaterialTable.hh" #include "G4VDiscreteProcess.hh" #include "G4VParticleChange.hh" #include "G4VSolid.hh" #include "G4RotationMatrix.hh" #include "G4ThreeVector.hh" #include "G4AffineTransform.hh" #include "G4SandiaTable.hh" #include "G4PhysicsVector.hh" #include "G4PhysicsFreeVector.hh" #include "G4PhysicsLinearVector.hh" //////////////////////////////////////////////////////////////////////////// // // Constructor, destructor G4VXTRenergyLoss::G4VXTRenergyLoss(G4LogicalVolume *anEnvelope, G4Material* foilMat,G4Material* gasMat, G4double a, G4double b, G4int n,const G4String& processName, G4ProcessType type) : G4VDiscreteProcess(processName, type), fGammaCutInKineticEnergy(0), fGammaTkinCut(0), fAngleDistrTable(0), fEnergyDistrTable(0), fPlatePhotoAbsCof(0), fGasPhotoAbsCof(0), fAngleForEnergyTable(0) { verboseLevel = 1; // Initialization of local constants fTheMinEnergyTR = 1.0*keV; fTheMaxEnergyTR = 100.0*keV; fTheMaxAngle = 1.0e-3; fTheMinAngle = 5.0e-6; fBinTR = 50; fMinProtonTkin = 100.0*GeV; fMaxProtonTkin = 100.0*TeV; fTotBin = 50; // Proton energy vector initialization fProtonEnergyVector = new G4PhysicsLogVector(fMinProtonTkin, fMaxProtonTkin, fTotBin ); fXTREnergyVector = new G4PhysicsLogVector(fTheMinEnergyTR, fTheMaxEnergyTR, fBinTR ); fPlasmaCof = 4.0*pi*fine_structure_const*hbarc*hbarc*hbarc/electron_mass_c2; fCofTR = fine_structure_const/pi; fEnvelope = anEnvelope ; fPlateNumber = n ; if(verboseLevel > 0) G4cout<<"### G4VXTRenergyLoss: the number of TR radiator plates = " < 0) G4cout<<"total radiator thickness = "<GetIndex() ; if(verboseLevel > 0) G4cout<<"plate material = "<GetName()<GetIndex() ; if(verboseLevel > 0) G4cout<<"gas material = "<GetName()<GetElectronDensity() ; // fSigma1 = (20.9*eV)*(20.9*eV) ; if(verboseLevel > 0) G4cout<<"plate plasma energy = "<GetElectronDensity() ; if(verboseLevel > 0) G4cout<<"gas plasma energy = "<GetLogicalVolume() != fEnvelope ) lambda = DBL_MAX; else { const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle(); kinEnergy = aParticle->GetKineticEnergy(); mass = aParticle->GetDefinition()->GetPDGMass(); gamma = 1.0 + kinEnergy/mass; if(verboseLevel > 1) { G4cout<<" gamma = "< 0) G4cout<<"Build angle distribution according the transparent regular radiator" < fTheMinEnergyTR) fMinEnergyTR = fGammaTkinCut ; else fMinEnergyTR = fTheMinEnergyTR ; if(fGammaTkinCut > fTheMaxEnergyTR) fMaxEnergyTR = 2.0*fGammaTkinCut ; else fMaxEnergyTR = fTheMaxEnergyTR ; G4cout.precision(4) ; G4Timer timer ; timer.Start() ; if(verboseLevel > 0) { G4cout< GetLowEdgeEnergy(iTkin)/proton_mass_c2) ; fMaxThetaTR = 25.0/(fGamma*fGamma) ; // theta^2 fTheMinAngle = 1.0e-3 ; // was 5.e-6, e-6 !!!, e-5, e-4 if( fMaxThetaTR > fTheMaxAngle ) fMaxThetaTR = fTheMaxAngle; else { if( fMaxThetaTR < fTheMinAngle ) fMaxThetaTR = fTheMinAngle; } G4PhysicsLinearVector* angleVector = new G4PhysicsLinearVector(0.0, fMaxThetaTR, fBinTR ); G4double energySum = 0.0; G4double angleSum = 0.0; G4Integrator integral; energyVector->PutValue(fBinTR-1,energySum); angleVector->PutValue(fBinTR-1,angleSum); for( iTR = fBinTR - 2 ; iTR >= 0 ; iTR-- ) { energySum += radiatorCof*fCofTR*integral.Legendre10( this,&G4VXTRenergyLoss::SpectralXTRdEdx, energyVector->GetLowEdgeEnergy(iTR), energyVector->GetLowEdgeEnergy(iTR+1) ); // angleSum += fCofTR*integral.Legendre96( // this,&G4VXTRenergyLoss::AngleXTRdEdx, // angleVector->GetLowEdgeEnergy(iTR), // angleVector->GetLowEdgeEnergy(iTR+1) ); energyVector->PutValue(iTR,energySum/fTotalDist); // angleVector ->PutValue(iTR,angleSum); } if(verboseLevel > 0) { G4cout // < fTheMinEnergyTR) fMinEnergyTR = fGammaTkinCut; else fMinEnergyTR = fTheMinEnergyTR; if(fGammaTkinCut > fTheMaxEnergyTR) fMaxEnergyTR = 2.0*fGammaTkinCut; else fMaxEnergyTR = fTheMaxEnergyTR; G4cout.precision(4); G4Timer timer; timer.Start(); if(verboseLevel > 0) { G4cout< GetLowEdgeEnergy(iTkin)/proton_mass_c2) ; fMaxThetaTR = 25.0/(fGamma*fGamma) ; // theta^2 fTheMinAngle = 1.0e-3 ; // was 5.e-6, e-6 !!!, e-5, e-4 if( fMaxThetaTR > fTheMaxAngle ) fMaxThetaTR = fTheMaxAngle; else { if( fMaxThetaTR < fTheMinAngle ) fMaxThetaTR = fTheMinAngle; } fAngleForEnergyTable = new G4PhysicsTable(fBinTR); for( iTR = 0; iTR < fBinTR; iTR++ ) { // energy = fMinEnergyTR*(iTR+1); energy = fXTREnergyVector->GetLowEdgeEnergy(iTR); G4PhysicsFreeVector* angleVector = new G4PhysicsFreeVector(fBinTR); angleVector = GetAngleVector(energy,fBinTR); // G4cout<insertAt(iTR,angleVector) ; } fAngleBank.push_back(fAngleForEnergyTable); } timer.Stop(); G4cout.precision(6); if(verboseLevel > 0) { G4cout< kMin) kMin++; kMax = kMin + fBinTR -1; if(verboseLevel > 2) { G4cout<<"n-1 = "< GetLowEdgeEnergy(iTkin)/proton_mass_c2) ; fMaxThetaTR = 25.0/(fGamma*fGamma) ; // theta^2 fTheMinAngle = 1.0e-3 ; // was 5.e-6, e-6 !!!, e-5, e-4 if( fMaxThetaTR > fTheMaxAngle ) fMaxThetaTR = fTheMaxAngle; else { if( fMaxThetaTR < fTheMinAngle ) fMaxThetaTR = fTheMinAngle; } G4PhysicsLinearVector* angleVector = new G4PhysicsLinearVector(0.0, fMaxThetaTR, fBinTR ); angleSum = 0.0; G4Integrator integral; angleVector->PutValue(fBinTR-1,angleSum); for( iTR = fBinTR - 2 ; iTR >= 0 ; iTR-- ) { angleSum += radiatorCof*fCofTR*integral.Legendre96( this,&G4VXTRenergyLoss::AngleXTRdEdx, angleVector->GetLowEdgeEnergy(iTR), angleVector->GetLowEdgeEnergy(iTR+1) ); angleVector ->PutValue(iTR,angleSum); } if(verboseLevel > 1) { G4cout // < 1) { G4cout<<"Start of G4VXTRenergyLoss::PostStepDoIt "<GetKineticEnergy() ; G4double mass = aParticle->GetDefinition()->GetPDGMass() ; G4double gamma = 1.0 + kinEnergy/mass ; if(verboseLevel > 1 ) { G4cout<<"gamma = "<GetPosition(); G4ParticleMomentum direction = aParticle->GetMomentumDirection(); G4double startTime = pPostStepPoint->GetGlobalTime(); for( iTkin = 0; iTkin < fTotBin; iTkin++ ) { if(TkinScaled < fProtonEnergyVector->GetLowEdgeEnergy(iTkin)) break; } iPlace = iTkin - 1; if(iTkin == 0) // Tkin is too small, neglect of TR photon generation { if( verboseLevel > 0) { G4cout<<"Go out from G4VXTRenergyLoss::PostStepDoIt:iTkin = "< 1) { G4cout<<"energyTR = "< 0.) theta = std::sqrt(theta2); else theta = theta2; } else theta = std::fabs(G4RandGauss::shoot(0.0,pi/gamma)); if( theta >= 0.1 ) theta = 0.1; // G4cout<<" : theta = "<GetTouchable()->GetRotation(); G4ThreeVector transl = pPostStepPoint->GetTouchable()->GetTranslation(); G4AffineTransform transform = G4AffineTransform(rotM,transl); transform.Invert(); G4ThreeVector localP = transform.TransformPoint(position); G4ThreeVector localV = transform.TransformAxis(directionTR); G4double distance = fEnvelope->GetSolid()->DistanceToOut(localP, localV); if(verboseLevel > 1) { G4cout<<"distance to exit = "<SetTouchableHandle( aStep.GetPostStepPoint()->GetTouchableHandle()); aSecondaryTrack->SetParentID( aTrack.GetTrackID() ); fParticleChange.AddSecondary(aSecondaryTrack); fParticleChange.ProposeEnergy(kinEnergy); } } return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep); } /////////////////////////////////////////////////////////////////////// // // This function returns the spectral and angle density of TR quanta // in X-ray energy region generated forward when a relativistic // charged particle crosses interface between two materials. // The high energy small theta approximation is applied. // (matter1 -> matter2, or 2->1) // varAngle =2* (1 - std::cos(theta)) or approximately = theta*theta // G4complex G4VXTRenergyLoss::OneInterfaceXTRdEdx( G4double energy, G4double gamma, G4double varAngle ) { G4complex Z1 = GetPlateComplexFZ(energy,gamma,varAngle) ; G4complex Z2 = GetGasComplexFZ(energy,gamma,varAngle) ; G4complex zOut = (Z1 - Z2)*(Z1 - Z2) * (varAngle*energy/hbarc/hbarc) ; return zOut ; } ////////////////////////////////////////////////////////////////////////////// // // For photon energy distribution tables. Integrate first over angle // G4double G4VXTRenergyLoss::SpectralAngleXTRdEdx(G4double varAngle) { G4double result = GetStackFactor(fEnergy,fGamma,varAngle); if(result < 0.0) result = 0.0; return result; } ///////////////////////////////////////////////////////////////////////// // // For second integration over energy G4double G4VXTRenergyLoss::SpectralXTRdEdx(G4double energy) { G4int i, iMax = 8; G4double result = 0.0; G4double lim[8] = { 0.0, 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1.0 }; for( i = 0; i < iMax; i++ ) lim[i] *= fMaxThetaTR; G4Integrator integral; fEnergy = energy; for( i = 0; i < iMax-1; i++ ) { result += integral.Legendre96(this,&G4VXTRenergyLoss::SpectralAngleXTRdEdx, lim[i],lim[i+1]); // result += integral.Legendre10(this,&G4VXTRenergyLoss::SpectralAngleXTRdEdx, // lim[i],lim[i+1]); } return result; } ////////////////////////////////////////////////////////////////////////// // // for photon angle distribution tables // G4double G4VXTRenergyLoss::AngleSpectralXTRdEdx(G4double energy) { G4double result = GetStackFactor(energy,fGamma,fVarAngle); if(result < 0) result = 0.0; return result; } /////////////////////////////////////////////////////////////////////////// // // The XTR angular distribution based on transparent regular radiator G4double G4VXTRenergyLoss::AngleXTRdEdx(G4double varAngle) { // G4cout<<"angle2 = "< 0) G4cout<<"energy, keV"<<"\t"<<"Zmu for plate"< 1) G4cout< 0) outPlate< 0) G4cout<<"energy, keV"<<"\t"<<"Zmu for gas"< 1) G4cout< 0) outGas<GetNumberOfElements() ; for( i = 0; i < numberOfElements; i++ ) { nowZ = (*theMaterialTable)[fMatIndex1]->GetElement(i)->GetZ(); sumZ += nowZ; xSection += GetComptonPerAtom(omega,nowZ); // *nowZ; } xSection /= sumZ; xSection *= (*theMaterialTable)[fMatIndex1]->GetElectronDensity(); return xSection; } //////////////////////////////////////////////////////////////////////// // // Computes Compton cross section for gas material in 1/mm G4double G4VXTRenergyLoss::GetGasCompton(G4double omega) { G4int i, numberOfElements; G4double xSection = 0., nowZ, sumZ = 0.; const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable(); numberOfElements = (*theMaterialTable)[fMatIndex2]->GetNumberOfElements() ; for( i = 0; i < numberOfElements; i++ ) { nowZ = (*theMaterialTable)[fMatIndex2]->GetElement(i)->GetZ(); sumZ += nowZ; xSection += GetComptonPerAtom(omega,nowZ); // *nowZ; } xSection /= sumZ; xSection *= (*theMaterialTable)[fMatIndex2]->GetElectronDensity(); return xSection; } //////////////////////////////////////////////////////////////////////// // // Computes Compton cross section per atom with Z electrons for gamma with // the energy GammaEnergy G4double G4VXTRenergyLoss::GetComptonPerAtom(G4double GammaEnergy, G4double Z) { G4double CrossSection = 0.0 ; if ( Z < 0.9999 ) return CrossSection; if ( GammaEnergy < 0.1*keV ) return CrossSection; if ( GammaEnergy > (100.*GeV/Z) ) return CrossSection; static const G4double a = 20.0 , b = 230.0 , c = 440.0; static const G4double d1= 2.7965e-1*barn, d2=-1.8300e-1*barn, d3= 6.7527 *barn, d4=-1.9798e+1*barn, e1= 1.9756e-5*barn, e2=-1.0205e-2*barn, e3=-7.3913e-2*barn, e4= 2.7079e-2*barn, f1=-3.9178e-7*barn, f2= 6.8241e-5*barn, f3= 6.0480e-5*barn, f4= 3.0274e-4*barn; G4double p1Z = Z*(d1 + e1*Z + f1*Z*Z), p2Z = Z*(d2 + e2*Z + f2*Z*Z), p3Z = Z*(d3 + e3*Z + f3*Z*Z), p4Z = Z*(d4 + e4*Z + f4*Z*Z); G4double T0 = 15.0*keV; if (Z < 1.5) T0 = 40.0*keV; G4double X = std::max(GammaEnergy, T0) / electron_mass_c2; CrossSection = p1Z*std::log(1.+2.*X)/X + (p2Z + p3Z*X + p4Z*X*X)/(1. + a*X + b*X*X + c*X*X*X); // modification for low energy. (special case for Hydrogen) if (GammaEnergy < T0) { G4double dT0 = 1.*keV; X = (T0+dT0) / electron_mass_c2 ; G4double sigma = p1Z*std::log(1.+2*X)/X + (p2Z + p3Z*X + p4Z*X*X)/(1. + a*X + b*X*X + c*X*X*X); G4double c1 = -T0*(sigma-CrossSection)/(CrossSection*dT0); G4double c2 = 0.150; if (Z > 1.5) c2 = 0.375-0.0556*std::log(Z); G4double y = std::log(GammaEnergy/T0); CrossSection *= std::exp(-y*(c1+c2*y)); } // G4cout << "e= " << GammaEnergy << " Z= " << Z << " cross= " << CrossSection << G4endl; return CrossSection; } /////////////////////////////////////////////////////////////////////// // // This function returns the spectral and angle density of TR quanta // in X-ray energy region generated forward when a relativistic // charged particle crosses interface between two materials. // The high energy small theta approximation is applied. // (matter1 -> matter2, or 2->1) // varAngle =2* (1 - std::cos(theta)) or approximately = theta*theta // G4double G4VXTRenergyLoss::OneBoundaryXTRNdensity( G4double energy,G4double gamma, G4double varAngle ) const { G4double formationLength1, formationLength2 ; formationLength1 = 1.0/ (1.0/(gamma*gamma) + fSigma1/(energy*energy) + varAngle) ; formationLength2 = 1.0/ (1.0/(gamma*gamma) + fSigma2/(energy*energy) + varAngle) ; return (varAngle/energy)*(formationLength1 - formationLength2) *(formationLength1 - formationLength2) ; } G4double G4VXTRenergyLoss::GetStackFactor( G4double energy, G4double gamma, G4double varAngle ) { // return stack factor corresponding to one interface return std::real( OneInterfaceXTRdEdx(energy,gamma,varAngle) ); } ////////////////////////////////////////////////////////////////////////////// // // For photon energy distribution tables. Integrate first over angle // G4double G4VXTRenergyLoss::XTRNSpectralAngleDensity(G4double varAngle) { return OneBoundaryXTRNdensity(fEnergy,fGamma,varAngle)* GetStackFactor(fEnergy,fGamma,varAngle) ; } ///////////////////////////////////////////////////////////////////////// // // For second integration over energy G4double G4VXTRenergyLoss::XTRNSpectralDensity(G4double energy) { fEnergy = energy ; G4Integrator integral ; return integral.Legendre96(this,&G4VXTRenergyLoss::XTRNSpectralAngleDensity, 0.0,0.2*fMaxThetaTR) + integral.Legendre10(this,&G4VXTRenergyLoss::XTRNSpectralAngleDensity, 0.2*fMaxThetaTR,fMaxThetaTR) ; } ////////////////////////////////////////////////////////////////////////// // // for photon angle distribution tables // G4double G4VXTRenergyLoss::XTRNAngleSpectralDensity(G4double energy) { return OneBoundaryXTRNdensity(energy,fGamma,fVarAngle)* GetStackFactor(energy,fGamma,fVarAngle) ; } /////////////////////////////////////////////////////////////////////////// // // G4double G4VXTRenergyLoss::XTRNAngleDensity(G4double varAngle) { fVarAngle = varAngle ; G4Integrator integral ; return integral.Legendre96(this,&G4VXTRenergyLoss::XTRNAngleSpectralDensity, fMinEnergyTR,fMaxEnergyTR) ; } ////////////////////////////////////////////////////////////////////////////// // // Check number of photons for a range of Lorentz factors from both energy // and angular tables void G4VXTRenergyLoss::GetNumberOfPhotons() { G4int iTkin ; G4double gamma, numberE ; std::ofstream outEn("numberE.dat", std::ios::out ) ; outEn.setf( std::ios::scientific, std::ios::floatfield ); std::ofstream outAng("numberAng.dat", std::ios::out ) ; outAng.setf( std::ios::scientific, std::ios::floatfield ); for(iTkin=0;iTkin GetLowEdgeEnergy(iTkin)/proton_mass_c2) ; numberE = (*(*fEnergyDistrTable)(iTkin))(0) ; // numberA = (*(*fAngleDistrTable)(iTkin))(0) ; if(verboseLevel > 1) G4cout< 0) outEn<= ( (*(*fEnergyDistrTable)(iPlace))(iTransfer)*W1 + (*(*fEnergyDistrTable)(iPlace+1))(iTransfer)*W2) ) break ; } transfer = GetXTRenergy(iPlace,position,iTransfer); } // G4cout<<"XTR transfer = "<GetLowEdgeEnergy(iTransfer) ; } else { y1 = (*(*fEnergyDistrTable)(iPlace))(iTransfer-1) ; y2 = (*(*fEnergyDistrTable)(iPlace))(iTransfer) ; x1 = (*fEnergyDistrTable)(iPlace)->GetLowEdgeEnergy(iTransfer-1) ; x2 = (*fEnergyDistrTable)(iPlace)->GetLowEdgeEnergy(iTransfer) ; if ( x1 == x2 ) result = x2 ; else { if ( y1 == y2 ) result = x1 + (x2 - x1)*G4UniformRand() ; else { result = x1 + (position - y1)*(x2 - x1)/(y2 - y1) ; } } } return result ; } ///////////////////////////////////////////////////////////////////////// // // Get XTR photon angle at given energy and Tkin G4double G4VXTRenergyLoss::GetRandomAngle( G4double energyXTR, G4int iTkin ) { G4int iTR, iAngle; G4double position, angle; if (iTkin == fTotBin) iTkin--; fAngleForEnergyTable = fAngleBank[iTkin]; for( iTR = 0; iTR < fBinTR; iTR++ ) { if( energyXTR < fXTREnergyVector->GetLowEdgeEnergy(iTR) ) break; } if (iTR == fBinTR) iTR--; position = (*(*fAngleForEnergyTable)(iTR))(0)*G4UniformRand() ; for(iAngle = 0;;iAngle++) { if(position >= (*(*fAngleForEnergyTable)(iTR))(iAngle)) break ; } angle = GetAngleXTR(iTR,position,iAngle); return angle; } //////////////////////////////////////////////////////////////////////// // // Returns approximate position of X-ray photon angle at given energy during random sampling // over integral energy distribution G4double G4VXTRenergyLoss::GetAngleXTR( G4int iPlace, G4double position, G4int iTransfer ) { G4double x1, x2, y1, y2, result ; if(iTransfer == 0) { result = (*fAngleForEnergyTable)(iPlace)->GetLowEdgeEnergy(iTransfer) ; } else { y1 = (*(*fAngleForEnergyTable)(iPlace))(iTransfer-1) ; y2 = (*(*fAngleForEnergyTable)(iPlace))(iTransfer) ; x1 = (*fAngleForEnergyTable)(iPlace)->GetLowEdgeEnergy(iTransfer-1) ; x2 = (*fAngleForEnergyTable)(iPlace)->GetLowEdgeEnergy(iTransfer) ; if ( x1 == x2 ) result = x2 ; else { if ( y1 == y2 ) result = x1 + (x2 - x1)*G4UniformRand() ; else { result = x1 + (position - y1)*(x2 - x1)/(y2 - y1) ; } } } return result ; } // // ///////////////////////////////////////////////////////////////////////