Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-30 08:56:53

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 // INCL++ intra-nuclear cascade model
0027 // Alain Boudard, CEA-Saclay, France
0028 // Joseph Cugnon, University of Liege, Belgium
0029 // Jean-Christophe David, CEA-Saclay, France
0030 // Pekka Kaitaniemi, CEA-Saclay, France, and Helsinki Institute of Physics, Finland
0031 // Sylvie Leray, CEA-Saclay, France
0032 // Davide Mancusi, CEA-Saclay, France
0033 //
0034 #define INCLXX_IN_GEANT4_MODE 1
0035 
0036 #include "globals.hh"
0037 
0038 #ifndef G4INCLCluster_hh
0039 #define G4INCLCluster_hh 1
0040 
0041 #include "G4INCLParticle.hh"
0042 #include "G4INCLNuclearDensityFactory.hh"
0043 #include "G4INCLParticleSampler.hh"
0044 #include "G4INCLAllocationPool.hh"
0045 
0046 namespace G4INCL {
0047 
0048   /**
0049    * Cluster is a particle (inherits from the Particle class) that is
0050    * actually a collection of elementary particles.
0051    */
0052   class Cluster : public Particle {
0053   public:
0054 
0055     /** \brief Standard Cluster constructor
0056      *
0057      * This constructor should mainly be used when constructing Nucleus or
0058      * when constructing Clusters to be used as composite projectiles.
0059      */
0060     Cluster(const G4int Z, const G4int A, const G4int S, const G4bool createParticleSampler=true) :
0061       Particle(),
0062       theExcitationEnergy(0.),
0063       theSpin(0.,0.,0.),
0064       theParticleSampler(NULL)
0065     {
0066       if(A >= 0){
0067       setType(Composite);
0068       theZ = Z;
0069       theA = A;
0070       theS = S;
0071       setINCLMass();
0072       if(createParticleSampler)
0073         theParticleSampler = new ParticleSampler(A,Z,S);
0074     }
0075       else {
0076         setType(antiComposite);
0077         theZ = Z;
0078         theA = A;
0079         theS = S;
0080         setINCLMass();
0081         if(createParticleSampler)
0082           theParticleSampler = new ParticleSampler(A,Z,S);
0083       }
0084     }
0085 
0086     /**
0087      * A cluster can be directly built from a list of particles.
0088      */
0089     template<class Iterator>
0090       Cluster(Iterator begin, Iterator end) :
0091         Particle(),
0092         theExcitationEnergy(0.),
0093         theSpin(0.,0.,0.),
0094         theParticleSampler(NULL)
0095     {
0096       setType(Composite);
0097       for(Iterator i = begin; i != end; ++i) {
0098         addParticle(*i);
0099       }
0100       if (theA < 0){
0101         setType(antiComposite);
0102         thePosition /= (-theA);
0103       }
0104       else 
0105       thePosition /= theA;
0106       setINCLMass();
0107       adjustMomentumFromEnergy();
0108     }
0109 
0110     virtual ~Cluster() {
0111       delete theParticleSampler;
0112     }
0113 
0114     /// \brief Copy constructor
0115     Cluster(const Cluster &rhs) :
0116       Particle(rhs),
0117       theExcitationEnergy(rhs.theExcitationEnergy),
0118       theSpin(rhs.theSpin)
0119     {
0120       for(ParticleIter p=rhs.particles.begin(), e=rhs.particles.end(); p!=e; ++p) {
0121         particles.push_back(new Particle(**p));
0122       }
0123       if(rhs.theParticleSampler)
0124         theParticleSampler = new ParticleSampler(rhs.theA,rhs.theZ,rhs.theS);
0125       else
0126         theParticleSampler = NULL;
0127     }
0128 
0129     /// \brief Assignment operator
0130     Cluster &operator=(const Cluster &rhs) {
0131       Cluster temporaryCluster(rhs);
0132       Particle::operator=(temporaryCluster);
0133       swap(temporaryCluster);
0134       return *this;
0135     }
0136 
0137     /// \brief Helper method for the assignment operator
0138     void swap(Cluster &rhs) {
0139       Particle::swap(rhs);
0140       std::swap(theExcitationEnergy, rhs.theExcitationEnergy);
0141       std::swap(theSpin, rhs.theSpin);
0142       // std::swap is overloaded by std::list and guaranteed to operate in
0143       // constant time
0144       std::swap(particles, rhs.particles);
0145       std::swap(theParticleSampler, rhs.theParticleSampler);
0146     }
0147 
0148     ParticleSpecies getSpecies() const {
0149       return ParticleSpecies(theA, theZ, theS);
0150     }
0151 
0152     void deleteParticles() {
0153       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0154         delete (*p);
0155       }
0156       clearParticles();
0157     }
0158 
0159     void clearParticles() { particles.clear(); }
0160 
0161     /// \brief Set the charge number of the cluster
0162     void setZ(const G4int Z) { theZ = Z; }
0163 
0164     /// \brief Set the mass number of the cluster
0165     void setA(const G4int A) { theA = A; }
0166 
0167     /// \brief Set the strangess number of the cluster
0168     void setS(const G4int S) { theS = S; }
0169 
0170     /// \brief Get the excitation energy of the cluster.
0171     G4double getExcitationEnergy() const { return theExcitationEnergy; }
0172 
0173     /// \brief Set the excitation energy of the cluster.
0174     void setExcitationEnergy(const G4double e) { theExcitationEnergy=e; }
0175 
0176     /** \brief Get the real particle mass.
0177      *
0178      * Overloads the Particle method.
0179      */
0180     inline virtual G4double getTableMass() const { return getRealMass(); }
0181 
0182     /**
0183      * Get the list of particles in the cluster.
0184      */
0185     ParticleList const &getParticles() const { return particles; }
0186 
0187     /// \brief Remove a particle from the cluster components.
0188     void removeParticle(Particle * const p) { particles.remove(p); }
0189 
0190     /**
0191      * Add one particle to the cluster. This updates the cluster mass,
0192      * energy, size, etc.
0193      */
0194     void addParticle(Particle * const p) {
0195       particles.push_back(p);
0196       theEnergy += p->getEnergy();
0197       thePotentialEnergy += p->getPotentialEnergy();
0198       theMomentum += p->getMomentum();
0199       thePosition += p->getPosition();
0200       theA += p->getA();
0201       theZ += p->getZ();
0202       theS += p->getS();
0203       nCollisions += p->getNumberOfCollisions();
0204     }
0205 
0206     /// \brief Set total cluster mass, energy, size, etc. from the particles
0207     void updateClusterParameters() {
0208       theEnergy = 0.;
0209       thePotentialEnergy = 0.;
0210       theMomentum = ThreeVector();
0211       thePosition = ThreeVector();
0212       theA = 0;
0213       theZ = 0;
0214       theS = 0;
0215       nCollisions = 0;
0216       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0217         theEnergy += (*p)->getEnergy();
0218         thePotentialEnergy += (*p)->getPotentialEnergy();
0219         theMomentum += (*p)->getMomentum();
0220         thePosition += (*p)->getPosition();
0221         theA += (*p)->getA();
0222         theZ += (*p)->getZ();
0223         theS += (*p)->getS();
0224         nCollisions += (*p)->getNumberOfCollisions();
0225       }
0226     }
0227 
0228     /// \brief Add a list of particles to the cluster
0229     void addParticles(ParticleList const &pL) {
0230       particles = pL;
0231       updateClusterParameters();
0232     }
0233 
0234     /// \brief Returns the list of particles that make up the cluster
0235     ParticleList getParticleList() const { return particles; }
0236 
0237     std::string print() const {
0238       std::stringstream ss;
0239       ss << "Cluster (ID = " << ID << ") type = ";
0240       ss << ParticleTable::getName(theType);
0241       ss << '\n'
0242         << "   A = " << theA << '\n'
0243         << "   Z = " << theZ << '\n'
0244         << "   S = " << theS << '\n'
0245         << "   mass = " << getMass() << '\n'
0246         << "   energy = " << theEnergy << '\n'
0247         << "   momentum = "
0248         << theMomentum.print()
0249         << '\n'
0250         << "   position = "
0251         << thePosition.print()
0252         << '\n'
0253         << "Contains the following particles:"
0254         << '\n';
0255       for(ParticleIter i=particles.begin(), e=particles.end(); i!=e; ++i)
0256         ss << (*i)->print();
0257       ss << '\n';
0258       return ss.str();
0259     }
0260 
0261     /// \brief Initialise the NuclearDensity pointer and sample the particles
0262     virtual void initializeParticles();
0263 
0264     /** \brief Boost to the CM of the component particles
0265      *
0266      * The position of all particles in the particles list is shifted so that
0267      * their centre of mass is in the origin and their total momentum is
0268      * zero.
0269      */
0270     void internalBoostToCM() {
0271 
0272       // First compute the current CM position and total momentum
0273       ThreeVector theCMPosition, theTotalMomentum;
0274       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0275         theCMPosition += (*p)->getPosition();
0276         theTotalMomentum += (*p)->getMomentum();
0277         //theTotalEnergy += (*p)->getEnergy();
0278       }
0279       if(theA>=0){
0280       theCMPosition /= theA;
0281 // assert((unsigned int)theA==particles.size());
0282       } else if (theA < 0){
0283         theCMPosition /= -theA;
0284 //assert(-theA==particles.size());
0285       }
0286 
0287       // Now determine the CM velocity of the particles
0288       // commented out because currently unused, see below
0289       // ThreeVector betaCM = theTotalMomentum / theTotalEnergy;
0290 
0291       // The new particle positions and momenta are scaled by a factor of
0292       // \f$\sqrt{A/(A-1)}\f$, so that the resulting density distributions in
0293       // the CM have the same variance as the one we started with.
0294       G4double rescaling;
0295       if (theA>0)
0296         rescaling = std::sqrt(((G4double)theA)/((G4double)(theA-1)));
0297       else if (theA<0)
0298         rescaling = std::sqrt(((G4double)(-theA))/((G4double)((-theA)-1)));
0299       else 
0300         rescaling = 0 ;
0301 
0302       // Loop again to boost and reposition
0303       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0304         // \bug{We should do the following, but the Fortran version actually
0305         // does not!
0306         // (*p)->boost(betaCM);
0307         // Here is what the Fortran version does:}
0308         if (theA>0)
0309          (*p)->setMomentum(((*p)->getMomentum()-theTotalMomentum/theA)*rescaling);
0310         else if (theA<0)
0311          (*p)->setMomentum(((*p)->getMomentum()-theTotalMomentum/(-theA))*rescaling);
0312 
0313         // Set the CM position of the particles
0314         (*p)->setPosition(((*p)->getPosition()-theCMPosition)*rescaling);
0315       }
0316 
0317       // Set the global cluster kinematic variables
0318       thePosition.setX(0.0);
0319       thePosition.setY(0.0);
0320       thePosition.setZ(0.0);
0321       theMomentum.setX(0.0);
0322       theMomentum.setY(0.0);
0323       theMomentum.setZ(0.0);
0324       theEnergy = getMass();
0325 
0326       INCL_DEBUG("Cluster boosted to internal CM:" << '\n' << print());
0327 
0328     }
0329 
0330     /** \brief Put the cluster components off shell
0331      *
0332      * The Cluster components are put off shell in such a way that their total
0333      * energy equals the cluster mass.
0334      */
0335     void putParticlesOffShell() {
0336       // Compute the dynamical potential
0337       const G4double theDynamicalPotential = computeDynamicalPotential();
0338       INCL_DEBUG("The dynamical potential is " << theDynamicalPotential << " MeV" << '\n');
0339 
0340       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0341         const G4double energy = (*p)->getEnergy() - theDynamicalPotential;
0342         const ThreeVector &momentum = (*p)->getMomentum();
0343         // Here particles are put off-shell so that we can satisfy the energy-
0344         // and momentum-conservation laws
0345         (*p)->setEnergy(energy);
0346         (*p)->setMass(std::sqrt(energy*energy - momentum.mag2()));
0347       }
0348       INCL_DEBUG("Cluster components are now off shell:" << '\n'
0349             << print());
0350     }
0351 
0352     /** \brief Set the position of the cluster
0353      *
0354      * This overloads the Particle method to take into account that the
0355      * positions of the cluster members must be updated as well.
0356      */
0357     void setPosition(const ThreeVector &position) {
0358       ThreeVector shift(position-thePosition);
0359       Particle::setPosition(position);
0360       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0361         (*p)->setPosition((*p)->getPosition()+shift);
0362       }
0363     }
0364 
0365     /** \brief Boost the cluster with the indicated velocity
0366      *
0367      * The Cluster is boosted as a whole, just like any Particle object;
0368      * moreover, the internal components (particles list) are also boosted,
0369      * according to Alain Boudard's off-shell recipe.
0370      *
0371      * \param aBoostVector the velocity to boost to [c]
0372      */
0373     void boost(const ThreeVector &aBoostVector) {
0374       Particle::boost(aBoostVector);
0375       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0376         (*p)->boost(aBoostVector);
0377         // Apply Lorentz contraction to the particle position
0378         (*p)->lorentzContract(aBoostVector,thePosition);
0379         (*p)->rpCorrelate();
0380       }
0381 
0382       INCL_DEBUG("Cluster was boosted with (bx,by,bz)=("
0383           << aBoostVector.getX() << ", " << aBoostVector.getY() << ", " << aBoostVector.getZ() << "):"
0384           << '\n' << print());
0385 
0386     }
0387 
0388     /** \brief Freeze the internal motion of the particles
0389      *
0390      * Each particle is assigned a frozen momentum four-vector determined by
0391      * the collective cluster velocity. This is used for propagation, but not
0392      * for dynamics. Normal propagation is restored by calling the
0393      * Particle::thawPropagation() method, which should be done in
0394      * InteractionAvatar::postInteraction.
0395      */
0396     void freezeInternalMotion() {
0397       const ThreeVector &normMomentum = theMomentum / getMass();
0398       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0399         const G4double pMass = (*p)->getMass();
0400         const ThreeVector frozenMomentum = normMomentum * pMass;
0401         const G4double frozenEnergy = std::sqrt(frozenMomentum.mag2()+pMass*pMass);
0402         (*p)->setFrozenMomentum(frozenMomentum);
0403         (*p)->setFrozenEnergy(frozenEnergy);
0404         (*p)->freezePropagation();
0405       }
0406     }
0407 
0408     /** \brief Rotate position of all the particles
0409      *
0410      * This includes the cluster components. Overloads Particle::rotateMomentum().
0411      *
0412      * \param angle the rotation angle
0413      * \param axis a unit vector representing the rotation axis
0414      */
0415     virtual void rotatePosition(const G4double angle, const ThreeVector &axis);
0416 
0417     /** \brief Rotate momentum of all the particles
0418      *
0419      * This includes the cluster components. Overloads Particle::rotateMomentum().
0420      *
0421      * \param angle the rotation angle
0422      * \param axis a unit vector representing the rotation axis
0423      */
0424     virtual void rotateMomentum(const G4double angle, const ThreeVector &axis);
0425 
0426     /// \brief Make all the components projectile spectators, too
0427     virtual void makeProjectileSpectator() {
0428       Particle::makeProjectileSpectator();
0429       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0430         (*p)->makeProjectileSpectator();
0431       }
0432     }
0433 
0434     /// \brief Make all the components target spectators, too
0435     virtual void makeTargetSpectator() {
0436       Particle::makeTargetSpectator();
0437       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0438         (*p)->makeTargetSpectator();
0439       }
0440     }
0441 
0442     /// \brief Make all the components participants, too
0443     virtual void makeParticipant() {
0444       Particle::makeParticipant();
0445       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0446         (*p)->makeParticipant();
0447       }
0448     }
0449 
0450     /// \brief Get the spin of the nucleus.
0451     ThreeVector const &getSpin() const { return theSpin; }
0452 
0453     /// \brief Set the spin of the nucleus.
0454     void setSpin(const ThreeVector &j) { theSpin = j; }
0455 
0456     /// \brief Get the total angular momentum (orbital + spin)
0457     G4INCL::ThreeVector getAngularMomentum() const {
0458       return Particle::getAngularMomentum() + getSpin();
0459     }
0460 
0461   private:
0462     /** \brief Compute the dynamical cluster potential
0463      *
0464      * Alain Boudard's boost prescription for low-energy beams requires to
0465      * define a "dynamical potential" that allows us to conserve momentum and
0466      * energy when boosting the projectile cluster.
0467      */
0468     G4double computeDynamicalPotential() {
0469       G4double theDynamicalPotential = 0.0;
0470       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0471         theDynamicalPotential += (*p)->getEnergy();
0472       }
0473       theDynamicalPotential -= getTableMass();
0474       theDynamicalPotential /= std::abs(theA);
0475 
0476       return theDynamicalPotential;
0477     }
0478 
0479   protected:
0480     ParticleList particles;
0481     G4double theExcitationEnergy;
0482     ThreeVector theSpin;
0483     ParticleSampler *theParticleSampler;
0484 
0485     INCL_DECLARE_ALLOCATION_POOL(Cluster)
0486   };
0487 
0488 }
0489 
0490 #endif