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

438 lines
17 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"
/*
* StandardPropagationModel.cpp
*
* Created on: 4 juin 2009
* Author: Pekka Kaitaniemi
*/
#include "G4INCLStandardPropagationModel.hh"
#include "G4INCLSurfaceAvatar.hh"
#include "G4INCLBinaryCollisionAvatar.hh"
#include "G4INCLDecayAvatar.hh"
#include "G4INCLCrossSections.hh"
#include "G4INCLRandom.hh"
#include <iostream>
#include "G4INCLLogger.hh"
#include "G4INCLGlobals.hh"
#include "G4INCLKinematicsUtils.hh"
#include "G4INCLCoulombDistortion.hh"
#include "G4INCLDeltaDecayChannel.hh"
namespace G4INCL {
StandardPropagationModel::StandardPropagationModel(LocalEnergyType localEnergyType, LocalEnergyType localEnergyDeltaType)
:theNucleus(0), maximumTime(70.0), currentTime(0.0), firstAvatar(true),
theLocalEnergyType(localEnergyType),
theLocalEnergyDeltaType(localEnergyDeltaType)
{
}
StandardPropagationModel::~StandardPropagationModel()
{
delete theNucleus;
}
G4INCL::Nucleus* StandardPropagationModel::getNucleus()
{
return theNucleus;
}
G4bool StandardPropagationModel::shootProjectile(G4INCL::Particle *p, G4double impactParameter) {
firstAvatar = true;
currentTime = 0.0;
G4double temfin = 0.0;
if( p->isNucleon() )
temfin = 29.8 * std::pow(theNucleus->getA(), 0.16);
else {
const G4double tlab = p->getEnergy() - p->getMass();
temfin = 30.18 * std::pow(theNucleus->getA(), 0.17*(1.0 - 5.7E-5*tlab));
}
maximumTime = temfin;
// If Coulomb is activated, do not process events with impact
// parameter larger than the maximum impact parameter, taking G4into
// account Coulomb distortion.
if(impactParameter>CoulombDistortion::maxImpactParameter(p,theNucleus))
return false;
const G4double tbid = Random::shoot() * Math::twoPi;
ThreeVector position(impactParameter * std::cos(tbid),
impactParameter * std::sin(tbid),
-1.E3);
p->setPosition(position);
theNucleus->setIncomingAngularMomentum(p->getAngularMomentum());
theNucleus->setIncomingMomentum(p->getMomentum());
theNucleus->setInitialEnergy(p->getEnergy() + ParticleTable::getMass(theNucleus->getA(),theNucleus->getZ()));
CoulombDistortion::bringToSurface(p, theNucleus);
theNucleus->getStore()->addIncomingParticle(p); // puts the particle in the waiting list
theNucleus->particleEnters(p); // removes the particle from the waiting list and changes its kinetic energy
theNucleus->insertParticipant(p);
return true;
}
G4bool StandardPropagationModel::shootProjectile(G4INCL::Nucleus * /* p */, G4double /* impactParameter */) {
firstAvatar = true;
currentTime = 0.0;
return true;
}
G4double StandardPropagationModel::getStoppingTime() {
return maximumTime;
}
void StandardPropagationModel::setStoppingTime(G4double time) {
if(time > 0.0) {
maximumTime = time;
} else {
ERROR("new stopping time is smaller than 0!" << std::endl);
}
}
G4double StandardPropagationModel::getCurrentTime() {
return currentTime;
}
void StandardPropagationModel::setNucleus(G4INCL::Nucleus *nucleus)
{
theNucleus = nucleus;
}
void StandardPropagationModel::registerAvatar(G4INCL::IAvatar *anAvatar)
{
if(anAvatar) theNucleus->getStore()->add(anAvatar);
}
IAvatar *StandardPropagationModel::generateBinaryCollisionAvatar(Particle * const p1, Particle * const p2) const {
// Is either particle a participant?
if(!p1->isParticipant() && !p2->isParticipant()) return NULL;
// Is it a pi-resonance collision (we don't treat them)?
if((p1->isResonance() && p2->isPion()) || (p1->isPion() && p2->isResonance()))
return NULL;
// 2N < Tf
if(
(p1->isNucleon() && p1->getKineticEnergy()<theNucleus->getPotential()->getFermiEnergy(p1->getType())) &&
(p2->isNucleon() && p2->getKineticEnergy()<theNucleus->getPotential()->getFermiEnergy(p2->getType()))
)
return NULL;
// Is the CM energy > cutNN? (no cutNN on the first collision)
if(theNucleus->getStore()->getBook()->getAcceptedCollisions()>0
&& p1->isNucleon() && p2->isNucleon()
&& KinematicsUtils::squareTotalEnergyInCM(p1,p2) < BinaryCollisionAvatar::cutNNSquared) return NULL;
// Will the avatar take place between now and the end of the cascade?
G4double minDistOfApproachSquared = 0.0;
G4double t = getTime(p1, p2, &minDistOfApproachSquared);
if(t>maximumTime || t<currentTime) return NULL;
// Local energy. Jump through some hoops to calculate the cross section
// at the collision poG4int, and clean up after yourself afterwards.
ThreeVector mom1, mom2, pos1, pos2;
G4double energy1 = 0.0, energy2 = 0.0;
G4bool hasLocalEnergy;
if(p1->isPion() || p2->isPion())
hasLocalEnergy = ((theLocalEnergyDeltaType == FirstCollisionLocalEnergy &&
theNucleus->getStore()->getBook()->getAcceptedCollisions()==0) ||
theLocalEnergyDeltaType == AlwaysLocalEnergy);
else
hasLocalEnergy = ((theLocalEnergyType == FirstCollisionLocalEnergy &&
theNucleus->getStore()->getBook()->getAcceptedCollisions()==0) ||
theLocalEnergyType == AlwaysLocalEnergy);
const G4bool p1HasLocalEnergy = (hasLocalEnergy && !p1->isPion());
const G4bool p2HasLocalEnergy = (hasLocalEnergy && !p2->isPion());
if(p1HasLocalEnergy) {
mom1 = p1->getMomentum();
pos1 = p1->getPosition();
energy1 = p1->getEnergy();
p1->propagate(t - currentTime);
if(p1->getPosition().mag() > theNucleus->getSurfaceRadius(p1)) {
p1->setPosition(pos1);
p1->setMomentum(mom1);
p1->setEnergy(energy1);
return NULL;
}
KinematicsUtils::transformToLocalEnergyFrame(theNucleus, p1);
}
if(p2HasLocalEnergy) {
energy2 = p2->getEnergy();
mom2 = p2->getMomentum();
pos2 = p2->getPosition();
p2->propagate(t - currentTime);
if(p2->getPosition().mag() > theNucleus->getSurfaceRadius(p2)) {
p2->setPosition(pos2);
p2->setMomentum(mom2);
p2->setEnergy(energy2);
if(p1HasLocalEnergy) {
p1->setPosition(pos1);
p1->setMomentum(mom1);
p1->setEnergy(energy1);
}
return NULL;
}
KinematicsUtils::transformToLocalEnergyFrame(theNucleus, p2);
}
// Compute the total cross section
const G4double totalCrossSection = CrossSections::total(p1, p2);
// Restore particles to their state before the local-energy tweak
if(p1HasLocalEnergy) {
p1->setPosition(pos1);
p1->setMomentum(mom1);
p1->setEnergy(energy1);
}
if(p2HasLocalEnergy) {
p2->setPosition(pos2);
p2->setMomentum(mom2);
p2->setEnergy(energy2);
}
// Do the particles come close enough to each other?
if(Math::tenPi*minDistOfApproachSquared > totalCrossSection) return NULL;
// Warn if the two collision partners are the same particle
if(p1->getID() == p2->getID()) {
ERROR("At BinaryCollisonAvatar generation, ID1 (" << p1->getID()
<< ") == ID2 (" << p2->getID() <<")." << std::endl);
}
// Return a new avatar, then!
return new G4INCL::BinaryCollisionAvatar(t, totalCrossSection, theNucleus, p1, p2);
}
G4double StandardPropagationModel::getReflectionTime(G4INCL::Particle const * const aParticle) {
G4double time = 0.0;
const G4double T2 = aParticle->getMomentum().mag2();
const G4double T4 = aParticle->getPosition().mag2();
const G4double r = theNucleus->getSurfaceRadius(aParticle);
const G4double T1 = aParticle->getMomentum().dot(aParticle->getPosition());
const G4double T3 = T1/T2;
const G4double T5 = T3*T3 + (r*r-T4)/T2;
if(T5 < 0.0) {
ERROR("Imaginary reflection time! Delta = " << T5 << " for particle: " << std::endl
<< aParticle->prG4int());
time = 10000.0;
} else {
time = currentTime + (-T3 + std::sqrt(T5)) * aParticle->getEnergy();
}
return time;
}
G4double StandardPropagationModel::getTime(G4INCL::Particle const * const particleA,
G4INCL::Particle const * const particleB, G4double *minDistOfApproach) const
{
G4double time;
G4INCL::ThreeVector t13 = particleA->getMomentum()/particleA->getEnergy();
t13 -= particleB->getMomentum()/particleB->getEnergy();
G4INCL::ThreeVector distance = particleA->getPosition();
distance -= particleB->getPosition();
const G4double t7 = t13.dot(distance);
const G4double dt = t13.mag2();
if(dt <= 1.0e-10) {
(*minDistOfApproach) = 100000.0;
return currentTime + 100000.0;
} else {
time = -t7/dt;
}
(*minDistOfApproach) = distance.mag2() + time * t7;
return currentTime + time;
}
void StandardPropagationModel::checkCollisions(const ParticleList &participants,
const ParticleList &particles)
{
G4int iind = 1, jind = 1;
for(ParticleIter i = participants.begin(); i != participants.end(); ++i) {
jind = 0;
for(ParticleIter j = particles.begin(); j != particles.end(); ++j) {
if( (*j)->isParticipant() )
{
++jind;
if(jind >= iind) continue;
}
if((*i)->getID() == (*j)->getID()) continue; // Do not process the collision of a particle with itself
registerAvatar(generateBinaryCollisionAvatar(*i,*j));
}
++iind;
}
}
void StandardPropagationModel::generateUpdatedCollisions(const ParticleList &updatedParticles, const ParticleList &particles) {
// Loop over all the updated particles
for(ParticleIter updated = updatedParticles.begin(); updated != updatedParticles.end(); ++updated)
{
// Loop over all the particles
for(ParticleIter particle = particles.begin(); particle != particles.end(); ++particle)
{
/* Consider the generation of a collision avatar only if (*particle)
* is not one of the updated particles.
* The criterion makes sure that you don't generate avatars between
* updated particles. */
if((*particle)->isInList(updatedParticles)) continue;
registerAvatar(generateBinaryCollisionAvatar(*particle,*updated));
}
}
}
void StandardPropagationModel::generateCollisions(const ParticleList &particles, const ParticleList &except) {
G4bool haveExcept;
haveExcept=(except.size()!=0);
// Loop over all the particles
for(ParticleIter p1 = particles.begin(); p1 != particles.end(); ++p1)
{
// Loop over the rest of the particles
ParticleIter p2 = p1;
for(++p2; p2 != particles.end(); ++p2)
{
// Skip the collision if both particles must be excluded
if(haveExcept && (*p1)->isInList(except) && (*p2)->isInList(except)) continue;
registerAvatar(generateBinaryCollisionAvatar(*p1,*p2));
}
}
}
void StandardPropagationModel::updateAvatars(const ParticleList &particles) {
for(ParticleIter iter = particles.begin(); iter != particles.end(); ++iter) {
G4double time = this->getReflectionTime(*iter);
if(time <= maximumTime) registerAvatar(new SurfaceAvatar(*iter, time, theNucleus));
}
ParticleList p = theNucleus->getStore()->getParticles();
generateUpdatedCollisions(particles, p); // Predict collisions with spectators and participants
}
void StandardPropagationModel::generateAllAvatars(G4bool excludeUpdated) {
ParticleList particles = theNucleus->getStore()->getParticles();
if(particles.empty()) { ERROR("No particles inside the nucleus!" << std::endl); }
for(ParticleIter i = particles.begin(); i != particles.end(); ++i) {
G4double time = this->getReflectionTime(*i);
if(time <= maximumTime) registerAvatar(new SurfaceAvatar(*i, time, theNucleus));
}
ParticleList except;
if(excludeUpdated)
except = theNucleus->getUpdatedParticles();
generateCollisions(particles,except);
generateDecays(particles);
}
void StandardPropagationModel::generateDecays(const ParticleList &particles) {
for(ParticleIter i = particles.begin(); i != particles.end(); ++i) {
if((*i)->isDelta()) {
G4double decayTime = DeltaDecayChannel::computeDecayTime((*i));
G4double time = currentTime + decayTime;
if(time <= maximumTime) {
registerAvatar(new DecayAvatar((*i), time, theNucleus));
}
}
}
}
G4INCL::IAvatar* StandardPropagationModel::propagate()
{
if(firstAvatar) { // When we propagate particles for the first time we create the full list of avatars.
generateAllAvatars();
/* if(!theNucleus->getStore()->containsCollisions()) {
theNucleus->forceTransparent();
return NULL;
}*/
firstAvatar = false;
} else { // For subsequent avatars we update only the
// information related to particles that were updated
// by the previous avatar.
#ifdef INCL_REGENERATE_AVATARS
#warning "The INCL_REGENERATE_AVATARS code has not been tested in a while. Use it at your peril."
// Regenerates the entire avatar list, skipping collisions between
// updated particles
if(theNucleus->getUpdatedParticles().size()!=0 || theNucleus->getCreatedParticles().size()!=0) {
theNucleus->getStore()->clearAvatars();
theNucleus->getStore()->initialiseParticleAvatarConnections();
generateAllAvatars(true);
}
#else
// Deltas are created by transforming nucleon G4into a delta for
// efficiency reasons
Particle * const blockedDelta = theNucleus->getBlockedDelta();
ParticleList updatedParticles = theNucleus->getUpdatedParticles();
if(blockedDelta)
updatedParticles.push_back(blockedDelta);
generateDecays(updatedParticles);
ParticleList needNewAvatars = theNucleus->getUpdatedParticles();
ParticleList created = theNucleus->getCreatedParticles();
needNewAvatars.splice(needNewAvatars.end(), created);
updateAvatars(needNewAvatars);
#endif
}
G4INCL::IAvatar *theAvatar = theNucleus->getStore()->findSmallestTime();
if(theAvatar == 0) return 0; // Avatar list is empty
// theAvatar->dispose();
theNucleus->getStore()->timeStep(theAvatar->getTime() - currentTime);
if(theAvatar->getTime() <= currentTime) {
ERROR("Avatar time = " << theAvatar->getTime() << ", currentTime = " << currentTime << std::endl);
return 0;
} else {
currentTime = theAvatar->getTime();
theNucleus->getStore()->getBook()->setCurrentTime(currentTime);
}
return theAvatar;
}
}