Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/hadronic/models/inclxx/incl_physics/include/G4INCLCluster.hh

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  1 //
  2 // ********************************************************************
  3 // * License and Disclaimer                                           *
  4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.                             *
 10 // *                                                                  *
 11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                                                  *
 18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // ********************************************************************
 25 //
 26 // INCL++ intra-nuclear cascade model
 27 // Alain Boudard, CEA-Saclay, France
 28 // Joseph Cugnon, University of Liege, Belgium
 29 // Jean-Christophe David, CEA-Saclay, France
 30 // Pekka Kaitaniemi, CEA-Saclay, France, and Helsinki Institute of Physics, Finland
 31 // Sylvie Leray, CEA-Saclay, France
 32 // Davide Mancusi, CEA-Saclay, France
 33 //
 34 #define INCLXX_IN_GEANT4_MODE 1
 35 
 36 #include "globals.hh"
 37 
 38 #ifndef G4INCLCluster_hh
 39 #define G4INCLCluster_hh 1
 40 
 41 #include "G4INCLParticle.hh"
 42 #include "G4INCLNuclearDensityFactory.hh"
 43 #include "G4INCLParticleSampler.hh"
 44 #include "G4INCLAllocationPool.hh"
 45 
 46 namespace G4INCL {
 47 
 48   /**
 49    * Cluster is a particle (inherits from the Particle class) that is
 50    * actually a collection of elementary particles.
 51    */
 52   class Cluster : public Particle {
 53   public:
 54 
 55     /** \brief Standard Cluster constructor
 56      *
 57      * This constructor should mainly be used when constructing Nucleus or
 58      * when constructing Clusters to be used as composite projectiles.
 59      */
 60     Cluster(const G4int Z, const G4int A, const G4int S, const G4bool createParticleSampler=true) :
 61       Particle(),
 62       theExcitationEnergy(0.),
 63       theSpin(0.,0.,0.),
 64       theParticleSampler(NULL)
 65     {
 66       setType(Composite);
 67       theZ = Z;
 68       theA = A;
 69       theS = S;
 70       setINCLMass();
 71       if(createParticleSampler)
 72         theParticleSampler = new ParticleSampler(A,Z,S);
 73     }
 74 
 75     /**
 76      * A cluster can be directly built from a list of particles.
 77      */
 78     template<class Iterator>
 79       Cluster(Iterator begin, Iterator end) :
 80         Particle(),
 81         theExcitationEnergy(0.),
 82         theSpin(0.,0.,0.),
 83         theParticleSampler(NULL)
 84     {
 85       setType(Composite);
 86       for(Iterator i = begin; i != end; ++i) {
 87         addParticle(*i);
 88       }
 89       thePosition /= theA;
 90       setINCLMass();
 91       adjustMomentumFromEnergy();
 92     }
 93 
 94     virtual ~Cluster() {
 95       delete theParticleSampler;
 96     }
 97 
 98     /// \brief Copy constructor
 99     Cluster(const Cluster &rhs) :
100       Particle(rhs),
101       theExcitationEnergy(rhs.theExcitationEnergy),
102       theSpin(rhs.theSpin)
103     {
104       for(ParticleIter p=rhs.particles.begin(), e=rhs.particles.end(); p!=e; ++p) {
105         particles.push_back(new Particle(**p));
106       }
107       if(rhs.theParticleSampler)
108         theParticleSampler = new ParticleSampler(rhs.theA,rhs.theZ,rhs.theS);
109       else
110         theParticleSampler = NULL;
111     }
112 
113     /// \brief Assignment operator
114     Cluster &operator=(const Cluster &rhs) {
115       Cluster temporaryCluster(rhs);
116       Particle::operator=(temporaryCluster);
117       swap(temporaryCluster);
118       return *this;
119     }
120 
121     /// \brief Helper method for the assignment operator
122     void swap(Cluster &rhs) {
123       Particle::swap(rhs);
124       std::swap(theExcitationEnergy, rhs.theExcitationEnergy);
125       std::swap(theSpin, rhs.theSpin);
126       // std::swap is overloaded by std::list and guaranteed to operate in
127       // constant time
128       std::swap(particles, rhs.particles);
129       std::swap(theParticleSampler, rhs.theParticleSampler);
130     }
131 
132     ParticleSpecies getSpecies() const {
133       return ParticleSpecies(theA, theZ, theS);
134     }
135 
136     void deleteParticles() {
137       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
138         delete (*p);
139       }
140       clearParticles();
141     }
142 
143     void clearParticles() { particles.clear(); }
144 
145     /// \brief Set the charge number of the cluster
146     void setZ(const G4int Z) { theZ = Z; }
147 
148     /// \brief Set the mass number of the cluster
149     void setA(const G4int A) { theA = A; }
150 
151     /// \brief Set the strangess number of the cluster
152     void setS(const G4int S) { theS = S; }
153 
154     /// \brief Get the excitation energy of the cluster.
155     G4double getExcitationEnergy() const { return theExcitationEnergy; }
156 
157     /// \brief Set the excitation energy of the cluster.
158     void setExcitationEnergy(const G4double e) { theExcitationEnergy=e; }
159 
160     /** \brief Get the real particle mass.
161      *
162      * Overloads the Particle method.
163      */
164     inline virtual G4double getTableMass() const { return getRealMass(); }
165 
166     /**
167      * Get the list of particles in the cluster.
168      */
169     ParticleList const &getParticles() const { return particles; }
170 
171     /// \brief Remove a particle from the cluster components.
172     void removeParticle(Particle * const p) { particles.remove(p); }
173 
174     /**
175      * Add one particle to the cluster. This updates the cluster mass,
176      * energy, size, etc.
177      */
178     void addParticle(Particle * const p) {
179       particles.push_back(p);
180       theEnergy += p->getEnergy();
181       thePotentialEnergy += p->getPotentialEnergy();
182       theMomentum += p->getMomentum();
183       thePosition += p->getPosition();
184       theA += p->getA();
185       theZ += p->getZ();
186       theS += p->getS();
187       nCollisions += p->getNumberOfCollisions();
188     }
189 
190     /// \brief Set total cluster mass, energy, size, etc. from the particles
191     void updateClusterParameters() {
192       theEnergy = 0.;
193       thePotentialEnergy = 0.;
194       theMomentum = ThreeVector();
195       thePosition = ThreeVector();
196       theA = 0;
197       theZ = 0;
198       theS = 0;
199       nCollisions = 0;
200       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
201         theEnergy += (*p)->getEnergy();
202         thePotentialEnergy += (*p)->getPotentialEnergy();
203         theMomentum += (*p)->getMomentum();
204         thePosition += (*p)->getPosition();
205         theA += (*p)->getA();
206         theZ += (*p)->getZ();
207         theS += (*p)->getS();
208         nCollisions += (*p)->getNumberOfCollisions();
209       }
210     }
211 
212     /// \brief Add a list of particles to the cluster
213     void addParticles(ParticleList const &pL) {
214       particles = pL;
215       updateClusterParameters();
216     }
217 
218     /// \brief Returns the list of particles that make up the cluster
219     ParticleList getParticleList() const { return particles; }
220 
221     std::string print() const {
222       std::stringstream ss;
223       ss << "Cluster (ID = " << ID << ") type = ";
224       ss << ParticleTable::getName(theType);
225       ss << '\n'
226         << "   A = " << theA << '\n'
227         << "   Z = " << theZ << '\n'
228         << "   S = " << theS << '\n'
229         << "   mass = " << getMass() << '\n'
230         << "   energy = " << theEnergy << '\n'
231         << "   momentum = "
232         << theMomentum.print()
233         << '\n'
234         << "   position = "
235         << thePosition.print()
236         << '\n'
237         << "Contains the following particles:"
238         << '\n';
239       for(ParticleIter i=particles.begin(), e=particles.end(); i!=e; ++i)
240         ss << (*i)->print();
241       ss << '\n';
242       return ss.str();
243     }
244 
245     /// \brief Initialise the NuclearDensity pointer and sample the particles
246     virtual void initializeParticles();
247 
248     /** \brief Boost to the CM of the component particles
249      *
250      * The position of all particles in the particles list is shifted so that
251      * their centre of mass is in the origin and their total momentum is
252      * zero.
253      */
254     void internalBoostToCM() {
255 
256       // First compute the current CM position and total momentum
257       ThreeVector theCMPosition, theTotalMomentum;
258       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
259         theCMPosition += (*p)->getPosition();
260         theTotalMomentum += (*p)->getMomentum();
261         //theTotalEnergy += (*p)->getEnergy();
262       }
263       theCMPosition /= theA;
264 // assert((unsigned int)theA==particles.size());
265 
266       // Now determine the CM velocity of the particles
267       // commented out because currently unused, see below
268       // ThreeVector betaCM = theTotalMomentum / theTotalEnergy;
269 
270       // The new particle positions and momenta are scaled by a factor of
271       // \f$\sqrt{A/(A-1)}\f$, so that the resulting density distributions in
272       // the CM have the same variance as the one we started with.
273       const G4double rescaling = std::sqrt(((G4double)theA)/((G4double)(theA-1)));
274 
275       // Loop again to boost and reposition
276       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
277         // \bug{We should do the following, but the Fortran version actually
278         // does not!
279         // (*p)->boost(betaCM);
280         // Here is what the Fortran version does:}
281         (*p)->setMomentum(((*p)->getMomentum()-theTotalMomentum/theA)*rescaling);
282 
283         // Set the CM position of the particles
284         (*p)->setPosition(((*p)->getPosition()-theCMPosition)*rescaling);
285       }
286 
287       // Set the global cluster kinematic variables
288       thePosition.setX(0.0);
289       thePosition.setY(0.0);
290       thePosition.setZ(0.0);
291       theMomentum.setX(0.0);
292       theMomentum.setY(0.0);
293       theMomentum.setZ(0.0);
294       theEnergy = getMass();
295 
296       INCL_DEBUG("Cluster boosted to internal CM:" << '\n' << print());
297 
298     }
299 
300     /** \brief Put the cluster components off shell
301      *
302      * The Cluster components are put off shell in such a way that their total
303      * energy equals the cluster mass.
304      */
305     void putParticlesOffShell() {
306       // Compute the dynamical potential
307       const G4double theDynamicalPotential = computeDynamicalPotential();
308       INCL_DEBUG("The dynamical potential is " << theDynamicalPotential << " MeV" << '\n');
309 
310       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
311         const G4double energy = (*p)->getEnergy() - theDynamicalPotential;
312         const ThreeVector &momentum = (*p)->getMomentum();
313         // Here particles are put off-shell so that we can satisfy the energy-
314         // and momentum-conservation laws
315         (*p)->setEnergy(energy);
316         (*p)->setMass(std::sqrt(energy*energy - momentum.mag2()));
317       }
318       INCL_DEBUG("Cluster components are now off shell:" << '\n'
319             << print());
320     }
321 
322     /** \brief Set the position of the cluster
323      *
324      * This overloads the Particle method to take into account that the
325      * positions of the cluster members must be updated as well.
326      */
327     void setPosition(const ThreeVector &position) {
328       ThreeVector shift(position-thePosition);
329       Particle::setPosition(position);
330       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
331         (*p)->setPosition((*p)->getPosition()+shift);
332       }
333     }
334 
335     /** \brief Boost the cluster with the indicated velocity
336      *
337      * The Cluster is boosted as a whole, just like any Particle object;
338      * moreover, the internal components (particles list) are also boosted,
339      * according to Alain Boudard's off-shell recipe.
340      *
341      * \param aBoostVector the velocity to boost to [c]
342      */
343     void boost(const ThreeVector &aBoostVector) {
344       Particle::boost(aBoostVector);
345       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
346         (*p)->boost(aBoostVector);
347         // Apply Lorentz contraction to the particle position
348         (*p)->lorentzContract(aBoostVector,thePosition);
349         (*p)->rpCorrelate();
350       }
351 
352       INCL_DEBUG("Cluster was boosted with (bx,by,bz)=("
353           << aBoostVector.getX() << ", " << aBoostVector.getY() << ", " << aBoostVector.getZ() << "):"
354           << '\n' << print());
355 
356     }
357 
358     /** \brief Freeze the internal motion of the particles
359      *
360      * Each particle is assigned a frozen momentum four-vector determined by
361      * the collective cluster velocity. This is used for propagation, but not
362      * for dynamics. Normal propagation is restored by calling the
363      * Particle::thawPropagation() method, which should be done in
364      * InteractionAvatar::postInteraction.
365      */
366     void freezeInternalMotion() {
367       const ThreeVector &normMomentum = theMomentum / getMass();
368       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
369         const G4double pMass = (*p)->getMass();
370         const ThreeVector frozenMomentum = normMomentum * pMass;
371         const G4double frozenEnergy = std::sqrt(frozenMomentum.mag2()+pMass*pMass);
372         (*p)->setFrozenMomentum(frozenMomentum);
373         (*p)->setFrozenEnergy(frozenEnergy);
374         (*p)->freezePropagation();
375       }
376     }
377 
378     /** \brief Rotate position of all the particles
379      *
380      * This includes the cluster components. Overloads Particle::rotateMomentum().
381      *
382      * \param angle the rotation angle
383      * \param axis a unit vector representing the rotation axis
384      */
385     virtual void rotatePosition(const G4double angle, const ThreeVector &axis);
386 
387     /** \brief Rotate momentum of all the particles
388      *
389      * This includes the cluster components. Overloads Particle::rotateMomentum().
390      *
391      * \param angle the rotation angle
392      * \param axis a unit vector representing the rotation axis
393      */
394     virtual void rotateMomentum(const G4double angle, const ThreeVector &axis);
395 
396     /// \brief Make all the components projectile spectators, too
397     virtual void makeProjectileSpectator() {
398       Particle::makeProjectileSpectator();
399       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
400         (*p)->makeProjectileSpectator();
401       }
402     }
403 
404     /// \brief Make all the components target spectators, too
405     virtual void makeTargetSpectator() {
406       Particle::makeTargetSpectator();
407       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
408         (*p)->makeTargetSpectator();
409       }
410     }
411 
412     /// \brief Make all the components participants, too
413     virtual void makeParticipant() {
414       Particle::makeParticipant();
415       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
416         (*p)->makeParticipant();
417       }
418     }
419 
420     /// \brief Get the spin of the nucleus.
421     ThreeVector const &getSpin() const { return theSpin; }
422 
423     /// \brief Set the spin of the nucleus.
424     void setSpin(const ThreeVector &j) { theSpin = j; }
425 
426     /// \brief Get the total angular momentum (orbital + spin)
427     G4INCL::ThreeVector getAngularMomentum() const {
428       return Particle::getAngularMomentum() + getSpin();
429     }
430 
431   private:
432     /** \brief Compute the dynamical cluster potential
433      *
434      * Alain Boudard's boost prescription for low-energy beams requires to
435      * define a "dynamical potential" that allows us to conserve momentum and
436      * energy when boosting the projectile cluster.
437      */
438     G4double computeDynamicalPotential() {
439       G4double theDynamicalPotential = 0.0;
440       for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
441         theDynamicalPotential += (*p)->getEnergy();
442       }
443       theDynamicalPotential -= getTableMass();
444       theDynamicalPotential /= theA;
445 
446       return theDynamicalPotential;
447     }
448 
449   protected:
450     ParticleList particles;
451     G4double theExcitationEnergy;
452     ThreeVector theSpin;
453     ParticleSampler *theParticleSampler;
454 
455     INCL_DECLARE_ALLOCATION_POOL(Cluster)
456   };
457 
458 }
459 
460 #endif
461