Import Geant4 0.0.0 source tree

This commit is contained in:
Gabriele Cosmo
2016-06-01 15:25:35 +02:00
parent 54d6b71f95
commit b97f8d0df7
3237 changed files with 807095 additions and 0 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,592 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4MuBremsstrahlung.cc,v 2.6 1998/11/13 13:38:35 urban Exp $
// GEANT4 tag $Name: geant4-00 $
//
//
// --------------------------------------------------------------
// GEANT 4 class implementation file
//
// For information related to this code contact:
// CERN, CN Division, ASD group
// History: first implementation, based on object model of
// 2nd December 1995, G.Cosmo
// -------- G4MuBremsstrahlung physics process ---------
// by Laszlo Urban, September 1997
//
// 08-04-98: remove 'tracking cut' of muon in DoIt, MMa
// 26/10/98: new cross section of R.Kokoulin,cleanup , L.Urban
// --------------------------------------------------------------
#include "G4MuBremsstrahlung.hh"
#include "G4UnitsTable.hh"
// static members ........
G4int G4MuBremsstrahlung::nzdat = 5 ;
G4double G4MuBremsstrahlung::zdat[]={1.,4.,13.,29.,92.};
G4double G4MuBremsstrahlung::adat[]={1.01,9.01,26.98,63.55,238.03};
G4int G4MuBremsstrahlung::ntdat = 8 ;
G4double G4MuBremsstrahlung::tdat[]={1.e3,1.e4,1.e5,1.e6,1.e7,1.e8,1.e9,1.e10};
G4int G4MuBremsstrahlung::NBIN = 100 ; //500 ;
G4double G4MuBremsstrahlung::ya[1000]={0.};
G4double G4MuBremsstrahlung::proba[5][8][1000]={0.};
// constructor
G4MuBremsstrahlung::G4MuBremsstrahlung(const G4String& processName)
: G4MuEnergyLoss(processName),
theMeanFreePathTable(NULL),
LowestKineticEnergy (1.*GeV),
HighestKineticEnergy (1000000.*TeV),
TotBin(100),
theGamma (G4Gamma::Gamma() ),
theMuonMinus ( G4MuonMinus::MuonMinus() ),
theMuonPlus ( G4MuonPlus::MuonPlus() )
{ }
G4MuBremsstrahlung::~G4MuBremsstrahlung()
{
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable;
}
if (&PartialSumSigma) {
PartialSumSigma.clearAndDestroy();
}
}
void G4MuBremsstrahlung::SetPhysicsTableBining(G4double lowE, G4double highE,
G4int nBins)
{
LowestKineticEnergy = lowE; HighestKineticEnergy = highE ; TotBin = nBins ;
}
void G4MuBremsstrahlung::BuildPhysicsTable(
const G4ParticleDefinition& aParticleType)
{
BuildLossTable(aParticleType) ;
if(&aParticleType==theMuonMinus)
{
RecorderOfmuminusProcess[CounterOfmuminusProcess] = (*this).theLossTable ;
CounterOfmuminusProcess++;
}
else
{
RecorderOfmuplusProcess[CounterOfmuplusProcess] = (*this).theLossTable ;
CounterOfmuplusProcess++;
}
if(theMeanFreePathTable == NULL)
MakeSamplingTables(&aParticleType) ;
BuildLambdaTable(aParticleType) ;
G4MuEnergyLoss::BuildDEDXTable(aParticleType) ;
if(&aParticleType == theMuonPlus)
PrintInfoDefinition() ;
}
void G4MuBremsstrahlung::BuildLossTable(
const G4ParticleDefinition& aParticleType)
{
G4double KineticEnergy,TotalEnergy,bremloss,Z,
loss,natom,Cut ;
const G4MaterialTable* theMaterialTable =
G4Material::GetMaterialTable();
ParticleMass = aParticleType.GetPDGMass();
GammaCutInKineticEnergy = (*theGamma).GetEnergyCuts() ;
G4int numOfMaterials = theMaterialTable->length() ;
if (theLossTable) {
theLossTable->clearAndDestroy();
delete theLossTable;
}
theLossTable = new G4PhysicsTable(numOfMaterials) ;
for (G4int J=0; J<numOfMaterials; J++)
{
G4PhysicsLogVector* aVector = new G4PhysicsLogVector(
LowestKineticEnergy,HighestKineticEnergy,TotBin);
GammaCutInKineticEnergyNow = GammaCutInKineticEnergy[J] ;
const G4Material* material = (*theMaterialTable)[J] ;
const G4ElementVector* theElementVector =
material->GetElementVector() ;
const G4double* theAtomicNumDensityVector =
material->GetAtomicNumDensityVector() ;
const G4int NumberOfElements =
material->GetNumberOfElements() ;
for (G4int i=0; i<TotBin; i++)
{
KineticEnergy = aVector->GetLowEdgeEnergy(i) ;
TotalEnergy = KineticEnergy+ParticleMass ;
Cut = GammaCutInKineticEnergyNow ;
if(Cut>KineticEnergy) Cut = KineticEnergy ;
bremloss = 0.;
for (G4int iel=0; iel<NumberOfElements; iel++)
{
Z=(*theElementVector)(iel)->GetZ();
natom = theAtomicNumDensityVector[iel] ;
loss = ComputeBremLoss((&aParticleType),Z,
(*theElementVector)(iel)->GetA(),
KineticEnergy,Cut) ;
bremloss += natom*loss ;
}
if(bremloss<0.) bremloss = 0. ;
aVector->PutValue(i,bremloss);
}
theLossTable->insert(aVector);
}
}
G4double G4MuBremsstrahlung::ComputeBremLoss(
const G4ParticleDefinition* aParticleType,
G4double AtomicNumber,G4double AtomicMass,
G4double KineticEnergy,G4double GammaEnergyCut)
{
G4double TotalEnergy,vcut,vmax,aaa,bbb,hhh,aa,x,ep ;
G4int kkk ;
G4double ak1=0.05 ;
G4int k2=5 ;
G4double xgi[]={0.03377,0.16940,0.38069,0.61931,0.83060,0.96623};
G4double wgi[]={0.08566,0.18038,0.23396,0.23396,0.18038,0.08566};
G4double loss = 0. ;
TotalEnergy=KineticEnergy+ParticleMass ;
vcut = GammaEnergyCut/TotalEnergy ;
vmax = KineticEnergy/TotalEnergy ;
aaa=0.;
bbb=vcut ;
if(vcut>vmax) bbb=vmax ;
kkk=int((bbb-aaa)/ak1)+k2 ;
hhh=(bbb-aaa)/float(kkk) ;
for(G4int l=0; l<kkk; l++)
{
aa=aaa+hhh*float(l) ;
for(G4int i=0; i<6; i++)
{
x=aa+xgi[i]*hhh ;
ep=x*TotalEnergy ;
loss += ep*wgi[i]*ComputeDMicroscopicCrossSection(
aParticleType,KineticEnergy,
AtomicNumber,AtomicMass,ep) ;
}
}
return loss ;
}
void G4MuBremsstrahlung::BuildLambdaTable(
const G4ParticleDefinition& ParticleType)
{
G4double LowEdgeEnergy , Value;
G4double FixedEnergy = (LowestKineticEnergy + HighestKineticEnergy)/2. ;
const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable() ;
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable;
}
theMeanFreePathTable = new G4PhysicsTable(G4Material::GetNumberOfMaterials());
G4PhysicsLogVector* ptrVector;
for ( G4int J=0 ; J < G4Material::GetNumberOfMaterials(); J++ )
{
ptrVector=new G4PhysicsLogVector(LowestKineticEnergy, HighestKineticEnergy,
TotBin ) ;
const G4Material* material= (*theMaterialTable)[J];
for ( G4int i = 0 ; i < TotBin ; i++ )
{
LowEdgeEnergy = ptrVector->GetLowEdgeEnergy( i ) ;
Value = ComputeMeanFreePath( &ParticleType, LowEdgeEnergy,
material );
ptrVector->PutValue( i , Value ) ;
}
theMeanFreePathTable->insertAt( J , ptrVector );
// Compute the PartialSumSigma table at a given fixed energy
ComputePartialSumSigma( &ParticleType, FixedEnergy, material) ;
}
}
void G4MuBremsstrahlung::ComputePartialSumSigma(
const G4ParticleDefinition* ParticleType,
G4double KineticEnergy,
const G4Material* aMaterial)
// Build the table of cross section per element.The table is built for MATERIALS.
// This table is used by DoIt to select randomly an element in the material.
{
G4int Imate = aMaterial->GetIndex();
G4int NbOfElements = aMaterial->GetNumberOfElements();
const G4ElementVector* theElementVector = aMaterial->GetElementVector();
const G4double* theAtomNumDensityVector =
aMaterial->GetAtomicNumDensityVector();
G4double GammaEnergyCut = (G4Gamma::GetCutsInEnergy())[Imate];
PartialSumSigma(Imate) = new G4ValVector(NbOfElements);
G4double SIGMA = 0. ;
for ( G4int Ielem=0 ; Ielem < NbOfElements ; Ielem++ )
{
SIGMA += theAtomNumDensityVector[Ielem] *
ComputeMicroscopicCrossSection( ParticleType, KineticEnergy,
(*theElementVector)(Ielem)->GetZ(),
(*theElementVector)(Ielem)->GetA(),
GammaEnergyCut );
PartialSumSigma(Imate)->insertAt(Ielem, SIGMA);
}
}
G4double G4MuBremsstrahlung::ComputeMicroscopicCrossSection(
const G4ParticleDefinition* ParticleType,
G4double KineticEnergy,
G4double AtomicNumber,
G4double AtomicMass,
G4double GammaEnergyCut)
// Cross section is calculated according to a formula of R.Kokoulin.
{
G4double TotalEnergy,vcut,vmax,aaa,bbb,hhh,aa,x,ep ;
G4int kkk ;
G4double ak1=2.3 ;
G4int k2=4 ;
G4double xgi[]={0.03377,0.16940,0.38069,0.61931,0.83060,0.96623};
G4double wgi[]={0.08566,0.18038,0.23396,0.23396,0.18038,0.08566};
G4double CrossSection = 0. ;
TotalEnergy=KineticEnergy+ParticleMass ;
vcut = GammaEnergyCut/TotalEnergy ;
vmax = KineticEnergy/TotalEnergy ;
if(vmax <= vcut) return CrossSection;
// numerical integration
aaa=log(vcut) ;
bbb=log(vmax);
kkk=int((bbb-aaa)/ak1)+k2 ;
hhh=(bbb-aaa)/float(kkk) ;
for(G4int l=0; l<kkk; l++)
{
aa=aaa+hhh*float(l) ;
for(G4int i=0; i<6; i++)
{
x=aa+xgi[i]*hhh ;
ep=exp(x)*TotalEnergy ;
CrossSection += ep*wgi[i]*ComputeDMicroscopicCrossSection(
ParticleType,KineticEnergy,
AtomicNumber,AtomicMass,ep) ;
}
}
return CrossSection;
}
G4double G4MuBremsstrahlung::ComputeDMicroscopicCrossSection(
const G4ParticleDefinition* ParticleType,
G4double KineticEnergy,
G4double AtomicNumber,
G4double AtomicMass,
G4double GammaEnergy)
// differential cross section
{
static const G4double sqrte=sqrt(exp(1.)) ;
static const G4double bh=202.4,bh1=446.,btf=183.,btf1=1429. ;
static const G4double rmass=ParticleMass/electron_mass_c2 ;
static const G4double cc=classic_electr_radius/rmass ;
static const G4double coeff= 16.*fine_structure_const*cc*cc/3. ;
G4double dxsection = 0.;
if( GammaEnergy > KineticEnergy) return dxsection ;
G4double A = AtomicMass/(g/mole) ; // !!!!!!!!!!!!!!!!!!!
G4double E=KineticEnergy+ParticleMass ;
G4double v=GammaEnergy/E ;
G4double delta=0.5*ParticleMass*ParticleMass*v/(E-GammaEnergy) ;
G4double rab0=delta*sqrte ;
G4double z13=exp(-log(AtomicNumber)/3.) ;
G4double dn=1.54*exp(0.27*log(A)) ;
G4double b,b1,dnstar ;
if(AtomicNumber<1.5)
{
b=bh;
b1=bh1;
dnstar=dn ;
}
else
{
b=btf;
b1=btf1;
dnstar = exp((1.-1./AtomicNumber)*log(dn)) ;
}
// nucleus contribution logarithm
G4double rab1=b*z13;
G4double fn=log(rab1/(dnstar*(electron_mass_c2+rab0*rab1))*
(ParticleMass+delta*(dnstar*sqrte-2.))) ;
if(fn <0.) fn = 0. ;
// electron contribution logarithm
G4double epmax1=E/(1.+0.5*ParticleMass*rmass/E) ;
G4double fe=0.;
if(GammaEnergy<epmax1)
{
G4double rab2=b1*z13*z13 ;
fe=log(rab2*ParticleMass/((1.+delta*rmass/(electron_mass_c2*sqrte))*
(electron_mass_c2+rab0*rab2))) ;
if(fe<0.) fe=0. ;
}
dxsection = coeff*(1.-v*(1.-0.75*v))*AtomicNumber*(fn*AtomicNumber+fe)/
GammaEnergy ;
return dxsection ;
}
void G4MuBremsstrahlung::MakeSamplingTables(
const G4ParticleDefinition* ParticleType)
{
G4double CutFixed = 1.*keV ;
G4double epbin[1000],xbin[1000],prbin[1000] ;
G4int nbin;
G4double AtomicNumber,AtomicWeight,KineticEnergy,
TotalEnergy,Maxep ;
ParticleMass = ParticleType->GetPDGMass() ;
for (G4int iz=0; iz<nzdat; iz++)
{
AtomicNumber = zdat[iz];
AtomicWeight = adat[iz]*g/mole ;
for (G4int it=0; it<ntdat; it++)
{
KineticEnergy = tdat[it];
TotalEnergy = KineticEnergy + ParticleMass;
Maxep = KineticEnergy ;
G4double CrossSection = 0.0 ;
G4double c,y,ymin,ymax,dy,yy,dx,x,ep ;
G4int NbofIntervals ;
// calculate the differential cross section
// numerical integration in
// log ...............
c = log(Maxep/CutFixed) ;
ymin = -5. ;
ymax = 0. ;
dy = (ymax-ymin)/NBIN ;
nbin=-1;
y = ymin - 0.5*dy ;
yy = ymin - dy ;
for (G4int i=0 ; i<NBIN; i++)
{
y += dy ;
x = exp(y) ;
yy += dy ;
dx = exp(yy+dy)-exp(yy) ;
ep = CutFixed*exp(c*x) ;
CrossSection += ep*dx*ComputeDMicroscopicCrossSection(ParticleType,
KineticEnergy,AtomicNumber,
AtomicWeight,ep) ;
if(nbin<NBIN)
{
nbin += 1 ;
epbin[nbin]=ep;
xbin[nbin]=x;
prbin[nbin]=CrossSection ;
ya[nbin]=y ;
proba[iz][it][nbin] = CrossSection ;
}
}
if(CrossSection > 0.)
{
for(G4int ib=0; ib<=nbin; ib++)
{
prbin[ib] /= CrossSection ;
proba[iz][it][ib] /= CrossSection ;
}
}
}
}
}
G4VParticleChange* G4MuBremsstrahlung::PostStepDoIt(const G4Track& trackData,
const G4Step& stepData)
{
aParticleChange.Initialize(trackData);
G4Material* aMaterial=trackData.GetMaterial() ;
const G4DynamicParticle* aDynamicParticle=trackData.GetDynamicParticle();
G4double KineticEnergy = aDynamicParticle->GetKineticEnergy();
G4ParticleMomentum ParticleDirection =
aDynamicParticle->GetMomentumDirection();
// Gamma cut in this material
G4double GammaEnergyCut =
(G4Gamma::GetCutsInEnergy())[aMaterial->GetIndex()];
// check against insufficient energy
if (KineticEnergy < GammaEnergyCut)
{
aParticleChange.SetMomentumChange( ParticleDirection );
aParticleChange.SetEnergyChange( KineticEnergy );
aParticleChange.SetLocalEnergyDeposit (0.);
aParticleChange.SetNumberOfSecondaries(0);
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
// select randomly one element constituing the material
G4Element* anElement = SelectRandomAtom(aMaterial);
G4double TotalEnergy=KineticEnergy+aDynamicParticle->
GetDefinition()->GetPDGMass() ;
// sampling using tables
G4double v,xc,x,yc,y ;
G4int iZ,iT,iy ;
// select sampling table ;
G4double lnZ = log(anElement->GetZ()) ;
G4double delmin = 1.e10 ;
G4double del ;
G4int izz,itt,NBINminus1 ;
NBINminus1 = NBIN-1 ;
for (G4int iz=0; iz<nzdat; iz++)
{
del = abs(lnZ-log(zdat[iz])) ;
if(del<delmin)
{
delmin=del ;
izz=iz ;
}
}
delmin = 1.e10 ;
for (G4int it=0; it<ntdat; it++)
{
del = abs(log(KineticEnergy)-log(tdat[it])) ;
if(del<delmin)
{
del=delmin;
itt=it ;
}
}
//sample energy transfer according to the sampling table
G4double r = G4UniformRand() ;
iy = -1 ;
do {
iy += 1 ;
} while (((proba[izz][itt][iy]) < r)&&(iy < NBINminus1)) ;
//sampling is Done uniformly in y in the bin
if( iy < NBINminus1 )
y = ya[iy] + G4UniformRand() * ( ya[iy+1] - ya[iy] ) ;
else
y = ya[iy] ;
x = exp(y) ;
v = GammaEnergyCut*exp(x*log(KineticEnergy/GammaEnergyCut)) ;
if( v <= 0.)
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
// create G4DynamicParticle object for the Gamma
G4double GammaEnergy = v;
// angles of the emitted gamma. ( Z - axis along the parent particle)
// Teta = electron_mass_c2/TotalEnergy for the moment .....
G4double Teta = electron_mass_c2/TotalEnergy ;
G4double Phi = twopi * G4UniformRand() ;
G4double dirx = sin(Teta)*cos(Phi) , diry = sin(Teta)*sin(Phi) ,
dirz = cos(Teta) ;
G4ThreeVector GammaDirection ( dirx, diry, dirz);
GammaDirection.rotateUz(ParticleDirection);
G4DynamicParticle* aGamma= new G4DynamicParticle (G4Gamma::Gamma(),
GammaDirection, GammaEnergy);
aParticleChange.SetNumberOfSecondaries(1);
aParticleChange.AddSecondary(aGamma);
// Update the incident particle
G4double NewKinEnergy = KineticEnergy - GammaEnergy;
if (NewKinEnergy > 0.)
{
aParticleChange.SetMomentumChange(ParticleDirection);
aParticleChange.SetEnergyChange(NewKinEnergy);
aParticleChange.SetLocalEnergyDeposit (0.);
}
else
{
aParticleChange.SetEnergyChange(0.);
aParticleChange.SetLocalEnergyDeposit (0.);
aParticleChange.SetStatusChange(fStopButAlive);
}
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
G4Element* G4MuBremsstrahlung::SelectRandomAtom(G4Material* aMaterial) const
{
// select randomly 1 element within the material
const G4int Index = aMaterial->GetIndex();
const G4int NumberOfElements = aMaterial->GetNumberOfElements();
const G4ElementVector* theElementVector = aMaterial->GetElementVector();
G4double rval = G4UniformRand()*((*PartialSumSigma(Index))(NumberOfElements-1));
for ( G4int i=0; i < NumberOfElements; i++ )
if (rval <= (*PartialSumSigma(Index))(i)) return ((*theElementVector)(i));
G4cout << " WARNING !!! - The Material '"<< aMaterial->GetName()
<< "' has no elements, NULL pointer returned." << endl;
return NULL;
}
void G4MuBremsstrahlung::PrintInfoDefinition()
{
G4String comments = "cross sections from R. Kokoulin \n ";
comments += " Good description up to 1000 TeV.";
G4cout << endl << GetProcessName() << ": " << comments
<< "\n PhysicsTables from " << G4BestUnit(LowestKineticEnergy,
"Energy")
<< " to " << G4BestUnit(HighestKineticEnergy,"Energy")
<< " in " << TotBin << " bins. \n";
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,507 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4MuIonisation.cc,v 2.6 1998/11/13 13:38:35 urban Exp $
// GEANT4 tag $Name: geant4-00 $
//
//
// --------------------------------------------------------------
// GEANT 4 class implementation file
//
// For information related to this code contact:
// CERN, CN Division, ASD group
// History: first implementation, based on object model of
// 2nd December 1995, G.Cosmo
// ------------ G4MuIonisation physics process -------------
// by Laszlo Urban, September 1997
// ------------------------------------------------------------------
// It is the implementation of the NEW IONISATION PROCESS.
// It calculates the ionisation of muons.
// **************************************************************
// 08-04-98: remove 'tracking cut' of the ionizing particle, MMa
// 26/10/98: new stuff from R.Kokoulin + cleanup , L.Urban
// --------------------------------------------------------------
#include "G4MuIonisation.hh"
#include "G4UnitsTable.hh"
// constructor and destructor
G4MuIonisation::G4MuIonisation(const G4String& processName)
: G4MuEnergyLoss(processName),
LowestKineticEnergy(1.00*keV),
HighestKineticEnergy(1000000.*TeV),
theMeanFreePathTable(NULL),
lastCutInRange(0.),
TotBin(100),
theElectron ( G4Electron::Electron() ),
theMuonPlus ( G4MuonPlus::MuonPlus() ),
theMuonMinus ( G4MuonMinus::MuonMinus() )
{ }
G4MuIonisation::~G4MuIonisation()
{
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable;
}
}
void G4MuIonisation::SetPhysicsTableBining(G4double lowE, G4double highE,
G4int nBins)
{
LowestKineticEnergy = lowE; HighestKineticEnergy = highE;
TotBin = nBins;
}
void G4MuIonisation::BuildPhysicsTable(const G4ParticleDefinition& aParticleType)
// just call BuildLossTable+BuildLambdaTable
{
G4double Charge = aParticleType.GetPDGCharge();
CutInRange = aParticleType.GetLengthCuts();
BuildLossTable(aParticleType) ;
if(Charge>0.)
{
RecorderOfmuplusProcess[CounterOfmuplusProcess] = (*this).theLossTable ;
CounterOfmuplusProcess++;
}
else
{
RecorderOfmuminusProcess[CounterOfmuminusProcess] = (*this).theLossTable ;
CounterOfmuminusProcess++;
}
if(CutInRange != lastCutInRange)
{
lastCutInRange = CutInRange ;
BuildLambdaTable(aParticleType) ;
}
G4MuEnergyLoss::BuildDEDXTable(aParticleType) ;
if(&aParticleType == theMuonPlus)
PrintInfoDefinition() ;
}
void G4MuIonisation::BuildLossTable(const G4ParticleDefinition& aParticleType)
{
G4double Charge = aParticleType.GetPDGCharge() ;
if(Charge>0.)
ParticleCutInKineticEnergy = theMuonPlus->GetCutsInEnergy() ;
else
ParticleCutInKineticEnergy = theMuonMinus->GetCutsInEnergy() ;
DeltaCutInKineticEnergy = theElectron->GetCutsInEnergy() ;
G4double LowEdgeEnergy , ionloss ;
G4double RateMass ;
G4bool isOutRange ;
static const G4MaterialTable* theMaterialTable=
G4Material::GetMaterialTable();
const G4double twoln10 = 2.*log(10.) ;
const G4double Factor = twopi_mc2_rcl2 ;
const G4double bg2lim = 0.0169 , taulim = 8.4146e-3 ;
ParticleMass = aParticleType.GetPDGMass() ;
RateMass = electron_mass_c2/ParticleMass ;
G4int numOfMaterials = theMaterialTable->length();
if ( theLossTable) {
theLossTable->clearAndDestroy();
delete theLossTable;
}
theLossTable = new G4PhysicsTable(numOfMaterials);
for (G4int J=0; J<numOfMaterials; J++)
{
G4PhysicsLogVector* aVector = new G4PhysicsLogVector(
LowestKineticEnergy, HighestKineticEnergy, TotBin);
G4double ElectronDensity,Eexc,Eexc2,Cden,Mden,Aden,X0den,X1den,taul ;
G4double* ShellCorrectionVector;
const G4Material* material= (*theMaterialTable)[J];
ElectronDensity = material->GetElectronDensity();
Eexc = material->GetIonisation()->GetMeanExcitationEnergy();
Eexc2 = Eexc*Eexc ;
Cden = material->GetIonisation()->GetCdensity();
Mden = material->GetIonisation()->GetMdensity();
Aden = material->GetIonisation()->GetAdensity();
X0den = material->GetIonisation()->GetX0density();
X1den = material->GetIonisation()->GetX1density();
taul = material->GetIonisation()->GetTaul() ;
ShellCorrectionVector = material->GetIonisation()
->GetShellCorrectionVector();
const G4ElementVector* theElementVector=
material->GetElementVector() ;
const G4double* theAtomicNumDensityVector=
material->GetAtomicNumDensityVector() ;
const G4int NumberOfElements=
material->GetNumberOfElements() ;
DeltaCutInKineticEnergyNow = DeltaCutInKineticEnergy[J] ;
G4double tau,tau0,Tmax,gamma,bg2,beta2,rcut,delta,x,sh ;
for (G4int i = 0 ; i < TotBin ; i++)
{
LowEdgeEnergy = aVector->GetLowEdgeEnergy(i) ;
tau = LowEdgeEnergy/ParticleMass ;
if ( tau < taul )
// low energy part , parametrized energy loss formulae
{
ionloss = 0. ;
for (G4int iel=0; iel<NumberOfElements; iel++)
{
const G4Element* element = (*theElementVector)(iel);
if ( tau < element->GetIonisation()->GetTau0())
ionloss += theAtomicNumDensityVector[iel]
*( element->GetIonisation()->GetAlow()*sqrt(tau)
+element->GetIonisation()->GetBlow()*tau) ;
else
ionloss += theAtomicNumDensityVector[iel]
* element->GetIonisation()->GetClow()/sqrt(tau) ;
}
}
else
// high energy part , Bethe-Bloch formula
{
gamma = tau +1. ;
bg2 = tau*(tau+2.) ;
beta2 = bg2/(gamma*gamma) ;
Tmax = 2.*electron_mass_c2*bg2
/(1.+2.*gamma*RateMass+RateMass*RateMass) ;
if ( DeltaCutInKineticEnergyNow < Tmax)
rcut = DeltaCutInKineticEnergyNow/Tmax ;
else
rcut = 1.;
ionloss = log(2.*electron_mass_c2*bg2*Tmax/Eexc2)
+log(rcut)-(1.+rcut)*beta2 ;
// density correction
x = log(bg2)/twoln10 ;
if ( x < X0den )
delta = 0. ;
else
{
delta = twoln10*x - Cden ;
if ( x < X1den )
delta += Aden*pow((X1den-x),Mden) ;
}
// shell correction
if ( bg2 > bg2lim ) {
sh = 0. ;
x = 1. ;
for (G4int k=0; k<=2; k++) {
x *= bg2 ;
sh += ShellCorrectionVector[k]/x;
}
}
else {
sh = 0. ;
x = 1. ;
for (G4int k=0; k<=2; k++) {
x *= bg2lim ;
sh += ShellCorrectionVector[k]/x;
}
sh *= log(tau/taul)/log(taulim/taul) ;
}
ionloss -= delta + sh ;
ionloss /= beta2 ;
// correction of R. Kokoulin
G4double E = LowEdgeEnergy+ParticleMass ;
G4double epmax = RateMass*E*E/(RateMass*E+ParticleMass) ;
G4double apar = log(2.*epmax/electron_mass_c2) ;
ionloss += fine_structure_const*(log(2.*E/ParticleMass)-apar/3.)*
apar*apar/twopi ;
ionloss *= Factor*ElectronDensity ;
}
if ( ionloss <= 0.)
ionloss = 0. ;
aVector->PutValue(i,ionloss) ;
}
theLossTable->insert(aVector);
}
}
void G4MuIonisation::BuildLambdaTable(const G4ParticleDefinition& aParticleType)
{
// Build mean free path tables for the delta ray production process
G4double LowEdgeEnergy , Value ,sigma ;
G4bool isOutRange ;
const G4MaterialTable* theMaterialTable=G4Material::GetMaterialTable();
G4int numOfMaterials = theMaterialTable->length();
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable;
}
theMeanFreePathTable = new G4PhysicsTable(numOfMaterials);
// get electron and particle cuts in kinetic energy
DeltaCutInKineticEnergy = theElectron->GetCutsInEnergy() ;
ParticleCutInKineticEnergy = aParticleType.GetEnergyCuts() ;
for (G4int J=0 ; J < numOfMaterials; J++)
{
G4PhysicsLogVector* aVector = new G4PhysicsLogVector(
LowestKineticEnergy, HighestKineticEnergy, TotBin);
const G4Material* material= (*theMaterialTable)[J];
const G4ElementVector* theElementVector=
material->GetElementVector() ;
const G4double* theAtomicNumDensityVector =
material->GetAtomicNumDensityVector();
const G4int NumberOfElements=
material->GetNumberOfElements() ;
DeltaCutInKineticEnergyNow = DeltaCutInKineticEnergy[J] ;
for ( G4int i = 0 ; i < TotBin ; i++ )
{
LowEdgeEnergy = aVector->GetLowEdgeEnergy(i) ;
sigma = 0. ;
for (G4int iel=0; iel<NumberOfElements; iel++ )
{
sigma += theAtomicNumDensityVector[iel]*
ComputeMicroscopicCrossSection(aParticleType,
LowEdgeEnergy,
(*theElementVector)(iel)->GetZ() ) ;
}
Value = sigma<=0 ? DBL_MAX : 1./sigma ;
aVector->PutValue(i, Value) ;
}
theMeanFreePathTable->insert(aVector);
}
}
G4double G4MuIonisation::ComputeMicroscopicCrossSection(
const G4ParticleDefinition& aParticleType,
G4double KineticEnergy,
G4double AtomicNumber)
{
const G4double xgi[] = {0.06943,0.33001,0.66999,0.93057} ;
const G4double wgi[] = {0.17393,0.32607,0.32607,0.17393} ;
const G4double ak1 = 4.6 ;
const G4int k2 = 2 ;
const G4double masspar = 0.5*ParticleMass*ParticleMass/electron_mass_c2 ;
G4double TotalEnergy=KineticEnergy + ParticleMass;
G4double KnockonMaxEnergy = TotalEnergy/(1.+masspar/TotalEnergy) ;
G4double TotalCrossSection= 0. ;
if( KnockonMaxEnergy > DeltaCutInKineticEnergyNow )
{
G4double aaa = log(DeltaCutInKineticEnergyNow);
G4double bbb = log(KnockonMaxEnergy) ;
G4int kkk = int((bbb-aaa)/ak1)+k2 ;
G4double hhh = (bbb-aaa)/kkk ;
G4double step = exp(hhh) ;
G4double ymax = 1./KnockonMaxEnergy ;
for (G4int k=0; k<kkk; k++)
{
G4double ymin = ymax ;
ymax = ymin*step ;
G4double hhy = ymax-ymin ;
for (G4int i=0; i<4; i++)
{
G4double y = ymin+hhy*xgi[i];
G4double ep = 1./y ;
TotalCrossSection += ep*ep*wgi[i]*hhy*
ComputeDMicroscopicCrossSection(
aParticleType,KineticEnergy,
AtomicNumber,ep) ;
}
}
}
return TotalCrossSection ;
}
G4double G4MuIonisation::ComputeDMicroscopicCrossSection(
const G4ParticleDefinition& ParticleType,
G4double KineticEnergy, G4double AtomicNumber,
G4double KnockonEnergy)
// Calculates the differential (D) microscopic cross section
// using the cross section formula of R.P. Kokoulin (10/98)
{
const G4double masspar=0.5*ParticleMass*ParticleMass/electron_mass_c2 ;
const G4double alphaprime = fine_structure_const/twopi ;
G4double TotalEnergy = KineticEnergy + ParticleMass ;
G4double KnockonMaxEnergy = TotalEnergy/(1.+masspar/TotalEnergy) ;
G4double DCrossSection = 0. ;
if(KnockonEnergy >= KnockonMaxEnergy) return DCrossSection ;
G4double v = KnockonEnergy/TotalEnergy ;
DCrossSection = twopi_mc2_rcl2*AtomicNumber*
(1.-KnockonEnergy/KnockonMaxEnergy+0.5*v*v)/
(KnockonEnergy*KnockonEnergy) ;
G4double a1 = log(1.+2.*KnockonEnergy/electron_mass_c2) ;
G4double a3 = log(4.*TotalEnergy*(TotalEnergy-KnockonEnergy)/
(ParticleMass*ParticleMass)) ;
DCrossSection *= (1.+alphaprime*a1*(a3-a1)) ;
return DCrossSection ;
}
G4VParticleChange* G4MuIonisation::PostStepDoIt(
const G4Track& trackData,
const G4Step& stepData)
{
const G4DynamicParticle* aParticle ;
const G4double alphaprime = fine_structure_const/twopi ;
G4Material* aMaterial;
G4double KineticEnergy,TotalEnergy,TotalMomentum,
betasquare,MaxKineticEnergyTransfer,
DeltaKineticEnergy,DeltaTotalMomentum,costheta,sintheta,phi,
dirx,diry,dirz,finalKineticEnergy,finalPx,finalPy,finalPz,
x,xc,te2,grej,Psquare,Esquare,summass,rate,grejc,finalMomentum ;
G4double Charge ;
aParticleChange.Initialize(trackData) ;
aMaterial = trackData.GetMaterial() ;
aParticle = trackData.GetDynamicParticle() ;
Charge=aParticle->GetDefinition()->GetPDGCharge();
KineticEnergy=aParticle->GetKineticEnergy();
TotalEnergy=KineticEnergy + ParticleMass ;
Psquare=KineticEnergy*(TotalEnergy+ParticleMass) ;
Esquare=TotalEnergy*TotalEnergy ;
summass = ParticleMass + electron_mass_c2 ;
G4ParticleMomentum ParticleDirection = aParticle->GetMomentumDirection() ;
DeltaCutInKineticEnergyNow = DeltaCutInKineticEnergy[aMaterial->GetIndex()];
// some kinematics......................
betasquare=Psquare/Esquare ;
MaxKineticEnergyTransfer = 2.*electron_mass_c2*Psquare
/(summass*summass+2.*electron_mass_c2*KineticEnergy);
// sampling kinetic energy of the delta ray
if( MaxKineticEnergyTransfer <= DeltaCutInKineticEnergyNow )
{
// pathological case (it should not happen ,
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
else
{
// normal case ......................................
xc=DeltaCutInKineticEnergyNow/MaxKineticEnergyTransfer ;
rate=MaxKineticEnergyTransfer/TotalEnergy ;
te2=0.5*rate*rate ;
// sampling follows ...
G4double a0=log(2.*TotalEnergy/ParticleMass) ;
grejc=(1.-betasquare*xc+te2*xc*xc)*
(1.+ alphaprime*a0*a0) ;
do {
x=xc/(1.-(1.-xc)*G4UniformRand());
G4double twoep = 2.*x*MaxKineticEnergyTransfer ;
grej=(1.-x*(betasquare-x*te2))*
(1.+alphaprime*log(1.+twoep/electron_mass_c2)*
(a0+log((2.*TotalEnergy-twoep)/ParticleMass)-
log(1.+twoep/electron_mass_c2)))
/grejc ;
} while( G4UniformRand()>grej );
}
DeltaKineticEnergy = x * MaxKineticEnergyTransfer ;
if(DeltaKineticEnergy <= 0.)
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
DeltaTotalMomentum = sqrt(DeltaKineticEnergy * (DeltaKineticEnergy +
2. * electron_mass_c2 )) ;
TotalMomentum = sqrt(Psquare) ;
costheta = DeltaKineticEnergy * (TotalEnergy + electron_mass_c2)
/(DeltaTotalMomentum * TotalMomentum) ;
// protection against costheta > 1 or < -1 ---------------
if ( costheta < -1. )
costheta = -1. ;
if ( costheta > +1. )
costheta = +1. ;
// direction of the delta electron ........
phi = twopi * G4UniformRand() ;
sintheta = sqrt((1.+costheta)*(1.-costheta));
dirx = sintheta * cos(phi) ;
diry = sintheta * sin(phi) ;
dirz = costheta ;
G4ThreeVector DeltaDirection(dirx,diry,dirz) ;
DeltaDirection.rotateUz(ParticleDirection) ;
// create G4DynamicParticle object for delta ray
G4DynamicParticle *theDeltaRay = new G4DynamicParticle;
theDeltaRay->SetKineticEnergy( DeltaKineticEnergy );
theDeltaRay->SetMomentumDirection(
DeltaDirection.x(),DeltaDirection.y(),DeltaDirection.z());
theDeltaRay->SetDefinition(G4Electron::Electron());
finalKineticEnergy = KineticEnergy - DeltaKineticEnergy ;
if (finalKineticEnergy > 0. )
{
// changed energy and momentum of the actual particle
finalMomentum=sqrt(finalKineticEnergy*
(finalKineticEnergy+2.*ParticleMass)) ;
finalPx = (TotalMomentum*ParticleDirection.x()
-DeltaTotalMomentum*DeltaDirection.x())/finalMomentum ;
finalPy = (TotalMomentum*ParticleDirection.y()
-DeltaTotalMomentum*DeltaDirection.y())/finalMomentum ;
finalPz = (TotalMomentum*ParticleDirection.z()
-DeltaTotalMomentum*DeltaDirection.z())/finalMomentum ;
aParticleChange.SetMomentumChange( finalPx,finalPy,finalPz );
}
else
{
finalKineticEnergy = 0. ;
aParticleChange.SetStatusChange(fStopButAlive);
}
aParticleChange.SetEnergyChange( finalKineticEnergy );
aParticleChange.SetNumberOfSecondaries(1);
aParticleChange.AddSecondary( theDeltaRay );
aParticleChange.SetLocalEnergyDeposit (0.);
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
void G4MuIonisation::PrintInfoDefinition()
{
G4String comments = "knock-on electron cross sections .\n ";
comments += " Good description above the mean excitation energy.\n";
comments += " delta ray energy sampled from differential Xsection." ;
G4cout << endl << GetProcessName() << ": " << comments
<< "\n PhysicsTables from " << G4BestUnit(LowestKineticEnergy,
"Energy")
<< " to " << G4BestUnit(HighestKineticEnergy,"Energy")
<< " in " << TotBin << " bins. \n";
}
@@ -0,0 +1,814 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4MuPairProduction.cc,v 2.10 1998/12/02 16:33:18 urban Exp $
// GEANT4 tag $Name: geant4-00 $
//
// $Id:
// --------------------------------------------------------------
// GEANT 4 class implementation file
//
// For information related to this code contact:
// CERN, CN Division, ASD group
// History: first implementation, based on object model of
// 2nd December 1995, G.Cosmo
// -------- G4MuPairProduction physics process ---------
// by Laszlo Urban, May 1998
// **************************************************************
// 04-06-98, in DoIt,secondary production condition:range>min(threshold,safety)
// 26/10/98, new stuff from R. Kokoulin + cleanup , L.Urban
// --------------------------------------------------------------
#include "G4MuPairProduction.hh"
#include "G4EnergyLossTables.hh"
#include "G4UnitsTable.hh"
// static members ........
G4int G4MuPairProduction::nzdat = 5 ;
G4double G4MuPairProduction::zdat[]={1.,4.,13.,26.,92.};
G4int G4MuPairProduction::ntdat = 8 ;
G4double G4MuPairProduction::tdat[]={1.e3,1.e4,1.e5,1.e6,1.e7,1.e8,1.e9,1.e10};
G4int G4MuPairProduction::NBIN = 100 ; //500 ;
G4double G4MuPairProduction::ya[1000]={0.};
G4double G4MuPairProduction::proba[5][8][1000]={0.};
G4MuPairProduction::G4MuPairProduction(const G4String& processName)
: G4MuEnergyLoss(processName),
theMeanFreePathTable(NULL),
LowestKineticEnergy (1.*GeV),
HighestKineticEnergy (1000000.*TeV),
TotBin(50),
theElectron (G4Electron::Electron() ),
thePositron (G4Positron::Positron() ),
theMuonMinus ( G4MuonMinus::MuonMinus() ),
theMuonPlus ( G4MuonPlus::MuonPlus() )
{ }
G4MuPairProduction::~G4MuPairProduction()
{
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable;
}
if (&PartialSumSigma) {
PartialSumSigma.clearAndDestroy();
}
}
void G4MuPairProduction::SetPhysicsTableBining(G4double lowE,G4double highE,
G4int nBins)
{
LowestKineticEnergy=lowE; HighestKineticEnergy=highE; TotBin=nBins;
}
void G4MuPairProduction::BuildPhysicsTable(
const G4ParticleDefinition& aParticleType)
// just call BuildLossTable+BuildLambdaTable
{
BuildLossTable(aParticleType) ;
if(&aParticleType==theMuonMinus)
{
RecorderOfmuminusProcess[CounterOfmuminusProcess] = (*this).theLossTable ;
CounterOfmuminusProcess++;
}
else
{
RecorderOfmuplusProcess[CounterOfmuplusProcess] = (*this).theLossTable ;
CounterOfmuplusProcess++;
}
// sampling table should be made only once !
if(theMeanFreePathTable == NULL)
MakeSamplingTables(&aParticleType) ;
BuildLambdaTable(aParticleType) ;
G4MuEnergyLoss::BuildDEDXTable(aParticleType) ;
if(&aParticleType==theMuonPlus)
PrintInfoDefinition() ;
}
void G4MuPairProduction::BuildLossTable(
const G4ParticleDefinition& aParticleType)
{
G4double KineticEnergy,TotalEnergy,pairloss,Z,
loss,natom,eCut,pCut ;
const G4MaterialTable* theMaterialTable =
G4Material::GetMaterialTable();
ParticleMass = aParticleType.GetPDGMass() ;
ElectronCutInKineticEnergy = (*theElectron).GetEnergyCuts() ;
PositronCutInKineticEnergy = (*thePositron).GetEnergyCuts() ;
G4int numOfMaterials = theMaterialTable->length() ;
if (theLossTable) {
theLossTable->clearAndDestroy();
delete theLossTable;
}
theLossTable = new G4PhysicsTable(numOfMaterials) ;
for (G4int J=0; J<numOfMaterials; J++)
{
G4PhysicsLogVector* aVector = new G4PhysicsLogVector(
LowestKineticEnergy,HighestKineticEnergy,TotBin);
ElectronCutInKineticEnergyNow = ElectronCutInKineticEnergy[J] ;
PositronCutInKineticEnergyNow = PositronCutInKineticEnergy[J] ;
const G4Material* material = (*theMaterialTable)[J] ;
const G4ElementVector* theElementVector =
material->GetElementVector() ;
const G4double* theAtomicNumDensityVector =
material->GetAtomicNumDensityVector() ;
const G4int NumberOfElements =
material->GetNumberOfElements() ;
for (G4int i=0; i<TotBin; i++)
{
KineticEnergy = aVector->GetLowEdgeEnergy(i) ;
TotalEnergy = KineticEnergy+ParticleMass ;
eCut = ElectronCutInKineticEnergyNow ;
pCut = PositronCutInKineticEnergyNow ;
if(eCut>KineticEnergy)
eCut = KineticEnergy ;
if(pCut>KineticEnergy)
pCut = KineticEnergy ;
pairloss = 0.;
for (G4int iel=0; iel<NumberOfElements; iel++)
{
Z=(*theElementVector)(iel)->GetZ();
natom = theAtomicNumDensityVector[iel] ;
loss = ComputePairLoss(&aParticleType,
Z,KineticEnergy,eCut,pCut) ;
pairloss += natom*loss ;
}
if(pairloss<0.)
pairloss = 0. ;
aVector->PutValue(i,pairloss);
}
theLossTable->insert(aVector);
}
}
G4double G4MuPairProduction::ComputePairLoss(
const G4ParticleDefinition* ParticleType,
G4double AtomicNumber,
G4double KineticEnergy,
G4double ElectronEnergyCut,
G4double PositronEnergyCut)
{
static const G4double
xgi[] ={ 0.0199,0.1017,0.2372,0.4083,0.5917,0.7628,0.8983,0.9801 };
static const G4double
wgi[] ={ 0.0506,0.1112,0.1569,0.1813,0.1813,0.1569,0.1112,0.0506 };
static const G4double ak1=6.9 ;
static const G4double ak2=1.0 ;
G4double sqrte = sqrt(exp(1.)) ;
G4double z13 = exp(log(AtomicNumber)/3.) ;
G4double loss = 0.0 ;
if ( AtomicNumber < 1. ) return loss;
G4double CutInPairEnergy = ElectronEnergyCut+PositronEnergyCut
+2.*electron_mass_c2 ;
G4double MinPairEnergy = 4.*electron_mass_c2 ;
if( CutInPairEnergy <= MinPairEnergy ) return loss ;
G4double MaxPairEnergy = KineticEnergy+ParticleMass*(1.-0.75*sqrte*z13) ;
if( CutInPairEnergy >= MaxPairEnergy )
CutInPairEnergy = MaxPairEnergy ;
G4double aaa,bbb,hhh,x,epln,ep ;
G4int kkk ;
// calculate the rectricted loss
// numerical integration in log(PairEnergy)
aaa = log(MinPairEnergy) ;
bbb = log(CutInPairEnergy) ;
kkk = int((bbb-aaa)/ak1+ak2) ;
hhh = (bbb-aaa)/kkk ;
for (G4int l=0 ; l<kkk; l++)
{
x = aaa+hhh*l ;
for (G4int ll=0; ll<8; ll++)
{
epln=x+xgi[ll]*hhh ;
ep = exp(epln) ;
loss += wgi[ll]*ep*ep*ComputeDMicroscopicCrossSection(ParticleType,
KineticEnergy,AtomicNumber,
ep) ;
}
}
loss *= hhh ;
if (loss < 0.) loss = 0.;
return loss ;
}
void G4MuPairProduction::BuildLambdaTable(
const G4ParticleDefinition& ParticleType)
{
G4double LowEdgeEnergy , Value;
G4double FixedEnergy = (LowestKineticEnergy + HighestKineticEnergy)/2. ;
const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable() ;
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable;
}
theMeanFreePathTable = new
G4PhysicsTable( G4Material::GetNumberOfMaterials() ) ;
G4PhysicsLogVector* ptrVector;
for ( G4int J=0 ; J < G4Material::GetNumberOfMaterials(); J++ )
{
ptrVector = new
G4PhysicsLogVector(LowestKineticEnergy, HighestKineticEnergy,
TotBin ) ;
const G4Material* material= (*theMaterialTable)[J];
for ( G4int i = 0 ; i < TotBin ; i++ )
{
LowEdgeEnergy = ptrVector->GetLowEdgeEnergy( i ) ;
Value = ComputeMeanFreePath( &ParticleType, LowEdgeEnergy,
material );
ptrVector->PutValue( i , Value ) ;
}
theMeanFreePathTable->insertAt( J , ptrVector );
// Compute the PartialSumSigma table at a given fixed energy
ComputePartialSumSigma( &ParticleType, FixedEnergy, material) ;
}
}
void G4MuPairProduction::ComputePartialSumSigma(
const G4ParticleDefinition* ParticleType,
G4double KineticEnergy,
const G4Material* aMaterial)
{
G4int Imate = aMaterial->GetIndex();
G4int NbOfElements = aMaterial->GetNumberOfElements();
const G4ElementVector* theElementVector = aMaterial->GetElementVector();
const G4double* theAtomNumDensityVector = aMaterial->
GetAtomicNumDensityVector();
G4double ElectronEnergyCut = (G4Electron::GetCutsInEnergy())[Imate];
G4double PositronEnergyCut = (G4Positron::GetCutsInEnergy())[Imate];
PartialSumSigma(Imate) = new G4ValVector(NbOfElements);
G4double SIGMA = 0. ;
for ( G4int Ielem=0 ; Ielem < NbOfElements ; Ielem++ )
{
SIGMA += theAtomNumDensityVector[Ielem] *
ComputeMicroscopicCrossSection( ParticleType, KineticEnergy,
(*theElementVector)(Ielem)->GetZ(),
ElectronEnergyCut,PositronEnergyCut );
PartialSumSigma(Imate)->insertAt(Ielem, SIGMA);
}
}
G4double G4MuPairProduction::ComputeMicroscopicCrossSection(
const G4ParticleDefinition* ParticleType,
G4double KineticEnergy,
G4double AtomicNumber,
G4double ElectronEnergyCut,
G4double PositronEnergyCut)
{
static const G4double
xgi[] ={ 0.0199,0.1017,0.2372,0.4083,0.5917,0.7628,0.8983,0.9801 };
static const G4double
wgi[] ={ 0.0506,0.1112,0.1569,0.1813,0.1813,0.1569,0.1112,0.0506 };
static const G4double ak1=6.9 ;
static const G4double ak2=1.0 ;
G4double sqrte = sqrt(exp(1.)) ;
G4double z13 = exp(log(AtomicNumber)/3.) ;
G4double CrossSection = 0.0 ;
if ( AtomicNumber < 1. ) return CrossSection;
G4double CutInPairEnergy = ElectronEnergyCut+PositronEnergyCut
+2.*electron_mass_c2 ;
if( CutInPairEnergy < 4.*electron_mass_c2 )
CutInPairEnergy = 4.*electron_mass_c2 ;
G4double MaxPairEnergy = KineticEnergy+ParticleMass*(1.-0.75*sqrte*z13) ;
if( CutInPairEnergy >= MaxPairEnergy ) return CrossSection ;
G4double aaa,bbb,hhh,x,epln,ep ;
G4int kkk ;
// calculate the total cross section
// numerical integration in log(PairEnergy)
aaa = log(CutInPairEnergy) ;
bbb = log(MaxPairEnergy) ;
kkk = int((bbb-aaa)/ak1+ak2) ;
hhh = (bbb-aaa)/kkk ;
for (G4int l=0 ; l<kkk; l++)
{
x = aaa+hhh*l ;
for (G4int ll=0; ll<8; ll++)
{
epln = x+xgi[ll]*hhh;
ep = exp(epln) ;
CrossSection += wgi[ll]*ep*ComputeDMicroscopicCrossSection(ParticleType,
KineticEnergy,AtomicNumber,
ep) ;
}
}
CrossSection *= hhh ;
if (CrossSection < 0.) CrossSection = 0.;
return CrossSection;
}
void G4MuPairProduction::MakeSamplingTables(
const G4ParticleDefinition* ParticleType)
{
G4double epbin[1000],xbin[1000],prbin[1000] ;
G4int nbin;
G4double AtomicNumber,KineticEnergy,MinPairEnergy ;
G4double c,y,ymin,ymax,dy,yy,dx,x,ep ;
MinPairEnergy = 4.*electron_mass_c2 ;
G4double sqrte = sqrt(exp(1.)) ;
for (G4int iz=0; iz<nzdat; iz++)
{
AtomicNumber = zdat[iz];
G4double z13 = exp(log(AtomicNumber)/3.) ;
for (G4int it=0; it<ntdat; it++)
{
KineticEnergy = tdat[it];
G4double MaxPairEnergy = KineticEnergy+ParticleMass*(1.-0.75*sqrte*z13) ;
G4double CrossSection = 0.0 ;
G4int NbofIntervals ;
c = log(MaxPairEnergy/MinPairEnergy) ;
ymin = -5. ;
ymax = 0. ;
dy = (ymax-ymin)/NBIN ;
nbin=-1;
y = ymin - 0.5*dy ;
yy = ymin - dy ;
for (G4int i=0 ; i<NBIN; i++)
{
y += dy ;
x = exp(y) ;
yy += dy ;
dx = exp(yy+dy)-exp(yy) ;
ep = MinPairEnergy*exp(c*x) ;
CrossSection += ep*dx*ComputeDMicroscopicCrossSection(ParticleType,
KineticEnergy,AtomicNumber,ep);
if(nbin<NBIN)
{
nbin += 1 ;
epbin[nbin]=ep;
xbin[nbin]=x;
prbin[nbin]=CrossSection ;
ya[nbin]=y ;
proba[iz][it][nbin] = CrossSection ;
}
}
if(CrossSection > 0.)
{
for(G4int ib=0; ib<=nbin; ib++)
{
prbin[ib] /= CrossSection ;
proba[iz][it][ib] /= CrossSection ;
}
}
}
}
}
G4double G4MuPairProduction::ComputeDDMicroscopicCrossSection(
const G4ParticleDefinition* ParticleType,
G4double KineticEnergy, G4double AtomicNumber,
G4double PairEnergy,G4double asymmetry)
// Calculates the double differential (DD) microscopic cross section
// using the cross section formula of R.P. Kokoulin (18/01/98)
{
G4double sqrte = sqrt(exp(1.)) ;
G4double bbbtf= 183. ;
G4double bbbh = 202.4 ;
G4double g1tf = 1.95e-5 ;
G4double g2tf = 5.3e-5 ;
G4double g1h = 4.4e-5 ;
G4double g2h = 4.8e-5 ;
G4double massratio = ParticleMass/electron_mass_c2 ;
G4double massratio2 = massratio*massratio ;
G4double TotalEnergy = KineticEnergy + ParticleMass ;
G4double z13 = exp(log(AtomicNumber)/3.) ;
G4double z23 = z13*z13 ;
G4double EnergyLoss = TotalEnergy - PairEnergy ;
G4double c3 = 3.*sqrte*ParticleMass/4. ;
G4double DDCrossSection = 0. ;
if(EnergyLoss <= c3*z13)
return DDCrossSection ;
G4double c7 = 4.*electron_mass_c2 ;
G4double c8 = 6.*ParticleMass*ParticleMass ;
G4double alf = c7/PairEnergy ;
G4double a3 = 1. - alf ;
if(a3 <= 0.)
return DDCrossSection ;
// zeta calculation
G4double bbb,g1,g2,zeta1,zeta2,zeta,z2 ;
if( AtomicNumber < 1.5 )
{
bbb = bbbh ;
g1 = g1h ;
g2 = g2h ;
}
else
{
bbb = bbbtf ;
g1 = g1tf ;
g2 = g2tf ;
}
zeta1 = 0.073 * log(TotalEnergy/(ParticleMass+g1*z23*TotalEnergy))-0.26 ;
if( zeta1 > 0.)
{
zeta2 = 0.058*log(TotalEnergy/(ParticleMass+g2*z13*TotalEnergy))-0.14 ;
zeta = zeta1/zeta2 ;
}
else
{
zeta = 0. ;
}
z2 = AtomicNumber*(AtomicNumber+zeta) ;
G4double screen0 = 2.*electron_mass_c2*sqrte*bbb/(z13*PairEnergy) ;
G4double a0 = TotalEnergy*EnergyLoss ;
G4double a1 = PairEnergy*PairEnergy/a0 ;
G4double bet = 0.5*a1 ;
G4double xi0 = 0.25*massratio2*a1 ;
G4double del = c8/a0 ;
G4double romin = 0. ;
G4double romax = (1.-del)*sqrt(1.-c7/PairEnergy) ;
if((asymmetry < romin) || (asymmetry > romax))
return DDCrossSection ;
G4double a4 = 1.-asymmetry ;
G4double a5 = a4*(2.-a4) ;
G4double a6 = 1.-a5 ;
G4double a7 = 1.+a6 ;
G4double a9 = 3.+a6 ;
G4double xi = xi0*a5 ;
G4double xii = 1./xi ;
G4double xi1 = 1.+xi ;
G4double screen = screen0*xi1/a5 ;
G4double yeu = 5.-a6+4.*bet*a7 ;
G4double yed = 2.*(1.+3.*bet)*log(3.+xii)-a6-a1*(2.-a6) ;
G4double yel = 1.+yeu/yed ;
G4double ale=log(bbb/z13*sqrt(xi1*yel)/(1.+screen*yel)) ;
G4double cre = 0.5*log(1.+2.25/(massratio2*z23)*xi1*yel) ;
G4double be ;
if(xi <= 1.e3)
be = ((2.+a6)*(1.+bet)+xi*a9)*log(1.+xii)+(a5-bet)/xi1-a9;
else
be = (3.-a6+a1*a7)/(2.+xi) ;
G4double fe = (ale-cre)*be ;
if( fe < 0.)
fe = 0. ;
G4double ymu = 4.+a6 +3.*bet*a7 ;
G4double ymd = a7*(1.5+a1)*log(3.+xi)+1.-1.5*a6 ;
G4double ym1 = 1.+ymu/ymd ;
G4double alm_crm = log(bbb*massratio/(1.5*z23*(1.+screen*ym1))) ;
G4double a10,bm ;
if( xi >= 1.e-3)
{
a10 = (1.+a1)*a5 ;
bm = (a7*(1.+1.5*bet)-a10*xii)*log(xi1)+xi*(a5-bet)/xi1+a10 ;
}
else
bm = (5.-a6+bet*a9)*(xi/2.) ;
G4double fm = alm_crm*bm ;
if( fm < 0.)
fm = 0. ;
DDCrossSection = (fe+fm/massratio2) ;
DDCrossSection *= 4.*fine_structure_const*fine_structure_const
*classic_electr_radius*classic_electr_radius/(3.*pi) ;
DDCrossSection *= z2*EnergyLoss/(TotalEnergy*PairEnergy) ;
return DDCrossSection ;
}
G4double G4MuPairProduction::ComputeDMicroscopicCrossSection(
const G4ParticleDefinition* ParticleType,
G4double KineticEnergy, G4double AtomicNumber,
G4double PairEnergy)
// Calculates the differential (D) microscopic cross section
// using the cross section formula of R.P. Kokoulin (18/01/98)
{
static const G4double
xgi[] ={ 0.0199,0.1017,0.2372,0.4083,0.5917,0.7628,0.8983,0.9801 };
static const G4double
wgi[] ={ 0.0506,0.1112,0.1569,0.1813,0.1813,0.1569,0.1112,0.0506 };
G4double TotalEnergy = KineticEnergy + ParticleMass ;
G4double EnergyLoss = TotalEnergy - PairEnergy ;
G4double a = 6.*ParticleMass*ParticleMass/(TotalEnergy*EnergyLoss) ;
G4double b = 4.*electron_mass_c2/PairEnergy ;
G4double tmn=log((b+2.*a*(1.-b))/(1.+(1.-a)*sqrt(1.-b))) ;
G4double DCrossSection = 0. ;
G4double ro ;
// Gaussian integration in ln(1-ro) ( with 8 points)
for (G4int i=0; i<7; i++)
{
ro = 1.-exp(tmn*xgi[i]) ;
DCrossSection += (1.-ro)*ComputeDDMicroscopicCrossSection(
ParticleType,KineticEnergy,
AtomicNumber,PairEnergy,ro)
*wgi[i] ;
}
DCrossSection *= -tmn ;
return DCrossSection ;
}
G4VParticleChange* G4MuPairProduction::PostStepDoIt(const G4Track& trackData,
const G4Step& stepData)
{
static const G4double esq = sqrt(exp(1.));
aParticleChange.Initialize(trackData);
G4Material* aMaterial=trackData.GetMaterial() ;
const G4DynamicParticle* aDynamicParticle=trackData.GetDynamicParticle();
G4double KineticEnergy = aDynamicParticle->GetKineticEnergy();
G4ParticleMomentum ParticleDirection =
aDynamicParticle->GetMomentumDirection();
// e-e+ cut in this material
G4double ElectronEnergyCut =
(G4Electron::GetCutsInEnergy())[aMaterial->GetIndex()];
G4double PositronEnergyCut =
(G4Electron::GetCutsInEnergy())[aMaterial->GetIndex()];
G4double CutInPairEnergy = ElectronEnergyCut + PositronEnergyCut ;
G4double MinPairEnergy = 4.*electron_mass_c2 ;
if (CutInPairEnergy < MinPairEnergy) CutInPairEnergy = MinPairEnergy ;
// check against insufficient energy
if (KineticEnergy < CutInPairEnergy )
{
aParticleChange.SetMomentumChange( ParticleDirection );
aParticleChange.SetEnergyChange( KineticEnergy );
aParticleChange.SetLocalEnergyDeposit (0.);
aParticleChange.SetNumberOfSecondaries(0);
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
// select randomly one element constituing the material
G4Element* anElement = SelectRandomAtom(aMaterial);
// limits of the energy sampling
G4double TotalEnergy = KineticEnergy + ParticleMass ;
G4double TotalMomentum = sqrt(KineticEnergy*(TotalEnergy+ParticleMass)) ;
G4double Z3 = anElement->GetIonisation()->GetZ3() ;
G4double MaxPairEnergy = TotalEnergy-0.75*esq*ParticleMass*Z3 ;
if(MinPairEnergy >= MaxPairEnergy)
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
// sample e-e+ energy, pair energy first
G4double PairEnergy,xc,x,yc,y ;
G4int iZ,iT,iy ;
// select sampling table ;
G4double lnZ = log(anElement->GetZ()) ;
G4double delmin = 1.e10 ;
G4double del ;
G4int izz,itt,NBINminus1 ;
NBINminus1 = NBIN-1 ;
for (G4int iz=0; iz<nzdat; iz++)
{
del = abs(lnZ-log(zdat[iz])) ;
if(del<delmin)
{
delmin=del ;
izz=iz ;
}
}
delmin = 1.e10 ;
for (G4int it=0; it<ntdat; it++)
{
del = abs(log(KineticEnergy)-log(tdat[it])) ;
if(del<delmin)
{
del=delmin;
itt=it ;
}
}
xc = log(CutInPairEnergy/MinPairEnergy)/log(MaxPairEnergy/MinPairEnergy) ;
yc = log(xc) ;
iy = -1 ;
do {
iy += 1 ;
} while ((ya[iy] < yc )&&(iy < NBINminus1)) ;
G4double norm = 1./(1.-proba[izz][itt][iy]) ;
G4double r = G4UniformRand() ;
iy = -1 ;
do {
iy += 1 ;
} while (((norm*proba[izz][itt][iy]) < r)&&(iy < NBINminus1)) ;
//sampling is uniformly in y in the bin
if( iy < NBINminus1 )
y = ya[iy] + G4UniformRand() * ( ya[iy+1] - ya[iy]) ;
else
y = ya[iy] ;
x = exp(y) ;
PairEnergy = MinPairEnergy*exp(x*log(MaxPairEnergy/MinPairEnergy)) ;
// sample r=(E+-E-)/PairEnergy ( uniformly .....)
G4double rmax = (1.-6.*ParticleMass*ParticleMass/(TotalEnergy*
(TotalEnergy-PairEnergy)))
*sqrt(1.-MinPairEnergy/PairEnergy) ;
r = rmax * (-1.+2.*G4UniformRand()) ;
// compute energies from PairEnergy,r
G4double ElectronEnergy=(1.-r)*PairEnergy/2. ;
G4double PositronEnergy=(1.+r)*PairEnergy/2. ;
// angles of the emitted particles ( Z - axis along the parent particle)
// (mean theta for the moment)
G4double Teta = electron_mass_c2/TotalEnergy ;
G4double Phi = twopi * G4UniformRand() ;
G4double dirx = sin(Teta)*cos(Phi) , diry = sin(Teta)*sin(Phi) ,
dirz = cos(Teta) ;
G4double LocalEnerDeposit = 0. ;
G4int numberofsecondaries = 1 ;
G4int flagelectron = 0 ;
G4int flagpositron = 1 ;
G4DynamicParticle *aParticle1,*aParticle2 ;
G4double ElectronMomentum , PositronMomentum ;
G4double finalPx,finalPy,finalPz ;
G4double ElectKineEnergy = ElectronEnergy - electron_mass_c2 ;
if((ElectKineEnergy > ElectronEnergyCut) ||
(G4EnergyLossTables::GetRange(
G4Electron::Electron(),ElectKineEnergy,aMaterial) >=
stepData.GetPostStepPoint()->GetSafety()))
{
numberofsecondaries += 1 ;
flagelectron = 1 ;
ElectronMomentum = sqrt(ElectKineEnergy*
(ElectronEnergy+electron_mass_c2));
G4ThreeVector ElectDirection ( dirx, diry, dirz );
ElectDirection.rotateUz(ParticleDirection);
// create G4DynamicParticle object for the particle1
aParticle1= new G4DynamicParticle (G4Electron::Electron(),
ElectDirection, ElectKineEnergy);
}
else
{ LocalEnerDeposit += ElectKineEnergy ; }
// the e+ is always created (even with Ekine=0) for further annihilation.
G4double PositKineEnergy = PositronEnergy - electron_mass_c2 ;
PositronMomentum = sqrt(PositKineEnergy*(PositronEnergy+electron_mass_c2));
if((PositKineEnergy < PositronEnergyCut) &&
(G4EnergyLossTables::GetRange(
G4Positron::Positron(),PositKineEnergy,aMaterial) <=
stepData.GetPostStepPoint()->GetSafety()))
{
LocalEnerDeposit += PositKineEnergy ;
PositKineEnergy = 0. ;
}
G4ThreeVector PositDirection ( -dirx, -diry, dirz );
PositDirection.rotateUz(ParticleDirection);
// create G4DynamicParticle object for the particle2
aParticle2= new G4DynamicParticle (G4Positron::Positron(),
PositDirection, PositKineEnergy);
// fill particle change and update initial particle
aParticleChange.SetNumberOfSecondaries(numberofsecondaries) ;
if(flagelectron==1)
aParticleChange.AddSecondary( aParticle1 ) ;
if(flagpositron==1)
aParticleChange.AddSecondary( aParticle2 ) ;
G4double NewKinEnergy = KineticEnergy - ElectronEnergy - PositronEnergy ;
G4double finalMomentum=sqrt(NewKinEnergy*
(NewKinEnergy+2.*ParticleMass)) ;
aParticleChange.SetMomentumChange( ParticleDirection );
G4double KinEnergyCut = (aDynamicParticle->GetDefinition()->
GetEnergyCuts())[aMaterial->GetIndex()];
if (NewKinEnergy > KinEnergyCut)
{
aParticleChange.SetEnergyChange( NewKinEnergy );
}
else
{
aParticleChange.SetEnergyChange(0.);
LocalEnerDeposit += NewKinEnergy ;
aParticleChange.SetStatusChange(fStopButAlive);
}
aParticleChange.SetLocalEnergyDeposit( LocalEnerDeposit ) ;
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
G4Element* G4MuPairProduction::SelectRandomAtom(G4Material* aMaterial) const
{
// select randomly 1 element within the material
const G4int Index = aMaterial->GetIndex();
const G4int NumberOfElements = aMaterial->GetNumberOfElements();
const G4ElementVector* theElementVector = aMaterial->GetElementVector();
G4double rval = G4UniformRand()*((*PartialSumSigma(Index))
(NumberOfElements-1));
for ( G4int i=0; i < NumberOfElements; i++ )
{
if (rval <= (*PartialSumSigma(Index))(i)) return ((*theElementVector)(i));
}
cout << " WARNING !!! - The Material '"<< aMaterial->GetName()
<< "' has no elements, NULL pointer returned." << endl;
return NULL;
}
void G4MuPairProduction::PrintInfoDefinition()
{
G4String comments = "cross sections from R. Kokoulin \n ";
comments += " Good description up to 1000 TeV.";
G4cout << endl << GetProcessName() << ": " << comments
<< "\n PhysicsTables from " << G4BestUnit(LowestKineticEnergy,
"Energy")
<< " to " << G4BestUnit(HighestKineticEnergy,"Energy")
<< " in " << TotBin << " bins. \n";
}