Files
geant4/source/processes/hadronic/models/inclxx/incl_physics/src/G4INCLCascade.cc
T

514 lines
20 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. *
// ********************************************************************
//
// INCL++ intra-nuclear cascade model
// Pekka Kaitaniemi, CEA and Helsinki Institute of Physics
// Davide Mancusi, CEA
// Alain Boudard, CEA
// Sylvie Leray, CEA
// Joseph Cugnon, University of Liege
//
// INCL++ revision: v5.0_rc3
//
#define INCLXX_IN_GEANT4_MODE 1
#include "globals.hh"
#include "G4INCLCascade.hh"
#include "G4INCLRandom.hh"
#include "G4INCLRanecu.hh"
#include "G4INCLGeant4Random.hh"
#include "G4INCLStandardPropagationModel.hh"
#include "G4INCLParticleTable.hh"
#include "G4INCLGlobalInfo.hh"
#include "G4INCLPauliBlocking.hh"
#include "G4INCLIPauli.hh"
#include "G4INCLPauliStrict.hh"
#include "G4INCLPauliStandard.hh"
#include "G4INCLPauliStrictStandard.hh"
#include "G4INCLPauliGlobal.hh"
#include "G4INCLCDPP.hh"
#include "G4INCLLogger.hh"
#include "G4INCLGlobals.hh"
#include "G4INCLNuclearDensityFactory.hh"
#include "G4INCLCoulombDistortion.hh"
#include "G4INCLICoulomb.hh"
#include "G4INCLCoulombNone.hh"
#include "G4INCLCoulombNonRelativistic.hh"
#include "G4INCLClustering.hh"
#include "G4INCLClusteringModelIntercomparison.hh"
#include "G4INCLClusteringModelNone.hh"
#include <cstring>
#include <cstdlib>
namespace G4INCL {
INCL::INCL(G4INCL::Config const * const config)
:propagationModel(0), theA(208), theZ(82), maxImpactParameter(0.),
theConfig(config)
{
// Set the logger object.
G4INCL::Logger::setLoggerSlave(new G4INCL::LoggerSlave(theConfig->getLogFileName()));
G4INCL::Logger::setVerbosityLevel(theConfig->getVerbosity());
// Set the random number generator algorithm. The system can support
// multiple different generator algorithms in a completely
// transparent way.
#ifdef INCLXX_IN_GEANT4_MODE
G4INCL::Random::setGenerator(new G4INCL::Geant4RandomGenerator());
#else
G4INCL::Random::setGenerator(new G4INCL::Ranecu(theConfig->getRandomSeeds()));
#endif // INCLXX_IN_GEANT4_MODE
// Select the Pauli blocking algorithm:
G4INCL::PauliType pauli = theConfig->getPauliType();
if(pauli == G4INCL::StrictStatisticalPauli)
G4INCL::Pauli::setBlocker(new G4INCL::PauliStrictStandard);
else if(pauli == G4INCL::StatisticalPauli)
G4INCL::Pauli::setBlocker(new G4INCL::PauliStandard);
else if(pauli == G4INCL::StrictPauli)
G4INCL::Pauli::setBlocker(new G4INCL::PauliStrict);
else if(pauli == G4INCL::GlobalPauli)
G4INCL::Pauli::setBlocker(new G4INCL::PauliGlobal);
else if(pauli == G4INCL::NoPauli)
G4INCL::Pauli::setBlocker(NULL);
if(theConfig->getCDPP())
G4INCL::Pauli::setCDPP(new G4INCL::CDPP);
else
G4INCL::Pauli::setCDPP(NULL);
// Select the Coulomb-distortion algorithm:
G4INCL::CoulombType coulombType = theConfig->getCoulombType();
if(coulombType == G4INCL::NonRelativisticCoulomb)
G4INCL::CoulombDistortion::setCoulomb(new G4INCL::CoulombNonRelativistic);
else // if(coulombType == G4INCL::NoCoulomb)
G4INCL::CoulombDistortion::setCoulomb(new G4INCL::CoulombNone);
// Select the clustering algorithm:
G4INCL::ClusterAlgorithmType clusterAlgorithm = theConfig->getClusterAlgorithm();
if(clusterAlgorithm == G4INCL::IntercomparisonClusterAlgorithm) {
G4INCL::Clustering::setClusteringModel(new G4INCL::ClusteringModelIntercomparison);
// Set the maximum mass for the clustering algorithm
G4INCL::IClusteringModel::maxClusterAlgorithmMass = theConfig->getClusterMaxMass();
}
else // if(clusterAlgorithm == G4INCL::NoClusterAlgorithm)
G4INCL::Clustering::setClusteringModel(new G4INCL::ClusteringModelNone);
// Initialize the INCL particle table:
G4INCL::ParticleTable::initialize();
// Propagation model is responsible for finding avatars and
// transporting the particles. In principle this step is "hidden"
// behind an abstract G4interface and the rest of the system does not
// care how the transportation and avatar finding is done. This
// should allow us to "easily" experiment with different avatar
// finding schemes and even to support things like curved
// trajectories in the future.
propagationModel = new G4INCL::StandardPropagationModel(theConfig->getLocalEnergyBBType(),theConfig->getLocalEnergyPiType());
eventAction = new EventAction();
propagationAction = new PropagationAction();
avatarAction = new AvatarAction();
std::strcpy(theGlobalInfo.cascadeModel, theConfig->getVersionID().c_str());
std::strcpy(theGlobalInfo.deexcitationModel, "none");
// Set the target
if(!theConfig->isNaturalTarget()) {
setTarget(theConfig->getTargetA(), theConfig->getTargetZ());
// Fill in the global information
theGlobalInfo.At = theConfig->getTargetA();
theGlobalInfo.Zt = theConfig->getTargetZ();
} else {
// TODO: support for natural targets
FATAL("Fatal: natural targets are not supported yet." << std::endl);
std::exit(EXIT_FAILURE);
}
#ifndef INCLXX_IN_GEANT4_MODE
// Echo the input parameters to the log file
INFO(theConfig->echo() << std::endl);
#endif
}
INCL::INCL(IPropagationModel *aPropagationModel)
:propagationModel(aPropagationModel), theA(208), theZ(82), maxImpactParameter(0.), theConfig(NULL)
{
// Set the random number generator algorithm. The system can support
// multiple different generator algorithms in a completely
// transparent way.
G4INCL::Random::setGenerator(new G4INCL::Ranecu());
}
INCL::~INCL() {
G4INCL::Pauli::deleteBlockers();
G4INCL::CoulombDistortion::deleteCoulomb();
G4INCL::Random::deleteGenerator();
G4INCL::ParticleTable::deletePDS();
G4INCL::Clustering::deleteClusteringModel();
G4INCL::Logger::deleteLoggerSlave();
delete avatarAction;
delete propagationAction;
delete eventAction;
delete propagationModel;
}
void INCL::setTarget(G4int A, G4int Z) {
if(A > 0 && A < 300 && Z > 0 && Z < 200) {
theA = A;
theZ = Z;
} else {
ERROR("Unsupported target: A = " << A << " Z = " << Z << std::endl);
ERROR("Target configuration rejected." << std::endl);
}
// Set the maximum impact parameter
// TODO: for natural target abundances, make this the largest impact
// parameter for all the isotopes.
// TODO: reduce the maximum impact parameter for Coulomb-distorted
// trajectories. Make this dependent on the configuration choice for
// Coulomb distortion.
NuclearDensity const * const density = NuclearDensityFactory::createDensity(A,Z);
maxImpactParameter = density->getMaximumRadius();
delete density;
// Set the geometric cross section
theGlobalInfo.geometricCrossSection =
Math::tenPi*std::pow(maxImpactParameter,2);
}
G4bool INCL::initializeTarget(G4int A, G4int Z) {
Nucleus *previousNucleus = propagationModel->getNucleus();
delete previousNucleus;
Nucleus *aNucleus = new Nucleus(A, Z, theConfig);
aNucleus->getStore()->getBook()->reset();
aNucleus->initializeParticles();
propagationModel->setNucleus(aNucleus);
return true;
}
const EventInfo &INCL::processEvent(Particle *projectile) {
initializeTarget(theA, theZ);
// Usage of the projectile API:
// Test projectile:
// G4INCL::ThreeVector position(0.0, 0.0, 0.0);
// G4INCL::ThreeVector momentum(0.0, 0.0, 2000.0);
// G4double energy = std::sqrt(momentum.mag2() + G4INCL::ProtonMass * G4INCL::ProtonMass);
// G4INCL::Particle *projectile = new G4INCL::Particle(G4INCL::Proton, energy,
// momentum, position);
// composite
// G4INCL::Nucleus *projectileNucleus = new G4INCL::Nucleus(6, 12);
//projectileNucleus->initializeParticles();
// Create a nucleus of Z = 82 and A = 208
// G4INCL::Nucleus *theNucleus = new G4INCL::Nucleus(6, 12);
// Generate the initial distribution of particles
// theNucleus->initializeParticles();
// theNucleus->shootMe(projectile);
// theNucleus->shootMe(projectileNucleus);
// Manually set the stopping time of the simulation.
// propagationModel->setStoppingTime(70.0);
// Assign the nucleus to the propagation model
// propagationModel->setNucleus(theNucleus);
// Shortcut poG4inter
Nucleus *nucleus = propagationModel->getNucleus();
// Reset theEventInfo
theEventInfo.reset();
EventInfo::eventNumber++;
// Increment the global counter for the number of shots
theGlobalInfo.nShots++;
// Fill in the global information
// TODO: should be moved to the input processing
theGlobalInfo.Ap = projectile->getA();
theGlobalInfo.Zp = projectile->getZ();
theGlobalInfo.Ep = projectile->getKineticEnergy();
// Fill in the event information
theEventInfo.projectileType = projectile->getType();
theEventInfo.Ap = projectile->getA();
theEventInfo.Zp = projectile->getZ();
theEventInfo.Ep = projectile->getKineticEnergy();
theEventInfo.At = nucleus->getA();
theEventInfo.Zt = nucleus->getZ();
// Randomly draw an impact parameter
G4double impactParameter = maxImpactParameter * std::sqrt(Random::shoot());
// Fill in the event information
theEventInfo.impactParameter = impactParameter;
G4bool projectileHitsTarget = propagationModel->shootProjectile(projectile, impactParameter);
if(projectileHitsTarget == false) {
// Increment the global counter for the number of transparents
theGlobalInfo.nTransparents++;
// Fill in the event information
theEventInfo.transparent = true;
// Delete the projectile!
delete projectile;
return theEventInfo;
}
// Fill in the event information
const G4double effectiveImpactParameter =
projectile->getTransversePosition().mag();
theEventInfo.effectiveImpactParameter = effectiveImpactParameter;
do {
// Run book keeping actions that should take place before propagation:
propagationAction->beforePropagationAction(propagationModel);
// Get the avatar with the smallest time and propagate particles
// to that poG4int in time.
G4INCL::IAvatar *avatar = propagationModel->propagate();
// Run book keeping actions that should take place after propagation:
propagationAction->afterPropagationAction(propagationModel, avatar);
if(avatar == 0) break; // No more avatars in the avatar list.
// Run book keeping actions that should take place before avatar:
avatarAction->beforeAvatarAction(avatar, nucleus);
// Channel is responsible for calculating the outcome of the
// selected avatar. There are different kinds of channels. The
// class IChannel is, again, an abstract G4interface that defines
// the externally observable behavior of all G4interaction
// channels.
// The handling of the channel is transparent to the API.
// Final state tells what changed...
G4INCL::FinalState *finalState = avatar->getFinalState();
// Run book keeping actions that should take place after avatar:
avatarAction->afterAvatarAction(avatar, nucleus, finalState);
// So now we must give this information to the nucleus
nucleus->applyFinalState(finalState);
// and now we are ready to process the next avatar!
delete avatar;
delete finalState;
} while(continueCascade());
// Fill in the event information
theEventInfo.transparent = nucleus->isEventTransparent();
if(theEventInfo.transparent) {
// Increment the global counter for the number of transparents
theGlobalInfo.nTransparents++;
} else {
// Check if the nucleus contains deltas
theEventInfo.deltasInside = nucleus->containsDeltas();
// Take care of any remaining deltas
theEventInfo.forcedDeltasOutside = nucleus->decayOutgoingDeltas();
theEventInfo.forcedDeltasInside = nucleus->decayInsideDeltas();
// Cluster decay
theEventInfo.clusterDecay = nucleus->decayOutgoingClusters();
// Apply Coulomb distortion, if appropriate
// Note that this will apply Coulomb distortion also on pions emitted by
// unphysical remnants (see decayInsideDeltas). This is at variance with
// what INCL4.6 does, but these events are (should be!) so rare that
// whatever we do doesn't (shouldn't!) make any noticeable difference.
G4INCL::CoulombDistortion::distortOut(nucleus->getStore()->getOutgoingParticles(), nucleus);
// Compute recoil momentum, energy and spin of the nucleus
nucleus->computeRecoilKinematics();
// Make room for the remnant recoil by rescaling the energies of the
// outgoing particles.
if(nucleus->hasRemnant()) rescaleOutgoingForRecoil();
// Global checks of conservation laws
globalConservationChecks();
// Fill the EventInfo structure
nucleus->fillEventInfo(&theEventInfo);
// theEventInfo.fillFromNucleus(nucleus);
theEventInfo.stoppingTime = propagationModel->getCurrentTime();
}
return theEventInfo;
}
void INCL::rescaleOutgoingForRecoil() {
Nucleus *nucleus = propagationModel->getNucleus();
G4double sumKineticEnergies = 0.0;
// Sum up the kinetic energies of the outgoing particles
ParticleList outgoingParticles = nucleus->getStore()->getOutgoingParticles();
for( ParticleIter i = outgoingParticles.begin(); i != outgoingParticles.end(); ++i )
sumKineticEnergies += (*i)->getKineticEnergy();
// If there is too little outgoing energy, we stop here.
if(sumKineticEnergies <= 0.001) return;
// The rescaling factor
G4double rescale = 1. - nucleus->getRecoilEnergy()/sumKineticEnergies;
if(rescale < 0.0) {
WARN("Cannot accommodate remnant recoil by scaling outgoing energies. rescale = " << rescale << std::endl);
rescale = 0.0;
}
// Rescale the energies (and the momenta) of the outgoing particles.
ThreeVector pBalance = nucleus->getIncomingMomentum();
for( ParticleIter i = outgoingParticles.begin(); i != outgoingParticles.end(); ++i )
{
const G4double mass = (*i)->getMass();
const G4double newKineticEnergy = (*i)->getKineticEnergy() * rescale;
(*i)->setEnergy(mass + newKineticEnergy);
(*i)->adjustMomentumFromEnergy();
//nucleus->updatePotentialEnergy(*i);
pBalance -= (*i)->getMomentum();
}
nucleus->setRecoilMomentum(pBalance);
const G4double remnantMass = ParticleTable::getMass(nucleus->getA(),nucleus->getZ()) + nucleus->getExcitationEnergy();
const G4double pRem2 = pBalance.mag2();
const G4double recoilEnergy = pRem2/
(std::sqrt(pRem2+remnantMass*remnantMass) + remnantMass);
nucleus->setRecoilEnergy(recoilEnergy);
}
void INCL::globalConservationChecks() {
const Nucleus *nucleus = propagationModel->getNucleus();
/* FIXME: This version of the energy-conservation check only uses kinetic
energies, to mimic what INCL4.5 does. This is unsatisfactory because it
does not take G4into account the particle masses. At some poG4int, it would
be nice to have real energy conservation, with real masses. When ready
to do so, have a look at the status of the code at commit
aad75d09b8a52d28b8eb1bd38bdf347e63b802db (or possibly simply revert the
following commit). */
// Initialise balance variables with the incoming values
G4int ZBalance = theEventInfo.Zp + theEventInfo.Zt;
G4int ABalance = theEventInfo.Ap + theEventInfo.At;
G4double projectileMass = 0.0;
// FIXME: since we are not using total energies, we must set the projectile
// mass to zero if the projectile is a pion.
if(theEventInfo.projectileType != PiPlus &&
theEventInfo.projectileType != PiZero &&
theEventInfo.projectileType != PiMinus)
projectileMass = ParticleTable::getMass(theEventInfo.projectileType);
G4double EBalance = nucleus->getInitialEnergy() - ParticleTable::getMass(theEventInfo.At, theEventInfo.Zt) - projectileMass;
ThreeVector pBalance = nucleus->getIncomingMomentum();
// Process outgoing particles
ParticleList outgoingParticles = nucleus->getStore()->getOutgoingParticles();
for( ParticleIter i = outgoingParticles.begin(); i != outgoingParticles.end(); ++i ) {
ZBalance -= (*i)->getZ();
ABalance -= (*i)->getA();
if((*i)->isPion()) // Ugly: we should calculate everything using total energies! (FIXME)
EBalance -= (*i)->getEnergy();
else
EBalance -= (*i)->getKineticEnergy();
pBalance -= (*i)->getMomentum();
}
EBalance -= nucleus->computeSeparationEnergyBalance();
// Remnant contribution, if present
if(nucleus->hasRemnant()) {
ZBalance -= nucleus->getZ();
ABalance -= nucleus->getA();
EBalance -= //ParticleTable::getMass(nucleus->getA(),nucleus->getZ()) +
nucleus->getExcitationEnergy() + nucleus->getRecoilEnergy();
pBalance -= nucleus->getRecoilMomentum();
}
// Global conservation checks
const G4double pLongBalance = pBalance.getZ();
const G4double pTransBalance = pBalance.perp();
if(ZBalance != 0) {
ERROR("Violation of charge conservation! ZBalance = " << ZBalance << std::endl);
}
if(ABalance != 0) {
ERROR("Violation of baryon-number conservation! ABalance = " << ABalance << std::endl);
}
if(std::abs(EBalance)>10.0) {
WARN("Violation of energy conservation > 10 MeV. EBalance = " << EBalance << std::endl);
}
if(std::abs(pLongBalance)>5.0) {
WARN("Violation of longitudinal momentum conservation > 5.0 MeV. pLongBalance = " << pLongBalance << std::endl);
}
if(std::abs(pTransBalance)>5.0) {
WARN("Violation of transverse momentum conservation > 5.0 MeV. pTransBalance = " << pTransBalance << std::endl);
}
// Feed the EventInfo variables
theEventInfo.EBalance = EBalance;
theEventInfo.pLongBalance = pLongBalance;
theEventInfo.pTransBalance = pTransBalance;
}
G4bool INCL::continueCascade() {
Nucleus *nucleus = propagationModel->getNucleus();
// Stop if we have passed the stopping time
if(propagationModel->getCurrentTime() > propagationModel->getStoppingTime()) return false;
// Stop if there are no participants and no pions inside the nucleus
if(nucleus->getStore()->getBook()->getParticipants()==0 &&
nucleus->getStore()->getIncomingParticles().empty()) return false;
// Stop if the remnant has only one nucleon
if(nucleus->getA() <= 1) return false;
return true;
}
void INCL::finaliseGlobalInfo() {
theGlobalInfo.reactionCrossSection = theGlobalInfo.geometricCrossSection *
((G4double) (theGlobalInfo.nShots - theGlobalInfo.nTransparents)) /
((G4double) theGlobalInfo.nShots);
theGlobalInfo.errorReactionCrossSection = theGlobalInfo.geometricCrossSection *
std::sqrt((G4double) (theGlobalInfo.nShots - theGlobalInfo.nTransparents)) /
((G4double) theGlobalInfo.nShots);
}
}