Files
2025-12-05 08:54:02 +01:00

1279 lines
41 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
// Alain Boudard, CEA-Saclay, France
// Joseph Cugnon, University of Liege, Belgium
// Jean-Christophe David, CEA-Saclay, France
// Pekka Kaitaniemi, CEA-Saclay, France, and Helsinki Institute of Physics, Finland
// Sylvie Leray, CEA-Saclay, France
// Davide Mancusi, CEA-Saclay, France
//
#define INCLXX_IN_GEANT4_MODE 1
#include "globals.hh"
/*
* G4INCLParticle.hh
*
* \date Jun 5, 2009
* \author Pekka Kaitaniemi
*/
#ifndef PARTICLE_HH_
#define PARTICLE_HH_
#include "G4INCLThreeVector.hh"
#include "G4INCLParticleTable.hh"
#include "G4INCLParticleType.hh"
#include "G4INCLParticleSpecies.hh"
#include "G4INCLLogger.hh"
#include "G4INCLUnorderedVector.hh"
#include "G4INCLAllocationPool.hh"
#include <sstream>
#include <string>
namespace G4INCL {
class Particle;
class ParticleList : public UnorderedVector<Particle*> {
public:
void rotatePositionAndMomentum(const G4double angle, const ThreeVector &axis) const;
void rotatePosition(const G4double angle, const ThreeVector &axis) const;
void rotateMomentum(const G4double angle, const ThreeVector &axis) const;
void boost(const ThreeVector &b) const;
G4double getParticleListBias() const;
std::vector<G4int> getParticleListBiasVector() const;
};
typedef ParticleList::const_iterator ParticleIter;
typedef ParticleList::iterator ParticleMutableIter;
class Particle {
public:
Particle();
Particle(ParticleType t, G4double energy, ThreeVector const &momentum, ThreeVector const &position);
Particle(ParticleType t, ThreeVector const &momentum, ThreeVector const &position);
virtual ~Particle() {}
/** \brief Copy constructor
*
* Does not copy the particle ID.
*/
Particle(const Particle &rhs) :
theZ(rhs.theZ),
theA(rhs.theA),
theS(rhs.theS),
theParticipantType(rhs.theParticipantType),
theType(rhs.theType),
theEnergy(rhs.theEnergy),
theFrozenEnergy(rhs.theFrozenEnergy),
theMomentum(rhs.theMomentum),
theFrozenMomentum(rhs.theFrozenMomentum),
thePosition(rhs.thePosition),
nCollisions(rhs.nCollisions),
nDecays(rhs.nDecays),
nSrcPair(rhs.nSrcPair),
thePotentialEnergy(rhs.thePotentialEnergy),
rpCorrelated(rhs.rpCorrelated),
uncorrelatedMomentum(rhs.uncorrelatedMomentum),
theParticleBias(rhs.theParticleBias),
theNKaon(rhs.theNKaon),
#ifdef INCLXX_IN_GEANT4_MODE
theParentResonancePDGCode(rhs.theParentResonancePDGCode),
theParentResonanceID(rhs.theParentResonanceID),
#endif
theHelicity(rhs.theHelicity),
emissionTime(rhs.emissionTime),
outOfWell(rhs.outOfWell),
theSrcPartner(rhs.theSrcPartner),
theMass(rhs.theMass)
{
if(rhs.thePropagationEnergy == &(rhs.theFrozenEnergy))
thePropagationEnergy = &theFrozenEnergy;
else
thePropagationEnergy = &theEnergy;
if(rhs.thePropagationMomentum == &(rhs.theFrozenMomentum))
thePropagationMomentum = &theFrozenMomentum;
else
thePropagationMomentum = &theMomentum;
// ID intentionally not copied
ID = nextID++;
theBiasCollisionVector = rhs.theBiasCollisionVector;
}
protected:
/// \brief Helper method for the assignment operator
void swap(Particle &rhs) {
std::swap(theZ, rhs.theZ);
std::swap(theA, rhs.theA);
std::swap(theS, rhs.theS);
std::swap(theParticipantType, rhs.theParticipantType);
std::swap(theType, rhs.theType);
if(rhs.thePropagationEnergy == &(rhs.theFrozenEnergy))
thePropagationEnergy = &theFrozenEnergy;
else
thePropagationEnergy = &theEnergy;
std::swap(theEnergy, rhs.theEnergy);
std::swap(theFrozenEnergy, rhs.theFrozenEnergy);
if(rhs.thePropagationMomentum == &(rhs.theFrozenMomentum))
thePropagationMomentum = &theFrozenMomentum;
else
thePropagationMomentum = &theMomentum;
std::swap(theMomentum, rhs.theMomentum);
std::swap(theFrozenMomentum, rhs.theFrozenMomentum);
std::swap(thePosition, rhs.thePosition);
std::swap(nCollisions, rhs.nCollisions);
std::swap(nDecays, rhs.nDecays);
std::swap(nSrcPair, rhs.nSrcPair),
std::swap(thePotentialEnergy, rhs.thePotentialEnergy);
// ID intentionally not swapped
#ifdef INCLXX_IN_GEANT4_MODE
std::swap(theParentResonancePDGCode, rhs.theParentResonancePDGCode);
std::swap(theParentResonanceID, rhs.theParentResonanceID);
#endif
std::swap(theHelicity, rhs.theHelicity);
std::swap(emissionTime, rhs.emissionTime);
std::swap(outOfWell, rhs.outOfWell);
std::swap(theSrcPartner, rhs.theSrcPartner);
std::swap(theMass, rhs.theMass);
std::swap(rpCorrelated, rhs.rpCorrelated);
std::swap(uncorrelatedMomentum, rhs.uncorrelatedMomentum);
std::swap(theParticleBias, rhs.theParticleBias);
std::swap(theBiasCollisionVector, rhs.theBiasCollisionVector);
}
public:
/** \brief Assignment operator
*
* Does not copy the particle ID.
*/
Particle &operator=(const Particle &rhs) {
Particle temporaryParticle(rhs);
swap(temporaryParticle);
return *this;
}
/**
* Get the particle type.
* @see G4INCL::ParticleType
*/
G4INCL::ParticleType getType() const {
return theType;
};
/// \brief Get the particle species
virtual G4INCL::ParticleSpecies getSpecies() const {
return ParticleSpecies(theType);
};
void setType(ParticleType t) {
theType = t;
switch(theType)
{
case DeltaPlusPlus:
theA = 1;
theZ = 2;
theS = 0;
break;
case Proton:
case DeltaPlus:
theA = 1;
theZ = 1;
theS = 0;
break;
case Neutron:
case DeltaZero:
theA = 1;
theZ = 0;
theS = 0;
break;
case DeltaMinus:
theA = 1;
theZ = -1;
theS = 0;
break;
case PiPlus:
theA = 0;
theZ = 1;
theS = 0;
break;
case PiZero:
case Eta:
case Omega:
case EtaPrime:
case Photon:
theA = 0;
theZ = 0;
theS = 0;
break;
case PiMinus:
theA = 0;
theZ = -1;
theS = 0;
break;
case Lambda:
theA = 1;
theZ = 0;
theS = -1;
break;
case SigmaPlus:
theA = 1;
theZ = 1;
theS = -1;
break;
case SigmaZero:
theA = 1;
theZ = 0;
theS = -1;
break;
case SigmaMinus:
theA = 1;
theZ = -1;
theS = -1;
break;
case antiProton:
theA = -1;
theZ = -1;
theS = 0;
break;
case XiMinus:
theA = 1;
theZ = -1;
theS = -2;
break;
case XiZero:
theA = 1;
theZ = 0;
theS = -2;
break;
case antiNeutron:
theA = -1;
theZ = 0;
theS = 0;
break;
case antiLambda:
theA = -1;
theZ = 0;
theS = 1;
break;
case antiSigmaMinus:
theA = -1;
theZ = 1;
theS = 1;
break;
case antiSigmaPlus:
theA = -1;
theZ = -1;
theS = 1;
break;
case antiSigmaZero:
theA = -1;
theZ = 0;
theS = 1;
break;
case antiXiMinus:
theA = -1;
theZ = 1;
theS = 2;
break;
case antiXiZero:
theA = -1;
theZ = 0;
theS = 2;
break;
case KPlus:
theA = 0;
theZ = 1;
theS = 1;
break;
case KZero:
theA = 0;
theZ = 0;
theS = 1;
break;
case KZeroBar:
theA = 0;
theZ = 0;
theS = -1;
break;
case KShort:
theA = 0;
theZ = 0;
// theS should not be defined
break;
case KLong:
theA = 0;
theZ = 0;
// theS should not be defined
break;
case KMinus:
theA = 0;
theZ = -1;
theS = -1;
break;
case Composite:
// INCL_ERROR("Trying to set particle type to Composite! Construct a Cluster object instead" << '\n');
theA = 0;
theZ = 0;
theS = 0;
break;
case antiComposite:
theA = 0;
theZ = 0;
theS = 0;
break;
case UnknownParticle:
theA = 0;
theZ = 0;
theS = 0;
INCL_ERROR("Trying to set particle type to Unknown!" << '\n');
break;
}
if( !isResonance() && t!=Composite && t!=antiComposite )
setINCLMass();
}
/**
* Is this a nucleon?
*/
G4bool isNucleon() const {
if(theType == G4INCL::Proton || theType == G4INCL::Neutron)
return true;
else
return false;
};
ParticipantType getParticipantType() const {
return theParticipantType;
}
void setParticipantType(ParticipantType const p) {
theParticipantType = p;
}
G4bool isParticipant() const {
return (theParticipantType==Participant);
}
G4bool isTargetSpectator() const {
return (theParticipantType==TargetSpectator);
}
G4bool isProjectileSpectator() const {
return (theParticipantType==ProjectileSpectator);
}
virtual void makeParticipant() {
theParticipantType = Participant;
}
virtual void makeTargetSpectator() {
theParticipantType = TargetSpectator;
}
virtual void makeProjectileSpectator() {
theParticipantType = ProjectileSpectator;
}
/** \brief Is this a pion? */
G4bool isPion() const { return (theType == PiPlus || theType == PiZero || theType == PiMinus); }
/** \brief Is this an eta? */
G4bool isEta() const { return (theType == Eta); }
/** \brief Is this an omega? */
G4bool isOmega() const { return (theType == Omega); }
/** \brief Is this an etaprime? */
G4bool isEtaPrime() const { return (theType == EtaPrime); }
/** \brief Is this a photon? */
G4bool isPhoton() const { return (theType == Photon); }
/** \brief Is it a resonance? */
inline G4bool isResonance() const { return isDelta(); }
/** \brief Is it a Delta? */
inline G4bool isDelta() const {
return (theType==DeltaPlusPlus || theType==DeltaPlus ||
theType==DeltaZero || theType==DeltaMinus); }
/** \brief Is this a Sigma? */
G4bool isSigma() const { return (theType == SigmaPlus || theType == SigmaZero || theType == SigmaMinus); }
/** \brief Is this a Kaon? */
G4bool isKaon() const { return (theType == KPlus || theType == KZero); }
/** \brief Is this an antiKaon? */
G4bool isAntiKaon() const { return (theType == KZeroBar || theType == KMinus); }
/** \brief Is this a Lambda? */
G4bool isLambda() const { return (theType == Lambda); }
/** \brief Is this a Nucleon or a Lambda? */
G4bool isNucleonorLambda() const { return (isNucleon() || isLambda()); }
/** \brief Is this an Hyperon? */
G4bool isHyperon() const { return (isLambda() || isSigma() ); } //|| isXi()
/** \brief Is this a Meson? */
G4bool isMeson() const { return (isPion() || isKaon() || isAntiKaon() || isEta() || isEtaPrime() || isOmega()); }
/** \brief Is this a Baryon? */
G4bool isBaryon() const { return (isNucleon() || isResonance() || isHyperon()); }
/** \brief Is this a Strange? */
G4bool isStrange() const { return (isKaon() || isAntiKaon() || isHyperon()); }
/** \brief Is this a Xi? */
G4bool isXi() const { return (theType == XiZero || theType == XiMinus); }
/** \brief Is this an antinucleon? */
G4bool isAntiNucleon() const { return (theType == antiProton || theType == antiNeutron); }
/** \brief Is this an antiSigma? */
G4bool isAntiSigma() const { return (theType == antiSigmaPlus || theType == antiSigmaZero || theType == antiSigmaMinus); }
/** \brief Is this an antiXi? */
G4bool isAntiXi() const { return (theType == antiXiZero || theType == antiXiMinus); }
/** \brief Is this an antiLambda? */
G4bool isAntiLambda() const { return (theType == antiLambda); }
/** \brief Is this an antiHyperon? */
G4bool isAntiHyperon() const { return (isAntiLambda() || isAntiSigma() || isAntiXi()); }
/** \brief Is this an antiBaryon? */
G4bool isAntiBaryon() const { return (isAntiNucleon() || isAntiHyperon()); }
/** \brief Is this an antiNucleon or an antiLambda? */
G4bool isAntiNucleonorAntiLambda() const { return (isAntiNucleon() || isAntiLambda()); }
/** \brief Returns the baryon number. */
G4int getA() const { return theA; }
/** \brief Returns the charge number. */
G4int getZ() const { return theZ; }
/** \brief Returns the strangeness number. */
G4int getS() const { return theS; }
/** \brief Returns the strangeness number. */
G4int getSrcPair() const { return nSrcPair; }
G4double getBeta() const {
const G4double P = theMomentum.mag();
return P/theEnergy;
}
/**
* Returns a three vector we can give to the boost() -method.
*
* In order to go to the particle rest frame you need to multiply
* the boost vector by -1.0.
*/
ThreeVector boostVector() const {
return theMomentum / theEnergy;
}
/**
* Boost the particle using a boost vector.
*
* Example (go to the particle rest frame):
* particle->boost(particle->boostVector());
*/
void boost(const ThreeVector &aBoostVector) {
const G4double beta2 = aBoostVector.mag2();
const G4double gamma = 1.0 / std::sqrt(1.0 - beta2);
const G4double bp = theMomentum.dot(aBoostVector);
const G4double alpha = (gamma*gamma)/(1.0 + gamma);
theMomentum = theMomentum + aBoostVector * (alpha * bp - gamma * theEnergy);
theEnergy = gamma * (theEnergy - bp);
}
/** \brief Lorentz-contract the particle position around some center
*
* Apply Lorentz contraction to the position component along the
* direction of the boost vector.
*
* \param aBoostVector the boost vector (velocity) [c]
* \param refPos the reference position
*/
void lorentzContract(const ThreeVector &aBoostVector, const ThreeVector &refPos) {
const G4double beta2 = aBoostVector.mag2();
const G4double gamma = 1.0 / std::sqrt(1.0 - beta2);
const ThreeVector theRelativePosition = thePosition - refPos;
const ThreeVector transversePosition = theRelativePosition - aBoostVector * (theRelativePosition.dot(aBoostVector) / aBoostVector.mag2());
const ThreeVector longitudinalPosition = theRelativePosition - transversePosition;
thePosition = refPos + transversePosition + longitudinalPosition / gamma;
}
/** \brief Get the cached particle mass. */
inline G4double getMass() const { return theMass; }
/** \brief Get the INCL particle mass. */
inline G4double getINCLMass() const {
switch(theType) {
case Proton:
case Neutron:
case PiPlus:
case PiMinus:
case PiZero:
case Lambda:
case SigmaPlus:
case SigmaZero:
case SigmaMinus:
case antiProton:
case XiZero:
case XiMinus:
case antiNeutron:
case antiLambda:
case antiSigmaPlus:
case antiSigmaZero:
case antiSigmaMinus:
case antiXiZero:
case antiXiMinus:
case KPlus:
case KZero:
case KZeroBar:
case KShort:
case KLong:
case KMinus:
case Eta:
case Omega:
case EtaPrime:
case Photon:
return ParticleTable::getINCLMass(theType);
break;
case DeltaPlusPlus:
case DeltaPlus:
case DeltaZero:
case DeltaMinus:
return theMass;
break;
case Composite:
return ParticleTable::getINCLMass(theA,theZ,theS);
break;
case antiComposite:
return ParticleTable::getINCLMass(-theA,-theZ,theS);
break;
default:
INCL_ERROR("Particle::getINCLMass: Unknown particle type." << '\n');
return 0.0;
break;
}
}
/** \brief Get the tabulated particle mass. */
inline virtual G4double getTableMass() const {
switch(theType) {
case Proton:
case Neutron:
case PiPlus:
case PiMinus:
case PiZero:
case Lambda:
case SigmaPlus:
case SigmaZero:
case SigmaMinus:
case antiProton:
case XiZero:
case XiMinus:
case antiNeutron:
case antiLambda:
case antiSigmaPlus:
case antiSigmaZero:
case antiSigmaMinus:
case antiXiZero:
case antiXiMinus:
case KPlus:
case KZero:
case KZeroBar:
case KShort:
case KLong:
case KMinus:
case Eta:
case Omega:
case EtaPrime:
case Photon:
return ParticleTable::getTableParticleMass(theType);
break;
case DeltaPlusPlus:
case DeltaPlus:
case DeltaZero:
case DeltaMinus:
return theMass;
break;
case Composite:
return ParticleTable::getTableMass(theA,theZ,theS);
break;
case antiComposite:
return ParticleTable::getTableMass(-theA,-theZ,theS);
break;
default:
INCL_ERROR("Particle::getTableMass: Unknown particle type." << '\n');
return 0.0;
break;
}
}
/** \brief Get the real particle mass. */
inline G4double getRealMass() const {
switch(theType) {
case Proton:
case Neutron:
case PiPlus:
case PiMinus:
case PiZero:
case Lambda:
case SigmaPlus:
case SigmaZero:
case SigmaMinus:
case antiProton:
case XiZero:
case XiMinus:
case antiNeutron:
case antiLambda:
case antiSigmaPlus:
case antiSigmaZero:
case antiSigmaMinus:
case antiXiZero:
case antiXiMinus:
case KPlus:
case KZero:
case KZeroBar:
case KShort:
case KLong:
case KMinus:
case Eta:
case Omega:
case EtaPrime:
case Photon:
return ParticleTable::getRealMass(theType);
break;
case DeltaPlusPlus:
case DeltaPlus:
case DeltaZero:
case DeltaMinus:
return theMass;
break;
case Composite:
return ParticleTable::getRealMass(theA,theZ,theS);
break;
case antiComposite:
return ParticleTable::getRealMass(-theA,-theZ,theS);
break;
default:
INCL_ERROR("Particle::getRealMass: Unknown particle type." << '\n');
return 0.0;
break;
}
}
/// \brief Set the mass of the Particle to its real mass
void setRealMass() { setMass(getRealMass()); }
/// \brief Set the mass of the Particle to its table mass
void setTableMass() { setMass(getTableMass()); }
/// \brief Set the mass of the Particle to its table mass
void setINCLMass() { setMass(getINCLMass()); }
/**\brief Computes correction on the emission Q-value
*
* Computes the correction that must be applied to INCL particles in
* order to obtain the correct Q-value for particle emission from a given
* nucleus. For absorption, the correction is obviously equal to minus
* the value returned by this function.
*
* \param AParent the mass number of the emitting nucleus
* \param ZParent the charge number of the emitting nucleus
* \return the correction
*/
G4double getEmissionQValueCorrection(const G4int AParent, const G4int ZParent) const {
const G4int SParent = 0;
const G4int ADaughter = AParent - theA;
const G4int ZDaughter = ZParent - theZ;
const G4int SDaughter = 0;
// Note the minus sign here
G4double theQValue;
if(isCluster())
theQValue = -ParticleTable::getTableQValue(theA, theZ, theS, ADaughter, ZDaughter, SDaughter);
else {
const G4double massTableParent = ParticleTable::getTableMass(AParent,ZParent,SParent);
const G4double massTableDaughter = ParticleTable::getTableMass(ADaughter,ZDaughter,SDaughter);
const G4double massTableParticle = getTableMass();
theQValue = massTableParent - massTableDaughter - massTableParticle;
}
const G4double massINCLParent = ParticleTable::getINCLMass(AParent,ZParent,SParent);
const G4double massINCLDaughter = ParticleTable::getINCLMass(ADaughter,ZDaughter,SDaughter);
const G4double massINCLParticle = getINCLMass();
// The rhs corresponds to the INCL Q-value
return theQValue - (massINCLParent-massINCLDaughter-massINCLParticle);
}
/**\brief Computes correction on the transfer Q-value
*
* Computes the correction that must be applied to INCL particles in
* order to obtain the correct Q-value for particle transfer from a given
* nucleus to another.
*
* Assumes that the receving nucleus is INCL's target nucleus, with the
* INCL separation energy.
*
* \param AFrom the mass number of the donating nucleus
* \param ZFrom the charge number of the donating nucleus
* \param ATo the mass number of the receiving nucleus
* \param ZTo the charge number of the receiving nucleus
* \return the correction
*/
G4double getTransferQValueCorrection(const G4int AFrom, const G4int ZFrom, const G4int ATo, const G4int ZTo) const {
const G4int SFrom = 0;
const G4int STo = 0;
const G4int AFromDaughter = AFrom - theA;
const G4int ZFromDaughter = ZFrom - theZ;
const G4int SFromDaughter = 0;
const G4int AToDaughter = ATo + theA;
const G4int ZToDaughter = ZTo + theZ;
const G4int SToDaughter = 0;
const G4double theQValue = ParticleTable::getTableQValue(AToDaughter,ZToDaughter,SToDaughter,AFromDaughter,ZFromDaughter,SFromDaughter,AFrom,ZFrom,SFrom);
const G4double massINCLTo = ParticleTable::getINCLMass(ATo,ZTo,STo);
const G4double massINCLToDaughter = ParticleTable::getINCLMass(AToDaughter,ZToDaughter,SToDaughter);
/* Note that here we have to use the table mass in the INCL Q-value. We
* cannot use theMass, because at this stage the particle is probably
* still off-shell; and we cannot use getINCLMass(), because it leads to
* violations of global energy conservation.
*/
const G4double massINCLParticle = getTableMass();
// The rhs corresponds to the INCL Q-value for particle absorption
return theQValue - (massINCLToDaughter-massINCLTo-massINCLParticle);
}
/**\brief Computes correction on the emission Q-value for hypernuclei
*
* Computes the correction that must be applied to INCL particles in
* order to obtain the correct Q-value for particle emission from a given
* nucleus. For absorption, the correction is obviously equal to minus
* the value returned by this function.
*
* \param AParent the mass number of the emitting nucleus
* \param ZParent the charge number of the emitting nucleus
* \param SParent the strangess number of the emitting nucleus
* \return the correction
*/
G4double getEmissionQValueCorrection(const G4int AParent, const G4int ZParent, const G4int SParent) const {
const G4int ADaughter = AParent - theA;
const G4int ZDaughter = ZParent - theZ;
const G4int SDaughter = SParent - theS;
// Note the minus sign here
G4double theQValue;
if(isCluster())
theQValue = -ParticleTable::getTableQValue(theA, theZ, theS, ADaughter, ZDaughter, SDaughter);
else {
const G4double massTableParent = ParticleTable::getTableMass(AParent,ZParent,SParent);
const G4double massTableDaughter = ParticleTable::getTableMass(ADaughter,ZDaughter,SDaughter);
const G4double massTableParticle = getTableMass();
theQValue = massTableParent - massTableDaughter - massTableParticle;
}
const G4double massINCLParent = ParticleTable::getINCLMass(AParent,ZParent,SParent);
const G4double massINCLDaughter = ParticleTable::getINCLMass(ADaughter,ZDaughter,SDaughter);
const G4double massINCLParticle = getINCLMass();
// The rhs corresponds to the INCL Q-value
return theQValue - (massINCLParent-massINCLDaughter-massINCLParticle);
}
/**\brief Computes correction on the transfer Q-value for hypernuclei
*
* Computes the correction that must be applied to INCL particles in
* order to obtain the correct Q-value for particle transfer from a given
* nucleus to another.
*
* Assumes that the receving nucleus is INCL's target nucleus, with the
* INCL separation energy.
*
* \param AFrom the mass number of the donating nucleus
* \param ZFrom the charge number of the donating nucleus
* \param SFrom the strangess number of the donating nucleus
* \param ATo the mass number of the receiving nucleus
* \param ZTo the charge number of the receiving nucleus
* \param STo the strangess number of the receiving nucleus
* \return the correction
*/
G4double getTransferQValueCorrection(const G4int AFrom, const G4int ZFrom, const G4int SFrom, const G4int ATo, const G4int ZTo , const G4int STo) const {
const G4int AFromDaughter = AFrom - theA;
const G4int ZFromDaughter = ZFrom - theZ;
const G4int SFromDaughter = SFrom - theS;
const G4int AToDaughter = ATo + theA;
const G4int ZToDaughter = ZTo + theZ;
const G4int SToDaughter = STo + theS;
const G4double theQValue = ParticleTable::getTableQValue(AToDaughter,ZToDaughter,SFromDaughter,AFromDaughter,ZFromDaughter,SToDaughter,AFrom,ZFrom,SFrom);
const G4double massINCLTo = ParticleTable::getINCLMass(ATo,ZTo,STo);
const G4double massINCLToDaughter = ParticleTable::getINCLMass(AToDaughter,ZToDaughter,SToDaughter);
/* Note that here we have to use the table mass in the INCL Q-value. We
* cannot use theMass, because at this stage the particle is probably
* still off-shell; and we cannot use getINCLMass(), because it leads to
* violations of global energy conservation.
*/
const G4double massINCLParticle = getTableMass();
// The rhs corresponds to the INCL Q-value for particle absorption
return theQValue - (massINCLToDaughter-massINCLTo-massINCLParticle);
}
/** \brief Get the the particle invariant mass.
*
* Uses the relativistic invariant
* \f[ m = \sqrt{E^2 - {\vec p}^2}\f]
**/
G4double getInvariantMass() const {
const G4double mass = std::pow(theEnergy, 2) - theMomentum.dot(theMomentum);
if(mass < 0.0) {
INCL_ERROR("E*E - p*p is negative." << '\n');
return 0.0;
} else {
return std::sqrt(mass);
}
};
/// \brief Get the particle kinetic energy.
inline G4double getKineticEnergy() const { return theEnergy - theMass; }
/// \brief Get the particle potential energy.
inline G4double getPotentialEnergy() const { return thePotentialEnergy; }
/// \brief Set the particle potential energy.
inline void setPotentialEnergy(G4double v) { thePotentialEnergy = v; }
/**
* Get the energy of the particle in MeV.
*/
G4double getEnergy() const
{
return theEnergy;
};
/**
* Set the mass of the particle in MeV/c^2.
*/
void setMass(G4double mass)
{
this->theMass = mass;
}
/**
* Set the energy of the particle in MeV.
*/
void setEnergy(G4double energy)
{
this->theEnergy = energy;
};
/**
* Get the momentum vector.
*/
const G4INCL::ThreeVector &getMomentum() const
{
return theMomentum;
};
/** Get the angular momentum w.r.t. the origin */
virtual G4INCL::ThreeVector getAngularMomentum() const
{
return thePosition.vector(theMomentum);
};
/**
* Set the momentum vector.
*/
virtual void setMomentum(const G4INCL::ThreeVector &momentum)
{
this->theMomentum = momentum;
};
/**
* Set the position vector.
*/
const G4INCL::ThreeVector &getPosition() const
{
return thePosition;
};
virtual void setPosition(const G4INCL::ThreeVector &position)
{
this->thePosition = position;
};
G4double getHelicity() { return theHelicity; };
void setHelicity(G4double h) { theHelicity = h; };
void propagate(G4double step) {
thePosition += ((*thePropagationMomentum)*(step/(*thePropagationEnergy)));
};
/** \brief Return the number of collisions undergone by the particle. **/
G4int getNumberOfCollisions() const { return nCollisions; }
/** \brief Set the number of collisions undergone by the particle. **/
void setNumberOfCollisions(G4int n) { nCollisions = n; }
/** \brief Increment the number of collisions undergone by the particle. **/
void incrementNumberOfCollisions() { nCollisions++; }
/** \brief Return the number of decays undergone by the particle. **/
G4int getNumberOfDecays() const { return nDecays; }
/** \brief Set the number of decays undergone by the particle. **/
void setNumberOfDecays(G4int n) { nDecays = n; }
/** \brief Increment the number of decays undergone by the particle. **/
void incrementNumberOfDecays() { nDecays++; }
/** \brief Set the number of srcpairs. **/
void setNumberOfSrcPair(int n) { nSrcPair = n; }
/** \brief Mark the particle as out of its potential well
*
* This flag is used to control pions created outside their potential well
* in delta decay. The pion potential checks it and returns zero if it is
* true (necessary in order to correctly enforce energy conservation). The
* Nucleus::applyFinalState() method uses it to determine whether new
* avatars should be generated for the particle.
*/
void setOutOfWell() { outOfWell = true; }
/// \brief Check if the particle is out of its potential well
G4bool isOutOfWell() const { return outOfWell; }
/// \brief Set and reset src partner
void setSrcPartner() { theSrcPartner = true; }
void resetSrcPartner() { theSrcPartner = false; nSrcPair=0; }
/// \brief Check if the particle is a src partner
G4bool isSrcPartner() const { return theSrcPartner; }
void setEmissionTime(G4double t) { emissionTime = t; }
G4double getEmissionTime() { return emissionTime; };
/** \brief Transverse component of the position w.r.t. the momentum. */
ThreeVector getTransversePosition() const {
return thePosition - getLongitudinalPosition();
}
/** \brief Longitudinal component of the position w.r.t. the momentum. */
ThreeVector getLongitudinalPosition() const {
return *thePropagationMomentum * (thePosition.dot(*thePropagationMomentum)/thePropagationMomentum->mag2());
}
/** \brief Rescale the momentum to match the total energy. */
const ThreeVector &adjustMomentumFromEnergy();
/** \brief Recompute the energy to match the momentum. */
G4double adjustEnergyFromMomentum();
G4bool isCluster() const {
return ((theType == Composite || theType == antiComposite));
}
/// \brief Set the frozen particle momentum
void setFrozenMomentum(const ThreeVector &momentum) { theFrozenMomentum = momentum; }
/// \brief Set the frozen particle momentum
void setFrozenEnergy(const G4double energy) { theFrozenEnergy = energy; }
/// \brief Get the frozen particle momentum
ThreeVector getFrozenMomentum() const { return theFrozenMomentum; }
/// \brief Get the frozen particle momentum
G4double getFrozenEnergy() const { return theFrozenEnergy; }
/// \brief Get the propagation velocity of the particle
ThreeVector getPropagationVelocity() const { return (*thePropagationMomentum)/(*thePropagationEnergy); }
/** \brief Freeze particle propagation
*
* Make the particle use theFrozenMomentum and theFrozenEnergy for
* propagation. The normal state can be restored by calling the
* thawPropagation() method.
*/
void freezePropagation() {
thePropagationMomentum = &theFrozenMomentum;
thePropagationEnergy = &theFrozenEnergy;
}
/** \brief Unfreeze particle propagation
*
* Make the particle use theMomentum and theEnergy for propagation. Call
* this method to restore the normal propagation if the
* freezePropagation() method has been called.
*/
void thawPropagation() {
thePropagationMomentum = &theMomentum;
thePropagationEnergy = &theEnergy;
}
/** \brief Rotate the particle position and momentum
*
* \param angle the rotation angle
* \param axis a unit vector representing the rotation axis
*/
virtual void rotatePositionAndMomentum(const G4double angle, const ThreeVector &axis) {
rotatePosition(angle, axis);
rotateMomentum(angle, axis);
}
/** \brief Rotate the particle position
*
* \param angle the rotation angle
* \param axis a unit vector representing the rotation axis
*/
virtual void rotatePosition(const G4double angle, const ThreeVector &axis) {
thePosition.rotate(angle, axis);
}
/** \brief Rotate the particle momentum
*
* \param angle the rotation angle
* \param axis a unit vector representing the rotation axis
*/
virtual void rotateMomentum(const G4double angle, const ThreeVector &axis) {
theMomentum.rotate(angle, axis);
theFrozenMomentum.rotate(angle, axis);
}
std::string print() const {
std::stringstream ss;
ss << "Particle (ID = " << ID << ") type = ";
ss << ParticleTable::getName(theType);
ss << ", SRC pair = " << nSrcPair;
ss << ", Potential energy = " << thePotentialEnergy;
ss << '\n'
<< " energy = " << theEnergy << '\n'
<< " momentum = "
<< theMomentum.print()
<< '\n'
<< " position = "
<< thePosition.print()
<< '\n';
return ss.str();
};
std::string dump() const {
std::stringstream ss;
ss << "(particle " << ID << " ";
ss << ParticleTable::getName(theType);
ss << nSrcPair << " ";
ss << '\n'
<< thePosition.dump()
<< '\n'
<< theMomentum.dump()
<< '\n'
<< theEnergy << ")" << '\n';
return ss.str();
};
long getID() const { return ID; };
/**
* Return a NULL pointer
*/
ParticleList const *getParticles() const {
INCL_WARN("Particle::getParticles() method was called on a Particle object" << '\n');
return 0;
}
/** \brief Return the reflection momentum
*
* The reflection momentum is used by calls to getSurfaceRadius to compute
* the radius of the sphere where the nucleon moves. It is necessary to
* introduce fuzzy r-p correlations.
*/
G4double getReflectionMomentum() const {
if(rpCorrelated)
return theMomentum.mag();
else
return uncorrelatedMomentum;
}
/// \brief Set the uncorrelated momentum
void setUncorrelatedMomentum(const G4double p) { uncorrelatedMomentum = p; }
/// \brief Make the particle follow a strict r-p correlation
void rpCorrelate() { rpCorrelated = true; }
/// \brief Make the particle not follow a strict r-p correlation
void rpDecorrelate() { rpCorrelated = false; }
/// \brief Get the cosine of the angle between position and momentum
G4double getCosRPAngle() const {
const G4double norm = thePosition.mag2()*thePropagationMomentum->mag2();
if(norm>0.)
return thePosition.dot(*thePropagationMomentum) / std::sqrt(norm);
else
return 1.;
}
/// \brief General bias vector function
static G4double getTotalBias();
static void setINCLBiasVector(std::vector<G4double> NewVector);
static void FillINCLBiasVector(G4double newBias);
static G4double getBiasFromVector(std::vector<G4int> VectorBias);
static std::vector<G4int> MergeVectorBias(Particle const * const p1, Particle const * const p2);
static std::vector<G4int> MergeVectorBias(std::vector<G4int> p1, Particle const * const p2);
/// \brief Get the particle bias.
G4double getParticleBias() const { return theParticleBias; };
/// \brief Set the particle bias.
void setParticleBias(G4double ParticleBias) { this->theParticleBias = ParticleBias; }
/// \brief Get the vector list of biased vertices on the particle path.
std::vector<G4int> getBiasCollisionVector() const { return theBiasCollisionVector; }
/// \brief Set the vector list of biased vertices on the particle path.
void setBiasCollisionVector(std::vector<G4int> BiasCollisionVector) {
this->theBiasCollisionVector = BiasCollisionVector;
this->setParticleBias(Particle::getBiasFromVector(std::move(BiasCollisionVector)));
}
/** \brief Number of Kaon inside de nucleus
*
* Put in the Particle class in order to calculate the
* "correct" mass of composit particle.
*
*/
G4int getNumberOfKaon() const { return theNKaon; };
void setNumberOfKaon(const G4int NK) { theNKaon = NK; }
#ifdef INCLXX_IN_GEANT4_MODE
G4int getParentResonancePDGCode() const { return theParentResonancePDGCode; };
void setParentResonancePDGCode(const G4int parentPDGCode) { theParentResonancePDGCode = parentPDGCode; };
G4int getParentResonanceID() const { return theParentResonanceID; };
void setParentResonanceID(const G4int parentID) { theParentResonanceID = parentID; };
#endif
public:
/** \brief Time ordered vector of all bias applied
*
* /!\ Caution /!\
* methods Assotiated to G4VectorCache<T> are:
* Push_back(…),
* operator[],
* Begin(),
* End(),
* Clear(),
* Size() and
* Pop_back()
*
*/
#ifdef INCLXX_IN_GEANT4_MODE
static std::vector<G4double> INCLBiasVector;
//static G4VectorCache<G4double> INCLBiasVector;
#else
static G4ThreadLocal std::vector<G4double> INCLBiasVector;
//static G4VectorCache<G4double> INCLBiasVector;
#endif
static G4ThreadLocal G4int nextBiasedCollisionID;
protected:
G4int theZ, theA, theS;
ParticipantType theParticipantType;
G4INCL::ParticleType theType;
G4double theEnergy;
G4double *thePropagationEnergy;
G4double theFrozenEnergy;
G4INCL::ThreeVector theMomentum;
G4INCL::ThreeVector *thePropagationMomentum;
G4INCL::ThreeVector theFrozenMomentum;
G4INCL::ThreeVector thePosition;
G4int nCollisions;
G4int nDecays;
G4int nSrcPair;
G4double thePotentialEnergy;
long ID;
G4bool rpCorrelated;
G4double uncorrelatedMomentum;
G4double theParticleBias;
/// \brief The number of Kaons inside the nucleus (update during the cascade)
G4int theNKaon;
#ifdef INCLXX_IN_GEANT4_MODE
G4int theParentResonancePDGCode;
G4int theParentResonanceID;
#endif
private:
G4double theHelicity;
G4double emissionTime;
G4bool outOfWell;
G4bool theSrcPartner;
/// \brief Time ordered vector of all biased vertices on the particle path
std::vector<G4int> theBiasCollisionVector;
G4double theMass;
static G4ThreadLocal long nextID;
INCL_DECLARE_ALLOCATION_POOL(Particle)
};
}
#endif /* PARTICLE_HH_ */