Files
geant4/source/particles/management/src/G4ParticleWithCuts.cc
T
2016-06-08 16:10:37 +02:00

598 lines
21 KiB
C++

//
// ********************************************************************
// * DISCLAIMER *
// * *
// * The following disclaimer summarizes all the specific disclaimers *
// * of contributors to this software. The specific disclaimers,which *
// * govern, are listed with their locations in: *
// * http://cern.ch/geant4/license *
// * *
// * 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. *
// * *
// * This code implementation is the intellectual property of the *
// * 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: G4ParticleWithCuts.cc,v 1.9.2.1 2001/06/28 19:11:13 gunter Exp $
// GEANT4 tag $Name: $
//
//
// --------------------------------------------------------------
// GEANT 4 class implementation file
//
// Hisaya Kurashige, 21 Oct 1996
// Hisaya Kurashige, 04 Jan 1997
// --------------------------------------------------------------
// New Physics scheme 8 Jan. 1997 H.Kurahige
// The cut in kinetic energy is set to zero for vacuum,
// bug in ConvertCutToKineticEnergy is corrected . L.Urban 04/04/97
// remove sprintf 10 Nov. 1997 H.Kurashige
// remove BuildPhysicTabel() 06 June 1998 H.Kurashige
// bug in CalcEnergyCuts is corrected , 22 June 1998 L.Urban
// modify CalcEnergyCuts 09 Nov. 1998, L.Urban
// added RestoreCuts H.Kurashige 09 Mar. 2001
// ------------------------------------------------------------
#include "globals.hh"
#include "G4ParticleWithCuts.hh"
#include "G4ParticleTable.hh"
#include "G4Material.hh"
#include "G4PhysicsLogVector.hh"
#include "G4ios.hh"
#include "g4std/strstream"
G4double G4ParticleWithCuts::LowestEnergy = 0.99e-3*MeV;
G4double G4ParticleWithCuts::HighestEnergy = 100.0e6*MeV;
G4ParticleWithCuts::G4ParticleWithCuts(
const G4String& aName,
G4double mass,
G4double width,
G4double charge,
G4int iSpin,
G4int iParity,
G4int iConjugation,
G4int iIsospin,
G4int iIsospinZ,
G4int gParity,
const G4String& pType,
G4int lepton,
G4int baryon,
G4int encoding,
G4bool stable,
G4double lifetime,
G4DecayTable *decaytable,
G4bool shortlived)
: G4ParticleDefinition(aName, mass, width, charge, iSpin, iParity,
iConjugation, iIsospin, iIsospinZ, gParity,
pType, lepton, baryon, encoding, stable,
lifetime, decaytable, shortlived),
//-- members initialisation for SetCuts ------------------------------
theCutInMaxInteractionLength(-1.0),
theKineticEnergyCuts(0),
theLossTable(0),
NumberOfElements(0)
{
// -- set ApplyCutsFlag in default ----------
SetApplyCutsFlag(false);
//-- default values for SetCuts ------------------------------
// Lowest/Highest energy is defined in MeV
TotBin = 200;
}
G4ParticleWithCuts::~G4ParticleWithCuts()
{
if (theKineticEnergyCuts) delete [] theKineticEnergyCuts;
if (theLossTable) delete theLossTable;
}
// **********************************************************************
// ************************ RangeLinSimpson *****************************
// **********************************************************************
G4double G4ParticleWithCuts::RangeLinSimpson(
const G4ElementVector* elementVector,
const G4double* atomicNumDensityVector,
const G4LossTable* aLossTable,
G4double aMass,
G4double taulow, G4double tauhigh,
G4int nbin, G4int NumEl)
{
// Simpson numerical integration, linear binning
G4double dtau = (tauhigh-taulow)/nbin;
G4double Value=0.;
for (G4int i=0; i<=nbin; i++)
{
G4double taui=taulow+dtau*i;
G4double ti=aMass*taui;
G4double lossi=0.;
for (G4int j=0; j<NumEl; j++)
{
G4bool isOut;
G4int IndEl = (*elementVector)(j)->GetIndex();
lossi += atomicNumDensityVector[j]*
(*aLossTable)[IndEl]->GetValue(ti,isOut);
}
if ( i==0 )
Value += 0.5/lossi;
else {
if ( i<nbin ) Value += 1./lossi;
else Value += 0.5/lossi;
}
}
Value *= aMass*dtau;
return Value;
}
// **********************************************************************
// ************************ RangeLogSimpson *****************************
// **********************************************************************
G4double G4ParticleWithCuts::RangeLogSimpson(
const G4ElementVector* elementVector,
const G4double* atomicNumDensityVector,
const G4LossTable* aLossTable,
G4double aMass,
G4double ltaulow, G4double ltauhigh,
G4int nbin, G4int NumEl)
{
// Simpson numerical integration, logarithmic binning
G4double ltt = ltauhigh-ltaulow;
G4double dltau = ltt/nbin;
G4double Value = 0.;
for (G4int i=0; i<=nbin; i++)
{
G4double ui = ltaulow+dltau*i;
G4double taui = exp(ui);
G4double ti = aMass*taui;
G4double lossi = 0.;
for (G4int j=0; j<NumEl; j++)
{
G4bool isOut;
G4int IndEl = (*elementVector)(j)->GetIndex();
lossi += atomicNumDensityVector[j]*
(*aLossTable)[IndEl]->GetValue(ti,isOut);
}
if ( i==0 )
Value += 0.5*taui/lossi;
else {
if ( i<nbin ) Value += taui/lossi;
else Value += 0.5*taui/lossi;
}
}
Value *= aMass*dltau;
return Value;
}
// **********************************************************************
// ************************ BuildLossTable ******************************
// **********************************************************************
// create Energy Loss Table for charged particles
// (cross section tabel for neutral )
void G4ParticleWithCuts::BuildLossTable()
{
// Build dE/dx tables for elements
if (NumberOfElements ==0)
{
NumberOfElements = G4Element::GetNumberOfElements();
theLossTable = new G4LossTable();
theLossTable->reserve(G4Element::GetNumberOfElements());
#ifdef G4VERBOSE
if (GetVerboseLevel()>2) {
G4cout << "G4ParticleWithCuts::BuildLossTable() ";
G4cout << "Create theLossTable[" << theLossTable << "]";
G4cout << " NumberOfElements=" << NumberOfElements <<G4endl;
}
#endif
} else {
if (NumberOfElements != G4int(G4Element::GetNumberOfElements())){
char errMsg[1024];
G4std::ostrstream errOs(errMsg,1024);
errOs << "Error in G4ParticlWithCuts::BuildLossTable()";
errOs << "[" << this->GetParticleName() << "] ";
errOs << " : inconsistent G4Element::GetNumberOfElements =" << G4Element::GetNumberOfElements();
errOs << " previous value" << NumberOfElements << '\0';
G4Exception(errMsg);
}
}
// fill the loss table
for (G4int J=0; J<NumberOfElements; J++)
{
G4double Value;
G4LossVector* aVector= new
G4LossVector(LowestEnergy, HighestEnergy, TotBin);
for (G4int i=0; i<TotBin; i++)
{
Value = ComputeLoss(
(*G4Element::GetElementTable())[J]->GetZ(),
aVector->GetLowEdgeEnergy(i)
);
aVector->PutValue(i,Value);
}
theLossTable->insert(aVector);
}
}
// **********************************************************************
// ****************** ConvertCutToKineticEnergy *************************
// **********************************************************************
G4double G4ParticleWithCuts::ConvertCutToKineticEnergy(G4RangeVector* rangeVector) const
{
const G4double epsilon=0.01;
const G4int NBIN=200;
// find max. range and the corresponding energy (rmax,Tmax)
G4double Tmax=HighestEnergy;
G4double rmax=-1.e10*mm;
G4double fac=log(HighestEnergy/LowestEnergy)/NBIN;
fac=exp(fac);
G4double T=LowestEnergy/fac;
G4bool isOut;
for (G4int ibin=0; ibin<NBIN; ibin++)
{
T=fac*T;
G4double r=rangeVector->GetValue(T,isOut);
if ( r>rmax )
{
Tmax=T;
rmax=r;
}
}
G4double T1 = LowestEnergy;
G4double r1 = rangeVector->GetValue(T1,isOut);
if ( theCutInMaxInteractionLength <= r1 )
return T1;
if ( theCutInMaxInteractionLength >= rmax )
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>0) {
G4cout << "Error in G4ParticleWithCuts::ConvertCutToKineticEnergy" <<G4endl;
G4cout << "******** ConvertCutToKineticEnergy for " << GetParticleName();
G4cout << " ********************" << G4endl;
G4cout << "The cut energy is set " << DBL_MAX/GeV << "GeV " <<G4endl;
}
#endif
return DBL_MAX;
} else {
G4double T2 = Tmax ;
G4double T3 = sqrt(T1*T2);
G4double r3 = rangeVector->GetValue(T3,isOut);
while ( abs(1.-r3/theCutInMaxInteractionLength)>epsilon )
{
if ( theCutInMaxInteractionLength <= r3 ) {
T2 = T3;
} else {
T1 = T3;
}
T3 = sqrt(T1*T2);
r3 = rangeVector->GetValue(T3,isOut);
}
return T3;
}
}
// **********************************************************************
// **************************** RestoreCuts *********************************
// **********************************************************************
void G4ParticleWithCuts::RestoreCuts(G4double cutInLength,
const G4double* cutInEnergy )
{
// Set cut in stopping range
theCutInMaxInteractionLength = cutInLength;
const G4MaterialTable* materialTable = G4Material::GetMaterialTable();
// Restore the vector of cuts in energy corresponding to the range cut
if(theKineticEnergyCuts) delete [] theKineticEnergyCuts;
theKineticEnergyCuts = new G4double [materialTable->length()];
for (size_t j=0; j<materialTable->length(); j +=1) {
theKineticEnergyCuts[j] = cutInEnergy[j];
}
}
// **********************************************************************
// **************************** SetCuts *********************************
// **********************************************************************
void G4ParticleWithCuts::CalcEnergyCuts(G4double aCut)
{
char errMsg[1024];
G4std::ostrstream errOs(errMsg,1024);
// check LowestEnergy/ HighestEnergy/TotBin
if (TotBin<1) {
errOs << "Error in G4ParticlWithCuts::G4ParticlWithCuts" ;
errOs << "[" << this->GetParticleName() << "]";
errOs << " : not defined or illegal TotBin [" << TotBin << "]" << '\0';
G4Exception(errMsg);
}
if ( (LowestEnergy<0.0)||(HighestEnergy<=LowestEnergy) ){
errOs << "Error in G4ParticlWithCuts::G4ParticlWithCuts";
errOs << "[" << this->GetParticleName() << "]";
errOs << " : illegal energy range" << "(" << LowestEnergy/GeV;
errOs << "," << HighestEnergy/GeV << ") [GeV]" << '\0';
G4Exception(errMsg);
}
// Set cut in stopping range
theCutInMaxInteractionLength = aCut;
const G4MaterialTable* materialTable = G4Material::GetMaterialTable();
// Create the vector of cuts in energy
// corresponding to the stopping range cut
if(theKineticEnergyCuts) delete [] theKineticEnergyCuts;
theKineticEnergyCuts = new G4double [materialTable->length()];
G4double Charge = this->GetPDGCharge() ;
G4bool useProtonCut =
((GetParticleName() != "gamma" ) &&
(GetParticleName() != "e-" ) &&
(GetParticleName() != "e+" ) &&
(GetParticleName() != "mu-" ) &&
(GetParticleName() != "mu+" ) &&
(GetParticleName() != "proton" ) &&
(GetParticleName() != "anti_proton" ) &&
(Charge != 0.) );
static G4ParticleDefinition* theProton =0;
// check if the proton exists or not
if ((useProtonCut) && (theProton ==0)) {
theProton = G4ParticleTable::GetParticleTable()->FindParticle("proton");
if (theProton ==0) {
#ifdef G4VERBOSE
if (GetVerboseLevel()>0) {
G4cout << " G4ParticleWithCuts::CalcEnergyCuts ";
G4cout << " proton is not defined !!" << G4endl;
}
#endif
useProtonCut = false;
}
}
if (useProtonCut) {
// check if cuts for the proton are defined or not
if (theProton->GetEnergyCuts()==0) {
errOs << " G4ParticleWithCuts::CalcEnergyCuts ";
errOs << " proton energy cut is not defined !!" << '\0';
G4Exception(errMsg);
}
// check if the cut in range is same as one fro the proton
useProtonCut = ( abs(aCut-theProton->GetLengthCuts())<1.*nanometer );
}
if (useProtonCut) {
// use energy cuts for Proton
#ifdef G4VERBOSE
if (GetVerboseLevel()>2) {
G4cout << " G4ParticleWithCuts: [" << GetParticleName() <<"]";
G4cout << " uses Proton Cut " << G4endl;
}
#endif
G4double ChargeSquare = Charge*Charge/(eplus*eplus) ;
G4double massRatio = proton_mass_c2/(this->GetPDGMass()) ;
for (size_t J=0; J<materialTable->length(); J +=1) {
G4double protonEnergyCut = (theProton->GetEnergyCuts())[J] ;
// cut energy is rescaled by using charge and mass ratio
theKineticEnergyCuts[J] = ChargeSquare*protonEnergyCut/massRatio ;
if(theKineticEnergyCuts[J] < LowestEnergy) {
theKineticEnergyCuts[J] = LowestEnergy ;
}
}
} else {
#ifdef G4VERBOSE
if (GetVerboseLevel()>2) {
G4cout << " G4ParticleWithCuts: [" << GetParticleName() <<"]";
G4cout << " calcurate by using its own loss table " << G4endl;
}
#endif
// Build the energy loss table
BuildLossTable();
// Build range vector for every material, convert cut into energy-cut,
// fill theKineticEnergyCuts and delete the range vector
G4double tune = 0.025*mm*g/cm3 ,lowen = 30.*keV ;
G4double density ;
for (size_t J=0; J<materialTable->length(); J +=1){
G4RangeVector* rangeVector = new
G4RangeVector(LowestEnergy, HighestEnergy, TotBin);
G4Material* aMaterial = (*materialTable)[J];
density = aMaterial->GetDensity() ;
if(density == 0.) {
theKineticEnergyCuts[J] = 0. ;
} else {
this->BuildRangeVector(aMaterial, this->theLossTable,
this->HighestEnergy, this->GetPDGMass(),
rangeVector);
theKineticEnergyCuts[J] = ConvertCutToKineticEnergy(rangeVector);
if( ((GetParticleName()=="e-")||(GetParticleName()=="e+"))
&& (theKineticEnergyCuts[J] < lowen) ) {
theKineticEnergyCuts[J] /= (1.+tune/(aCut*density)) ;
}
if(theKineticEnergyCuts[J] < LowestEnergy) {
theKineticEnergyCuts[J] = LowestEnergy ;
}
}
delete rangeVector;
}
// Delete energy loss table
theLossTable->clearAndDestroy();
}
}
// **********************************************************************
// ************************** ComputeLoss *******************************
// **********************************************************************
G4double G4ParticleWithCuts::ComputeLoss(G4double AtomicNumber,
G4double KineticEnergy) const
{
// calculate dE/dx
static G4double Z;
static G4double ionpot, tau0, taum, taul, ca, cba, cc;
G4double z2Particle = GetPDGCharge()/eplus;
z2Particle *= z2Particle;
if (z2Particle < 0.1) return 0.0;
if( abs(AtomicNumber-Z)>0.1 )
{
// recalculate constants
Z = AtomicNumber;
G4double Z13 = exp(log(Z)/3.);
tau0 = 0.1*Z13*MeV/proton_mass_c2;
taum = 0.035*Z13*MeV/proton_mass_c2;
taul = 2.*MeV/proton_mass_c2;
ionpot = 1.6e-5*MeV*exp(0.9*log(Z));
cc = (taul+1.)*(taul+1.)*log(2.*electron_mass_c2*taul*(taul+2.)/ionpot)/(taul*(taul+2.))-1.;
cc = 2.*twopi_mc2_rcl2*Z*cc*sqrt(taul);
ca = cc/((1.-0.5*sqrt(tau0/taum))*tau0);
cba = -0.5/sqrt(taum);
}
G4double tau = KineticEnergy/GetPDGMass();
G4double dEdx;
if ( tau <= tau0 )
dEdx = ca*(sqrt(tau)+cba*tau);
else
{
if( tau <= taul )
dEdx = cc/sqrt(tau);
else
{
dEdx = (tau+1.)*(tau+1.)*
log(2.*electron_mass_c2*tau*(tau+2.)/ionpot)/(tau*(tau+2.))-1.;
dEdx = 2.*twopi_mc2_rcl2*Z*dEdx;
}
}
return dEdx*z2Particle ;
}
// **********************************************************************
// ************************ BuildRangeVector ****************************
// **********************************************************************
void G4ParticleWithCuts::BuildRangeVector(
const G4Material* aMaterial,
const G4LossTable* aLossTable,
G4double maxEnergy,
G4double aMass,
G4RangeVector* rangeVector)
{
// create range vector for a material
const G4double tlim=2.*MeV, t1=0.1*MeV, t2=0.025*MeV;
const G4int maxnbint=100;
const G4ElementVector* elementVector = aMaterial->GetElementVector();
const G4double* atomicNumDensityVector = aMaterial->GetAtomicNumDensityVector();
G4int NumEl = aMaterial->GetNumberOfElements();
if (rangeVector == 0) {
char errMsg[1024];
G4std::ostrstream errOs(errMsg,1024);
errOs << "Error in G4ParticleWithCuts::BuildRangeVector()";
errOs << "[" << this->GetParticleName() << "] ";
errOs << " : 0 pointer is found in absorptionLengthVector" << '\0';
G4Exception(errMsg);
}
// calculate parameters of the low energy part first
G4double loss1=0.;
G4double loss2=0.;
G4int i;
for (i=0; i<NumEl; i++)
{
G4bool isOut;
G4int IndEl = (*elementVector)(i)->GetIndex();
loss1 += atomicNumDensityVector[i]*
(*aLossTable)[IndEl]->GetValue(t1,isOut);
loss2 += atomicNumDensityVector[i]*
(*aLossTable)[IndEl]->GetValue(t2,isOut);
}
G4double tau1 = t1/proton_mass_c2;
G4double sqtau1 = sqrt(tau1);
G4double ca = (4.*loss2-loss1)/sqtau1;
G4double cb = (2.*loss1-4.*loss2)/tau1;
G4double cba = cb/ca;
G4double taulim = tlim/proton_mass_c2;
G4double taumax = maxEnergy/aMass;
G4double ltaumax = log(taumax);
// now we can fill the range vector....
G4double rmax = 0.0;
for (i=0; i<TotBin; i++)
{
G4double LowEdgeEnergy = rangeVector->GetLowEdgeEnergy(i);
G4double tau = LowEdgeEnergy/aMass;
G4double Value;
if ( tau <= tau1 ){
Value =2.*aMass*log(1.+cba*sqrt(tau))/cb;
} else {
Value = 2.*aMass*log(1.+cba*sqtau1)/cb;
if ( tau <= taulim )
{
G4int nbin = (G4int)(maxnbint*(tau-tau1)/(taulim-tau1));
if ( nbin<1 ) nbin = 1;
Value += RangeLinSimpson(elementVector,atomicNumDensityVector,
aLossTable, aMass,
tau1, tau,
nbin, NumEl);
} else {
Value += RangeLinSimpson(elementVector,atomicNumDensityVector,
aLossTable, aMass,
tau1, taulim,
maxnbint, NumEl);
G4double ltaulow = log(taulim);
G4double ltauhigh = log(tau);
G4int nbin = (G4int)(maxnbint*(ltauhigh-ltaulow)/(ltaumax-ltaulow));
if ( nbin<1 ) nbin = 1;
Value += RangeLogSimpson(elementVector,atomicNumDensityVector,
aLossTable, aMass,
ltaulow, ltauhigh,
nbin, NumEl);
}
}
rangeVector->PutValue(i,Value);
if (rmax < Value) rmax = Value;
}
if ( theCutInMaxInteractionLength >= rmax) {
#ifdef G4VERBOSE
if (GetVerboseLevel()>0) {
G4cout << "Error in G4ParticleWithCuts::BuildRangeVector()" << G4endl;
G4cout << " SetCuts for " << GetParticleName() << G4endl;
G4cout << "The maximal meaningful cut is " << rmax/mm << " mm." << G4endl;
G4cout << "All the " << GetParticleName() << "will be killed !" << G4endl;
G4cout << "in the material " << aMaterial->GetName() << "." << G4endl;
}
#endif
}
}