Files
geant4/source/processes/hadronic/stopping/src/G4KaonMinusAbsorptionAtRest.cc
T
2016-06-09 16:46:55 +02:00

543 lines
18 KiB
C++

//
// ********************************************************************
// * 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: Christian V"olcker (Christian.Volcker@cern.ch),
//
// Creation date: November 1997
//
// Testfile: ../G4KaonMinusAbsorptionAtRestTest.cc
//
// Modifications:
// Maria Grazia Pia September 1998
// Various bug fixes, eliminated several memory leaks
//
// -------------------------------------------------------------------
#include "G4KaonMinusAbsorptionAtRest.hh"
#include "G4StopDeexcitation.hh"
#include "G4StopTheoDeexcitation.hh"
#include "G4StopDeexcitationAlgorithm.hh"
#include "G4ReactionKinematics.hh"
#include "G4HadronicProcessStore.hh"
G4KaonMinusAbsorptionAtRest::G4KaonMinusAbsorptionAtRest(const G4String& processName,
G4ProcessType aType ) :
G4VRestProcess (processName, aType)
{
if (verboseLevel>0) {
G4cout << GetProcessName() << " is created "<< G4endl;
}
SetProcessSubType(fHadronAtRest);
// see Cohn et al, PLB27(1968) 527;
// Davis et al, PLB1(1967) 434;
pionAbsorptionRate = 0.07;
// see VanderVelde-Wilquet et al, Nuov.Cim.39A(1978)538;
// see VanderVelde-Wilquet et al, Nuov.Cim.38A(1977)178;
// see VanderVelde-Wilquet et al, Nucl.Phys.A241(1975)511;
// primary production rates ( for absorption on Carbon)
// .. other elements are extrapolated by the halo factor.
rateLambdaZeroPiZero = 0.052;
rateSigmaMinusPiPlus = 0.199;
rateSigmaPlusPiMinus = 0.446;
rateSigmaZeroPiZero = 0.303;
rateLambdaZeroPiMinus = 0.568;
rateSigmaZeroPiMinus = 0.216;
rateSigmaMinusPiZero = 0.216;
// for sigma- p -> lambda n
// sigma+ n -> lambda p
// sigma- n -> lambda
// all values compatible with 0.55 same literature as above.
sigmaPlusLambdaConversionRate = 0.55;
sigmaMinusLambdaConversionRate = 0.55;
sigmaZeroLambdaConversionRate = 0.55;
G4HadronicProcessStore::Instance()->RegisterExtraProcess(this);
}
G4KaonMinusAbsorptionAtRest::~G4KaonMinusAbsorptionAtRest()
{
G4HadronicProcessStore::Instance()->DeRegisterExtraProcess(this);
}
void G4KaonMinusAbsorptionAtRest::PreparePhysicsTable(const G4ParticleDefinition& p)
{
G4HadronicProcessStore::Instance()->RegisterParticleForExtraProcess(this, &p);
}
void G4KaonMinusAbsorptionAtRest::BuildPhysicsTable(const G4ParticleDefinition& p)
{
G4HadronicProcessStore::Instance()->PrintInfo(&p);
}
G4VParticleChange* G4KaonMinusAbsorptionAtRest::AtRestDoIt
(const G4Track& track, const G4Step& )
{
stoppedHadron = track.GetDynamicParticle();
// Check applicability
if (!IsApplicable(*(stoppedHadron->GetDefinition())))
{
G4cerr <<"G4KaonMinusAbsorptionAtRest:ERROR, particle must be a Kaon!" <<G4endl;
return 0;
}
G4Material* material;
material = track.GetMaterial();
nucleus = 0;
do
{
// Select the nucleus, get nucleon
nucleus = new G4Nucleus(material);
if (nucleus->GetA_asInt() < 1.5)
{
delete nucleus;
nucleus = 0;
}
} while(nucleus == 0);
G4double Z = nucleus->GetZ_asInt();
G4double A = nucleus->GetA_asInt();
// Do the interaction with the nucleon
G4DynamicParticleVector* absorptionProducts = KaonNucleonReaction();
// Secondary interactions
G4DynamicParticle* thePion;
unsigned int i;
for(i = 0; i < absorptionProducts->size(); i++)
{
thePion = (*absorptionProducts)[i];
if (thePion->GetDefinition() == G4PionMinus::PionMinus()
|| thePion->GetDefinition() == G4PionPlus::PionPlus()
|| thePion->GetDefinition() == G4PionZero::PionZero())
{
if (AbsorbPionByNucleus(thePion))
{
absorptionProducts->erase(absorptionProducts->begin()+i);
i--;
delete thePion;
if (verboseLevel > 1)
G4cout << "G4KaonMinusAbsorption::AtRestDoIt: Pion absorbed in Nucleus"
<< G4endl;
}
}
}
G4DynamicParticle* theSigma;
G4DynamicParticle* theLambda;
for (i = 0; i < absorptionProducts->size(); i++)
{
theSigma = (*absorptionProducts)[i];
if (theSigma->GetDefinition() == G4SigmaMinus::SigmaMinus()
|| theSigma->GetDefinition() == G4SigmaPlus::SigmaPlus()
|| theSigma->GetDefinition() == G4SigmaZero::SigmaZero())
{
theLambda = SigmaLambdaConversion(theSigma);
if (theLambda != 0){
absorptionProducts->erase(absorptionProducts->begin()+i);
i--;
delete theSigma;
absorptionProducts->push_back(theLambda);
if (verboseLevel > 1)
G4cout << "G4KaonMinusAbsorption::AtRestDoIt: SigmaLambdaConversion Done"
<< G4endl;
}
}
}
// Nucleus deexcitation
G4double productEnergy = 0.;
G4ThreeVector pProducts(0.,0.,0.);
unsigned int nAbsorptionProducts = 0;
if (absorptionProducts != 0) nAbsorptionProducts = absorptionProducts->size();
for ( i = 0; i<nAbsorptionProducts; i++)
{
pProducts += (*absorptionProducts)[i]->GetMomentum();
productEnergy += (*absorptionProducts)[i]->GetKineticEnergy();
}
G4double newZ = nucleus->GetZ_asInt();
G4double newA = nucleus->GetA_asInt();
G4double bDiff = G4NucleiProperties::GetBindingEnergy(static_cast<G4int>(A),static_cast<G4int>(Z)) -
G4NucleiProperties::GetBindingEnergy(static_cast<G4int>(newA), static_cast<G4int>(newZ));
G4StopDeexcitationAlgorithm* nucleusAlgorithm = new G4StopTheoDeexcitation();
G4StopDeexcitation stopDeexcitation(nucleusAlgorithm);
nucleus->AddExcitationEnergy(bDiff);
// returns excitation energy for the moment ..
G4double energyDeposit = nucleus->GetEnergyDeposit();
if (verboseLevel>0)
{
G4cout << " -- KaonAtRest -- excitation = "
<< energyDeposit
<< ", pNucleus = "
<< pProducts
<< ", A: "
<< A
<< ", "
<< newA
<< ", Z: "
<< Z
<< ", "
<< newZ
<< G4endl;
}
if (energyDeposit < 0.)
G4Exception("G4KaonMinusAbsorptionAtRest::AtRestDoIt()", "HAD_STOP_0001",
FatalException, "Excitation energy < 0");
delete nucleus;
G4ReactionProductVector* fragmentationProducts = stopDeexcitation.DoBreakUp(newA,newZ,energyDeposit,pProducts);
unsigned int nFragmentationProducts = 0;
if (fragmentationProducts != 0) nFragmentationProducts = fragmentationProducts->size();
//Initialize ParticleChange
aParticleChange.Initialize(track);
aParticleChange.SetNumberOfSecondaries(G4int(nAbsorptionProducts+nFragmentationProducts) );
// update List of alive particles. put energy deposit at the right place ...
for (i = 0; i < nAbsorptionProducts; i++)
{aParticleChange.AddSecondary((*absorptionProducts)[i]); }
if (absorptionProducts != 0) delete absorptionProducts;
// for (i = 0; i < nFragmentationProducts; i++)
// { aParticleChange.AddSecondary(fragmentationProducts->at(i)); }
for(i=0; i<nFragmentationProducts; i++)
{
G4DynamicParticle * aNew =
new G4DynamicParticle((*fragmentationProducts)[i]->GetDefinition(),
(*fragmentationProducts)[i]->GetTotalEnergy(),
(*fragmentationProducts)[i]->GetMomentum());
G4double newTime = aParticleChange.GetGlobalTime((*fragmentationProducts)[i]->GetFormationTime());
aParticleChange.AddSecondary(aNew, newTime);
delete (*fragmentationProducts)[i];
}
if (fragmentationProducts != 0) delete fragmentationProducts;
// finally ...
aParticleChange.ProposeTrackStatus(fStopAndKill); // Kill the incident Kaon
return &aParticleChange;
}
G4DynamicParticle G4KaonMinusAbsorptionAtRest::GetAbsorbingNucleon()
{
G4DynamicParticle aNucleon;
// Get nucleon definition, based on Z,N of current Nucleus
aNucleon.SetDefinition(SelectAbsorbingNucleon());
// Fermi momentum distribution in three dimensions
G4ThreeVector pFermi = nucleus->GetFermiMomentum();
aNucleon.SetMomentum(pFermi);
return aNucleon;
}
G4ParticleDefinition* G4KaonMinusAbsorptionAtRest::SelectAbsorbingNucleon()
{
// (Ch. Voelcker) extended from ReturnTargetParticle():
// Choose a proton or a neutron as the absorbing particle,
// taking weight into account!
// Update nucleon's atomic numbers.
G4ParticleDefinition* absorbingParticleDef;
G4double ranflat = G4UniformRand();
G4double myZ = nucleus->GetZ_asInt(); // number of protons
G4double myN = nucleus->GetA_asInt(); // number of nucleons (not neutrons!!)
// See VanderVelde-Wilquet et al, Nuov.Cim.39A(1978)538;
G4double carbonRatioNP = 0.18; // (Rn/Rp)c, see page 544
G4double neutronProtonRatio = NeutronHaloFactor(myZ,myN)*carbonRatioNP*(myN-myZ)/myZ;
G4double protonProbability = 1./(1.+neutronProtonRatio);
if ( ranflat < protonProbability )
{
absorbingParticleDef = G4Proton::Proton();
myZ-= 1.;
}
else
{ absorbingParticleDef = G4Neutron::Neutron(); }
myN -= 1.;
nucleus->SetParameters(myN,myZ);
return absorbingParticleDef;
}
G4double G4KaonMinusAbsorptionAtRest::NeutronHaloFactor(G4double Z, G4double N)
{
// this function should take care of the probability for absorption
// on neutrons, depending on number of protons Z and number of neutrons N-Z
// parametrisation from fit to
// VanderVelde-Wilquet et al, Nuov.Cim.39A(1978)538;
//
if (Z == 1.) return 1.389; // deuterium
else if (Z == 2.) return 1.78; // helium
else if (Z == 10.) return 0.66; // neon
else
return 0.6742+(N-Z)*0.06524;
}
G4DynamicParticleVector* G4KaonMinusAbsorptionAtRest::KaonNucleonReaction()
{
G4DynamicParticleVector* products = new G4DynamicParticleVector();
G4double ranflat = G4UniformRand();
G4double prob = 0;
G4ParticleDefinition* producedBaryonDef;
G4ParticleDefinition* producedMesonDef;
G4double iniZ = nucleus->GetZ_asInt();
G4double iniA = nucleus->GetA_asInt();
G4DynamicParticle aNucleon = GetAbsorbingNucleon();
// DHW 15 may 2011: unused: G4double nucleonMass;
if (aNucleon.GetDefinition() == G4Proton::Proton())
{
// DHW 15 May 2011: unused: nucleonMass = proton_mass_c2+electron_mass_c2;
if ( (prob += rateLambdaZeroPiZero) > ranflat)
{ // lambda pi0
producedBaryonDef = G4Lambda::Lambda();
producedMesonDef = G4PionZero::PionZero();
}
else if ((prob += rateSigmaPlusPiMinus) > ranflat)
{ // sigma+ pi-
producedBaryonDef = G4SigmaPlus::SigmaPlus();
producedMesonDef = G4PionMinus::PionMinus();
}
else if ((prob += rateSigmaMinusPiPlus) > ranflat)
{ // sigma- pi+
producedBaryonDef = G4SigmaMinus::SigmaMinus();
producedMesonDef = G4PionPlus::PionPlus();
}
else
{ // sigma0 pi0
producedBaryonDef = G4SigmaZero::SigmaZero();
producedMesonDef = G4PionZero::PionZero();
}
}
else if (aNucleon.GetDefinition() == G4Neutron::Neutron())
{
// DHW 15 May 2011: unused: nucleonMass = neutron_mass_c2;
if ((prob += rateLambdaZeroPiMinus) > ranflat)
{ // lambda pi-
producedBaryonDef = G4Lambda::Lambda();
producedMesonDef = G4PionMinus::PionMinus();
}
else if ((prob += rateSigmaZeroPiMinus) > ranflat)
{ // sigma0 pi-
producedBaryonDef = G4SigmaZero::SigmaZero();
producedMesonDef = G4PionMinus::PionMinus();
}
else
{ // sigma- pi0
producedBaryonDef = G4SigmaMinus::SigmaMinus();
producedMesonDef = G4PionZero::PionZero();
}
}
else
{
if (verboseLevel>0)
{
G4cout
<< "G4KaonMinusAbsorption::KaonNucleonReaction: "
<< aNucleon.GetDefinition()->GetParticleName()
<< " is not a good nucleon - check G4Nucleus::ReturnTargetParticle()!"
<< G4endl;
}
return 0;
}
G4double newZ = nucleus->GetZ_asInt();
G4double newA = nucleus->GetA_asInt();
// Modify the Kaon mass to take nuclear binding energy into account
// .. using mas formula ..
// .. using mass table ..
// equivalent to -'initialBindingEnergy+nucleus.GetBindingEnergy' !
G4double nucleonBindingEnergy =
-G4NucleiProperties::GetBindingEnergy(static_cast<G4int>(iniA), static_cast<G4int>(iniZ) )
+G4NucleiProperties::GetBindingEnergy(static_cast<G4int>(newA), static_cast<G4int>(newZ) );
G4DynamicParticle modifiedHadron = (*stoppedHadron);
modifiedHadron.SetMass(stoppedHadron->GetMass() + nucleonBindingEnergy);
// Setup outgoing dynamic particles
G4ThreeVector dummy(0.,0.,0.);
G4DynamicParticle* producedBaryon = new G4DynamicParticle(producedBaryonDef,dummy);
G4DynamicParticle* producedMeson = new G4DynamicParticle(producedMesonDef,dummy);
// Produce the secondary particles in a twobody process:
G4ReactionKinematics theReactionKinematics;
theReactionKinematics.TwoBodyScattering( &modifiedHadron, &aNucleon,
producedBaryon, producedMeson);
products->push_back(producedBaryon);
products->push_back(producedMeson);
if (verboseLevel > 1)
{
G4cout
<< "G4KaonMinusAbsorption::KaonNucleonReaction: Number of primaries = "
<< products->size()
<< ": " <<producedMesonDef->GetParticleName()
<< ", " <<producedBaryonDef->GetParticleName() << G4endl;
}
return products;
}
G4bool G4KaonMinusAbsorptionAtRest::AbsorbPionByNucleus(G4DynamicParticle* aPion)
{
// Needs some more investigation!
G4double ranflat = G4UniformRand();
if (ranflat < pionAbsorptionRate){
// Add pion energy to ExcitationEnergy and NucleusMomentum
nucleus->AddExcitationEnergy(aPion->GetTotalEnergy());
nucleus->AddMomentum(aPion->GetMomentum());
}
return (ranflat < pionAbsorptionRate);
}
G4DynamicParticle* G4KaonMinusAbsorptionAtRest::SigmaLambdaConversion(G4DynamicParticle* aSigma)
{
G4double ranflat = G4UniformRand();
G4double sigmaLambdaConversionRate;
G4double A = nucleus->GetA_asInt();
G4double Z = nucleus->GetZ_asInt();
G4double newZ = Z;
// DHW 15 May 2011: unused: G4double nucleonMassDifference = 0;
G4ParticleDefinition* inNucleonDef=NULL;
G4ParticleDefinition* outNucleonDef=NULL;
// Decide which sigma
switch((int) aSigma->GetDefinition()->GetPDGCharge()) {
case 1:
sigmaLambdaConversionRate = sigmaPlusLambdaConversionRate;
inNucleonDef = G4Neutron::Neutron();
outNucleonDef = G4Proton::Proton();
newZ = Z+1;
// DHW 15 May 2011: unused: nucleonMassDifference = neutron_mass_c2 - proton_mass_c2-electron_mass_c2;
break;
case -1:
sigmaLambdaConversionRate = sigmaMinusLambdaConversionRate;
inNucleonDef = G4Proton::Proton();
outNucleonDef = G4Neutron::Neutron();
newZ = Z-1;
// DHW 15 May 2011: unused: nucleonMassDifference = proton_mass_c2+electron_mass_c2 - neutron_mass_c2;
break;
case 0:
sigmaLambdaConversionRate = sigmaZeroLambdaConversionRate;
// The 'outgoing' nucleon is just virtual, to keep the energy-momentum
// balance and will not appear in the ParticleChange. Therefore no need
// choose between neutron and proton here!
inNucleonDef = G4Neutron::Neutron();
outNucleonDef = G4Neutron::Neutron();
break;
default:
sigmaLambdaConversionRate = 0.;
// Add dummy particles to avoid possibility of passing NULL pointers
inNucleonDef = G4Proton::Proton();
outNucleonDef = G4Proton::Proton();
}
if (ranflat >= sigmaLambdaConversionRate) return 0;
G4ThreeVector dummy(0.,0.,0.);
// Fermi momentum distribution in three dimensions
G4ThreeVector momentum = nucleus->GetFermiMomentum();
G4ParticleDefinition* lambdaDef = G4Lambda::Lambda();
G4DynamicParticle inNucleon(inNucleonDef,momentum);
G4DynamicParticle outNucleon(outNucleonDef,dummy);
G4DynamicParticle* outLambda = new G4DynamicParticle(lambdaDef,dummy);
G4ReactionKinematics theReactionKinematics;
// Now do the twobody scattering
theReactionKinematics.TwoBodyScattering(aSigma, &inNucleon,
&outNucleon, outLambda);
// Binding energy of nucleus has changed. This will change the
// ExcitationEnergy.
// .. using mass formula ..
// .. using mass table ..
// equivalent to -'initialBindingEnergy+nucleus.GetBindingEnergy' !
// Add energy and momentum to nucleus, change Z,A
nucleus->AddExcitationEnergy(outNucleon.GetKineticEnergy());
nucleus->AddMomentum(outNucleon.GetMomentum());
nucleus->SetParameters(A,newZ);
// The calling routine is responsible to delete the sigma!!
return outLambda;
}