Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:58:25

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       setType(Composite);
0067       theZ = Z;
0068       theA = A;
0069       theS = S;
0070       setINCLMass();
0071       if(createParticleSampler)
0072         theParticleSampler = new ParticleSampler(A,Z,S);
0073     }
0074 
0075     /**
0076      * A cluster can be directly built from a list of particles.
0077      */
0078     template<class Iterator>
0079       Cluster(Iterator begin, Iterator end) :
0080         Particle(),
0081         theExcitationEnergy(0.),
0082         theSpin(0.,0.,0.),
0083         theParticleSampler(NULL)
0084     {
0085       setType(Composite);
0086       for(Iterator i = begin; i != end; ++i) {
0087         addParticle(*i);
0088       }
0089       thePosition /= theA;
0090       setINCLMass();
0091       adjustMomentumFromEnergy();
0092     }
0093 
0094     virtual ~Cluster() {
0095       delete theParticleSampler;
0096     }
0097 
0098     /// \brief Copy constructor
0099     Cluster(const Cluster &rhs) :
0100       Particle(rhs),
0101       theExcitationEnergy(rhs.theExcitationEnergy),
0102       theSpin(rhs.theSpin)
0103     {
0104       for(ParticleIter p=rhs.particles.begin(), e=rhs.particles.end(); p!=e; ++p) {
0105         particles.push_back(new Particle(**p));
0106       }
0107       if(rhs.theParticleSampler)
0108         theParticleSampler = new ParticleSampler(rhs.theA,rhs.theZ,rhs.theS);
0109       else
0110         theParticleSampler = NULL;
0111     }
0112 
0113     /// \brief Assignment operator
0114     Cluster &operator=(const Cluster &rhs) {
0115       Cluster temporaryCluster(rhs);
0116       Particle::operator=(temporaryCluster);
0117       swap(temporaryCluster);
0118       return *this;
0119     }
0120 
0121     /// \brief Helper method for the assignment operator
0122     void swap(Cluster &rhs) {
0123       Particle::swap(rhs);
0124       std::swap(theExcitationEnergy, rhs.theExcitationEnergy);
0125       std::swap(theSpin, rhs.theSpin);
0126       // std::swap is overloaded by std::list and guaranteed to operate in
0127       // constant time
0128       std::swap(particles, rhs.particles);
0129       std::swap(theParticleSampler, rhs.theParticleSampler);
0130     }
0131 
0132     ParticleSpecies getSpecies() const {
0133       return ParticleSpecies(theA, theZ, theS);
0134     }
0135 
0136     void deleteParticles() {
0137       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0138         delete (*p);
0139       }
0140       clearParticles();
0141     }
0142 
0143     void clearParticles() { particles.clear(); }
0144 
0145     /// \brief Set the charge number of the cluster
0146     void setZ(const G4int Z) { theZ = Z; }
0147 
0148     /// \brief Set the mass number of the cluster
0149     void setA(const G4int A) { theA = A; }
0150 
0151     /// \brief Set the strangess number of the cluster
0152     void setS(const G4int S) { theS = S; }
0153 
0154     /// \brief Get the excitation energy of the cluster.
0155     G4double getExcitationEnergy() const { return theExcitationEnergy; }
0156 
0157     /// \brief Set the excitation energy of the cluster.
0158     void setExcitationEnergy(const G4double e) { theExcitationEnergy=e; }
0159 
0160     /** \brief Get the real particle mass.
0161      *
0162      * Overloads the Particle method.
0163      */
0164     inline virtual G4double getTableMass() const { return getRealMass(); }
0165 
0166     /**
0167      * Get the list of particles in the cluster.
0168      */
0169     ParticleList const &getParticles() const { return particles; }
0170 
0171     /// \brief Remove a particle from the cluster components.
0172     void removeParticle(Particle * const p) { particles.remove(p); }
0173 
0174     /**
0175      * Add one particle to the cluster. This updates the cluster mass,
0176      * energy, size, etc.
0177      */
0178     void addParticle(Particle * const p) {
0179       particles.push_back(p);
0180       theEnergy += p->getEnergy();
0181       thePotentialEnergy += p->getPotentialEnergy();
0182       theMomentum += p->getMomentum();
0183       thePosition += p->getPosition();
0184       theA += p->getA();
0185       theZ += p->getZ();
0186       theS += p->getS();
0187       nCollisions += p->getNumberOfCollisions();
0188     }
0189 
0190     /// \brief Set total cluster mass, energy, size, etc. from the particles
0191     void updateClusterParameters() {
0192       theEnergy = 0.;
0193       thePotentialEnergy = 0.;
0194       theMomentum = ThreeVector();
0195       thePosition = ThreeVector();
0196       theA = 0;
0197       theZ = 0;
0198       theS = 0;
0199       nCollisions = 0;
0200       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0201         theEnergy += (*p)->getEnergy();
0202         thePotentialEnergy += (*p)->getPotentialEnergy();
0203         theMomentum += (*p)->getMomentum();
0204         thePosition += (*p)->getPosition();
0205         theA += (*p)->getA();
0206         theZ += (*p)->getZ();
0207         theS += (*p)->getS();
0208         nCollisions += (*p)->getNumberOfCollisions();
0209       }
0210     }
0211 
0212     /// \brief Add a list of particles to the cluster
0213     void addParticles(ParticleList const &pL) {
0214       particles = pL;
0215       updateClusterParameters();
0216     }
0217 
0218     /// \brief Returns the list of particles that make up the cluster
0219     ParticleList getParticleList() const { return particles; }
0220 
0221     std::string print() const {
0222       std::stringstream ss;
0223       ss << "Cluster (ID = " << ID << ") type = ";
0224       ss << ParticleTable::getName(theType);
0225       ss << '\n'
0226         << "   A = " << theA << '\n'
0227         << "   Z = " << theZ << '\n'
0228         << "   S = " << theS << '\n'
0229         << "   mass = " << getMass() << '\n'
0230         << "   energy = " << theEnergy << '\n'
0231         << "   momentum = "
0232         << theMomentum.print()
0233         << '\n'
0234         << "   position = "
0235         << thePosition.print()
0236         << '\n'
0237         << "Contains the following particles:"
0238         << '\n';
0239       for(ParticleIter i=particles.begin(), e=particles.end(); i!=e; ++i)
0240         ss << (*i)->print();
0241       ss << '\n';
0242       return ss.str();
0243     }
0244 
0245     /// \brief Initialise the NuclearDensity pointer and sample the particles
0246     virtual void initializeParticles();
0247 
0248     /** \brief Boost to the CM of the component particles
0249      *
0250      * The position of all particles in the particles list is shifted so that
0251      * their centre of mass is in the origin and their total momentum is
0252      * zero.
0253      */
0254     void internalBoostToCM() {
0255 
0256       // First compute the current CM position and total momentum
0257       ThreeVector theCMPosition, theTotalMomentum;
0258       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0259         theCMPosition += (*p)->getPosition();
0260         theTotalMomentum += (*p)->getMomentum();
0261         //theTotalEnergy += (*p)->getEnergy();
0262       }
0263       theCMPosition /= theA;
0264 // assert((unsigned int)theA==particles.size());
0265 
0266       // Now determine the CM velocity of the particles
0267       // commented out because currently unused, see below
0268       // ThreeVector betaCM = theTotalMomentum / theTotalEnergy;
0269 
0270       // The new particle positions and momenta are scaled by a factor of
0271       // \f$\sqrt{A/(A-1)}\f$, so that the resulting density distributions in
0272       // the CM have the same variance as the one we started with.
0273       const G4double rescaling = std::sqrt(((G4double)theA)/((G4double)(theA-1)));
0274 
0275       // Loop again to boost and reposition
0276       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0277         // \bug{We should do the following, but the Fortran version actually
0278         // does not!
0279         // (*p)->boost(betaCM);
0280         // Here is what the Fortran version does:}
0281         (*p)->setMomentum(((*p)->getMomentum()-theTotalMomentum/theA)*rescaling);
0282 
0283         // Set the CM position of the particles
0284         (*p)->setPosition(((*p)->getPosition()-theCMPosition)*rescaling);
0285       }
0286 
0287       // Set the global cluster kinematic variables
0288       thePosition.setX(0.0);
0289       thePosition.setY(0.0);
0290       thePosition.setZ(0.0);
0291       theMomentum.setX(0.0);
0292       theMomentum.setY(0.0);
0293       theMomentum.setZ(0.0);
0294       theEnergy = getMass();
0295 
0296       INCL_DEBUG("Cluster boosted to internal CM:" << '\n' << print());
0297 
0298     }
0299 
0300     /** \brief Put the cluster components off shell
0301      *
0302      * The Cluster components are put off shell in such a way that their total
0303      * energy equals the cluster mass.
0304      */
0305     void putParticlesOffShell() {
0306       // Compute the dynamical potential
0307       const G4double theDynamicalPotential = computeDynamicalPotential();
0308       INCL_DEBUG("The dynamical potential is " << theDynamicalPotential << " MeV" << '\n');
0309 
0310       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0311         const G4double energy = (*p)->getEnergy() - theDynamicalPotential;
0312         const ThreeVector &momentum = (*p)->getMomentum();
0313         // Here particles are put off-shell so that we can satisfy the energy-
0314         // and momentum-conservation laws
0315         (*p)->setEnergy(energy);
0316         (*p)->setMass(std::sqrt(energy*energy - momentum.mag2()));
0317       }
0318       INCL_DEBUG("Cluster components are now off shell:" << '\n'
0319             << print());
0320     }
0321 
0322     /** \brief Set the position of the cluster
0323      *
0324      * This overloads the Particle method to take into account that the
0325      * positions of the cluster members must be updated as well.
0326      */
0327     void setPosition(const ThreeVector &position) {
0328       ThreeVector shift(position-thePosition);
0329       Particle::setPosition(position);
0330       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0331         (*p)->setPosition((*p)->getPosition()+shift);
0332       }
0333     }
0334 
0335     /** \brief Boost the cluster with the indicated velocity
0336      *
0337      * The Cluster is boosted as a whole, just like any Particle object;
0338      * moreover, the internal components (particles list) are also boosted,
0339      * according to Alain Boudard's off-shell recipe.
0340      *
0341      * \param aBoostVector the velocity to boost to [c]
0342      */
0343     void boost(const ThreeVector &aBoostVector) {
0344       Particle::boost(aBoostVector);
0345       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0346         (*p)->boost(aBoostVector);
0347         // Apply Lorentz contraction to the particle position
0348         (*p)->lorentzContract(aBoostVector,thePosition);
0349         (*p)->rpCorrelate();
0350       }
0351 
0352       INCL_DEBUG("Cluster was boosted with (bx,by,bz)=("
0353           << aBoostVector.getX() << ", " << aBoostVector.getY() << ", " << aBoostVector.getZ() << "):"
0354           << '\n' << print());
0355 
0356     }
0357 
0358     /** \brief Freeze the internal motion of the particles
0359      *
0360      * Each particle is assigned a frozen momentum four-vector determined by
0361      * the collective cluster velocity. This is used for propagation, but not
0362      * for dynamics. Normal propagation is restored by calling the
0363      * Particle::thawPropagation() method, which should be done in
0364      * InteractionAvatar::postInteraction.
0365      */
0366     void freezeInternalMotion() {
0367       const ThreeVector &normMomentum = theMomentum / getMass();
0368       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0369         const G4double pMass = (*p)->getMass();
0370         const ThreeVector frozenMomentum = normMomentum * pMass;
0371         const G4double frozenEnergy = std::sqrt(frozenMomentum.mag2()+pMass*pMass);
0372         (*p)->setFrozenMomentum(frozenMomentum);
0373         (*p)->setFrozenEnergy(frozenEnergy);
0374         (*p)->freezePropagation();
0375       }
0376     }
0377 
0378     /** \brief Rotate position of all the particles
0379      *
0380      * This includes the cluster components. Overloads Particle::rotateMomentum().
0381      *
0382      * \param angle the rotation angle
0383      * \param axis a unit vector representing the rotation axis
0384      */
0385     virtual void rotatePosition(const G4double angle, const ThreeVector &axis);
0386 
0387     /** \brief Rotate momentum of all the particles
0388      *
0389      * This includes the cluster components. Overloads Particle::rotateMomentum().
0390      *
0391      * \param angle the rotation angle
0392      * \param axis a unit vector representing the rotation axis
0393      */
0394     virtual void rotateMomentum(const G4double angle, const ThreeVector &axis);
0395 
0396     /// \brief Make all the components projectile spectators, too
0397     virtual void makeProjectileSpectator() {
0398       Particle::makeProjectileSpectator();
0399       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0400         (*p)->makeProjectileSpectator();
0401       }
0402     }
0403 
0404     /// \brief Make all the components target spectators, too
0405     virtual void makeTargetSpectator() {
0406       Particle::makeTargetSpectator();
0407       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0408         (*p)->makeTargetSpectator();
0409       }
0410     }
0411 
0412     /// \brief Make all the components participants, too
0413     virtual void makeParticipant() {
0414       Particle::makeParticipant();
0415       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0416         (*p)->makeParticipant();
0417       }
0418     }
0419 
0420     /// \brief Get the spin of the nucleus.
0421     ThreeVector const &getSpin() const { return theSpin; }
0422 
0423     /// \brief Set the spin of the nucleus.
0424     void setSpin(const ThreeVector &j) { theSpin = j; }
0425 
0426     /// \brief Get the total angular momentum (orbital + spin)
0427     G4INCL::ThreeVector getAngularMomentum() const {
0428       return Particle::getAngularMomentum() + getSpin();
0429     }
0430 
0431   private:
0432     /** \brief Compute the dynamical cluster potential
0433      *
0434      * Alain Boudard's boost prescription for low-energy beams requires to
0435      * define a "dynamical potential" that allows us to conserve momentum and
0436      * energy when boosting the projectile cluster.
0437      */
0438     G4double computeDynamicalPotential() {
0439       G4double theDynamicalPotential = 0.0;
0440       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
0441         theDynamicalPotential += (*p)->getEnergy();
0442       }
0443       theDynamicalPotential -= getTableMass();
0444       theDynamicalPotential /= theA;
0445 
0446       return theDynamicalPotential;
0447     }
0448 
0449   protected:
0450     ParticleList particles;
0451     G4double theExcitationEnergy;
0452     ThreeVector theSpin;
0453     ParticleSampler *theParticleSampler;
0454 
0455     INCL_DECLARE_ALLOCATION_POOL(Cluster)
0456   };
0457 
0458 }
0459 
0460 #endif