Geant4  10.01.p01
G4INCLProjectileRemnant.cc
Go to the documentation of this file.
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 
46 #include <algorithm>
47 #include <numeric>
48 
49 namespace G4INCL {
50 
55  theEnergy = 0.0;
56  thePotentialEnergy = 0.0;
57  theA = 0;
58  theZ = 0;
59  nCollisions = 0;
60 
61  for(std::map<long, Particle*>::const_iterator i=storedComponents.begin(); i!=storedComponents.end(); ++i) {
62  Particle *p = new Particle(*(i->second));
63  EnergyLevelMap::iterator energyIter = theInitialEnergyLevels.find(i->first);
64 // assert(energyIter!=theInitialEnergyLevels.end());
65  const G4double energyLevel = energyIter->second;
66  theInitialEnergyLevels.erase(energyIter);
67  theInitialEnergyLevels[p->getID()] = energyLevel;
68  addParticle(p);
69  }
70  if(theA>0)
71  thePosition /= theA;
72  setTableMass();
73  INCL_DEBUG("ProjectileRemnant object was reset:" << '\n' << print());
74  }
75 
76  void ProjectileRemnant::removeParticle(Particle * const p, const G4double theProjectileCorrection) {
77 // assert(p->isNucleon());
78 
79  INCL_DEBUG("The following Particle is about to be removed from the ProjectileRemnant:"
80  << '\n' << p->print()
81  << "theProjectileCorrection=" << theProjectileCorrection << '\n');
82  // Update A, Z, momentum and energy of the projectile remnant
83  theA -= p->getA();
84  theZ -= p->getZ();
85 
86  ThreeVector const &oldMomentum = p->getMomentum();
87  const G4double oldEnergy = p->getEnergy();
89 
90 #if !defined(NDEBUG) && !defined(INCLXX_IN_GEANT4_MODE)
91  ThreeVector theTotalMomentum;
92  G4double theTotalEnergy = 0.;
93  const G4double theThreshold = 0.1;
94 #endif
95 
96  if(getA()>0) { // if there are any particles left
97 // assert((unsigned int)getA()==particles.size());
98 
99  const G4double theProjectileCorrectionPerNucleon = theProjectileCorrection / particles.size();
100 
101  // Update the kinematics of the components
102  for(ParticleIter i=particles.begin(), e=particles.end(); i!=e; ++i) {
103  (*i)->setEnergy((*i)->getEnergy() + theProjectileCorrectionPerNucleon);
104  (*i)->setMass((*i)->getInvariantMass());
105 #if !defined(NDEBUG) && !defined(INCLXX_IN_GEANT4_MODE)
106  theTotalMomentum += (*i)->getMomentum();
107  theTotalEnergy += (*i)->getEnergy();
108 #endif
109  }
110  }
111 
112  theMomentum -= oldMomentum;
113  theEnergy -= oldEnergy - theProjectileCorrection;
114 
115 // assert(std::abs((theTotalMomentum-theMomentum).mag())<theThreshold);
116 // assert(std::abs(theTotalEnergy-theEnergy)<theThreshold);
117  INCL_DEBUG("After Particle removal, the ProjectileRemnant looks like this:"
118  << '\n' << print());
119  }
120 
122  // Try as hard as possible to add back all the dynamical spectators.
123  // Don't add spectators that lead to negative excitation energies, but
124  // iterate over the spectators as many times as possible, until
125  // absolutely sure that all of them were rejected.
126  unsigned int accepted;
127  do {
128  accepted = 0;
129  ParticleList toBeAdded = pL;
130  for(ParticleIter p=toBeAdded.begin(), e=toBeAdded.end(); p!=e; ++p) {
131  G4bool isAccepted = addDynamicalSpectator(*p);
132  if(isAccepted) {
133  pL.remove(*p);
134  accepted++;
135  }
136  }
137  } while(accepted > 0);
138  return pL;
139  }
140 
142  // Put all the spectators in the projectile
143  ThreeVector theNewMomentum = theMomentum;
144  G4double theNewEnergy = theEnergy;
145  G4int theNewA = theA;
146  G4int theNewZ = theZ;
147  for(ParticleIter p=pL.begin(), e=pL.end(); p!=e; ++p) {
148 // assert((*p)->isNucleon());
149  // Add the initial (off-shell) momentum and energy to the projectile remnant
150  theNewMomentum += getStoredMomentum(*p);
151  theNewEnergy += (*p)->getEnergy();
152  theNewA += (*p)->getA();
153  theNewZ += (*p)->getZ();
154  }
155 
156  // Check that the excitation energy of the new projectile remnant is non-negative
157  const G4double theNewMass = ParticleTable::getTableMass(theNewA,theNewZ);
158  const G4double theNewExcitationEnergy = computeExcitationEnergyWith(pL);
159  const G4double theNewEffectiveMass = theNewMass + theNewExcitationEnergy;
160 
161  // If this condition is satisfied, there is no solution. Fall back on the
162  // "most" method
163  if(theNewEnergy<theNewEffectiveMass) {
164  INCL_WARN("Could not add all the dynamical spectators back into the projectile remnant."
165  << " Falling back to the \"most\" method." << '\n');
166  return addMostDynamicalSpectators(pL);
167  }
168 
169  // Add all the participants to the projectile remnant
170  for(ParticleIter p=pL.begin(), e=pL.end(); p!=e; ++p) {
171  particles.push_back(*p);
172  }
173 
174  // Rescale the momentum of the projectile remnant so that sqrt(s) has the
175  // correct value
176  const G4double scalingFactorSquared = (theNewEnergy*theNewEnergy-theNewEffectiveMass*theNewEffectiveMass)/theNewMomentum.mag2();
177  const G4double scalingFactor = std::sqrt(scalingFactorSquared);
178  INCL_DEBUG("Scaling factor for the projectile-remnant momentum = " << scalingFactor << '\n');
179 
180  theA = theNewA;
181  theZ = theNewZ;
182  theMomentum = theNewMomentum * scalingFactor;
183  theEnergy = theNewEnergy;
184 
185  return ParticleList();
186  }
187 
189  // Try as hard as possible to add back all the dynamical spectators.
190  // Don't add spectators that lead to negative excitation energies. Start by
191  // adding all of them, and repeatedly remove the most troublesome one until
192  // the excitation energy becomes non-negative.
193 
194  // Put all the spectators in the projectile
195  ThreeVector theNewMomentum = theMomentum;
196  G4double theNewEnergy = theEnergy;
197  G4int theNewA = theA;
198  G4int theNewZ = theZ;
199  for(ParticleIter p=pL.begin(), e=pL.end(); p!=e; ++p) {
200 // assert((*p)->isNucleon());
201  // Add the initial (off-shell) momentum and energy to the projectile remnant
202  theNewMomentum += getStoredMomentum(*p);
203  theNewEnergy += (*p)->getEnergy();
204  theNewA += (*p)->getA();
205  theNewZ += (*p)->getZ();
206  }
207 
208  // Check that the excitation energy of the new projectile remnant is non-negative
209  const G4double theNewMass = ParticleTable::getTableMass(theNewA,theNewZ);
210  const G4double theNewInvariantMassSquared = theNewEnergy*theNewEnergy-theNewMomentum.mag2();
211 
212  G4bool positiveExcitationEnergy = false;
213  if(theNewInvariantMassSquared>=0.) {
214  const G4double theNewInvariantMass = std::sqrt(theNewInvariantMassSquared);
215  positiveExcitationEnergy = (theNewInvariantMass-theNewMass>-1.e-5);
216  }
217 
218  // Keep removing nucleons from the projectile remnant until we achieve a
219  // non-negative excitation energy.
220  ParticleList rejected;
221  while(!positiveExcitationEnergy && !pL.empty()) {
222  G4double maxExcitationEnergy = -1.E30;
223  ParticleMutableIter best = pL.end();
224  ThreeVector bestMomentum;
225  G4double bestEnergy = -1.;
226  G4int bestA = -1, bestZ = -1;
227  for(ParticleList::iterator p=pL.begin(), e=pL.end(); p!=e; ++p) {
228  // Subtract the initial (off-shell) momentum and energy from the new
229  // projectile remnant
230  const ThreeVector theNewerMomentum = theNewMomentum - getStoredMomentum(*p);
231  const G4double theNewerEnergy = theNewEnergy - (*p)->getEnergy();
232  const G4int theNewerA = theNewA - (*p)->getA();
233  const G4int theNewerZ = theNewZ - (*p)->getZ();
234 
235  const G4double theNewerMass = ParticleTable::getTableMass(theNewerA,theNewerZ);
236  const G4double theNewerInvariantMassSquared = theNewerEnergy*theNewerEnergy-theNewerMomentum.mag2();
237 
238  if(theNewerInvariantMassSquared>=-1.e-5) {
239  const G4double theNewerInvariantMass = std::sqrt(std::max(0.,theNewerInvariantMassSquared));
240  const G4double theNewerExcitationEnergy = ((theNewerA>1) ? theNewerInvariantMass-theNewerMass : 0.);
241  // Pick the nucleon that maximises the excitation energy of the
242  // ProjectileRemnant
243  if(theNewerExcitationEnergy>maxExcitationEnergy) {
244  best = p;
245  maxExcitationEnergy = theNewerExcitationEnergy;
246  bestMomentum = theNewerMomentum;
247  bestEnergy = theNewerEnergy;
248  bestA = theNewerA;
249  bestZ = theNewerZ;
250  }
251  }
252  }
253 
254  // If we couldn't even calculate the excitation energy, fail miserably
255  if(best==pL.end())
256  return pL;
257 
258  rejected.push_back(*best);
259  pL.erase(best);
260  theNewMomentum = bestMomentum;
261  theNewEnergy = bestEnergy;
262  theNewA = bestA;
263  theNewZ = bestZ;
264 
265  if(maxExcitationEnergy>0.) {
266  // Stop here
267  positiveExcitationEnergy = true;
268  }
269  }
270 
271  // Add the accepted participants to the projectile remnant
272  for(ParticleIter p=pL.begin(), e=pL.end(); p!=e; ++p) {
273  particles.push_back(*p);
274  }
275  theA = theNewA;
276  theZ = theNewZ;
277  theMomentum = theNewMomentum;
278  theEnergy = theNewEnergy;
279 
280  return rejected;
281  }
282 
284 // assert(p->isNucleon());
285 
286  // Add the initial (off-shell) momentum and energy to the projectile remnant
287  ThreeVector const &oldMomentum = getStoredMomentum(p);
288  const ThreeVector theNewMomentum = theMomentum + oldMomentum;
289  const G4double oldEnergy = p->getEnergy();
290  const G4double theNewEnergy = theEnergy + oldEnergy;
291 
292  // Check that the excitation energy of the new projectile remnant is non-negative
293  const G4double theNewMass = ParticleTable::getTableMass(theA+p->getA(),theZ+p->getZ());
294  const G4double theNewInvariantMassSquared = theNewEnergy*theNewEnergy-theNewMomentum.mag2();
295 
296  if(theNewInvariantMassSquared<0.)
297  return false;
298 
299  const G4double theNewInvariantMass = std::sqrt(theNewInvariantMassSquared);
300 
301  if(theNewInvariantMass-theNewMass<-1.e-5)
302  return false; // negative excitation energy here
303 
304  // Add the spectator to the projectile remnant
305  theA += p->getA();
306  theZ += p->getZ();
307  theMomentum = theNewMomentum;
308  theEnergy = theNewEnergy;
309  particles.push_back(p);
310  return true;
311  }
312 
314  const EnergyLevels theEnergyLevels = getPresentEnergyLevelsExcept(exceptID);
315  return computeExcitationEnergy(theEnergyLevels);
316  }
317 
319  const EnergyLevels theEnergyLevels = getPresentEnergyLevelsWith(pL);
320  return computeExcitationEnergy(theEnergyLevels);
321  }
322 
324  // The ground-state energy is the sum of the A smallest initial projectile
325  // energies.
326  // For the last nucleon, return 0 so that the algorithm will just put it on
327  // shell.
328  const unsigned theNewA = levels.size();
329 // assert(theNewA>0);
330  if(theNewA==1)
331  return 0.;
332 
333  const G4double groundState = theGroundStateEnergies.at(theNewA-1);
334 
335  // Compute the sum of the presently occupied energy levels
336  const G4double excitedState = std::accumulate(
337  levels.begin(),
338  levels.end(),
339  0.);
340 
341  return excitedState-groundState;
342  }
343 
345  EnergyLevels theEnergyLevels;
346  for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
347  if((*p)->getID()!=exceptID) {
348  EnergyLevelMap::const_iterator i = theInitialEnergyLevels.find((*p)->getID());
349 // assert(i!=theInitialEnergyLevels.end());
350  theEnergyLevels.push_back(i->second);
351  }
352  }
353 // assert(theEnergyLevels.size()==particles.size()-1);
354  return theEnergyLevels;
355  }
356 
358  EnergyLevels theEnergyLevels;
359  for(ParticleIter p=particles.begin(), e=particles.end(); p!=e; ++p) {
360  EnergyLevelMap::const_iterator i = theInitialEnergyLevels.find((*p)->getID());
361 // assert(i!=theInitialEnergyLevels.end());
362  theEnergyLevels.push_back(i->second);
363  }
364  for(ParticleIter p=pL.begin(), e=pL.end(); p!=e; ++p) {
365  EnergyLevelMap::const_iterator i = theInitialEnergyLevels.find((*p)->getID());
366 // assert(i!=theInitialEnergyLevels.end());
367  theEnergyLevels.push_back(i->second);
368  }
369 
370 // assert(theEnergyLevels.size()==particles.size()+pL.size());
371  return theEnergyLevels;
372  }
373 
374 }
375 
G4int getA() const
Returns the baryon number.
EnergyLevels getPresentEnergyLevelsWith(const ParticleList &pL) const
G4bool addDynamicalSpectator(Particle *const p)
Add back a nucleon to the projectile remnant.
EnergyLevels getPresentEnergyLevelsExcept(const long exceptID) const
const G4INCL::ThreeVector & getMomentum() const
Get the momentum vector.
Class for constructing a projectile-like remnant.
std::string print() const
G4double getEnergy() const
Get the energy of the particle in MeV.
#define INCL_WARN(x)
ThreeVector const & getStoredMomentum(Particle const *const p) const
Return the stored momentum of a given projectile component.
void reset()
Reset the projectile remnant to the state at the beginning of the cascade.
int G4int
Definition: G4Types.hh:78
G4double mag2() const
Get the square of the length.
G4double computeExcitationEnergyWith(const ParticleList &pL) const
Compute the excitation energy if some nucleons are put back.
std::map< long, Particle * > storedComponents
Return the stored energy of a given projectile component.
std::string print() const
bool G4bool
Definition: G4Types.hh:79
ParticleList particles
G4int getZ() const
Returns the charge number.
G4double computeExcitationEnergyExcept(const long exceptID) const
Compute the excitation energy when a nucleon is removed.
G4INCL::ThreeVector thePosition
void removeParticle(Particle *const p)
Remove a particle from the cluster components.
ParticleList addDynamicalSpectators(ParticleList pL)
Add back dynamical spectators to the projectile remnant.
ParticleList addAllDynamicalSpectators(ParticleList const &pL)
Add back all dynamical spectators to the projectile remnant.
G4double computeExcitationEnergy(const EnergyLevels &levels) const
Compute the excitation energy for a given configuration.
T max(const T t1, const T t2)
brief Return the largest of the two arguments
G4ThreadLocal NuclearMassFn getTableMass
Static pointer to the mass function for nuclei.
void setTableMass()
Set the mass of the Particle to its table mass.
EnergyLevels theGroundStateEnergies
Ground-state energies for any number of nucleons.
ParticleList addMostDynamicalSpectators(ParticleList pL)
Add back dynamical spectators to the projectile remnant.
EnergyLevelMap theInitialEnergyLevels
Initial energy levels of the projectile.
void addParticle(Particle *const p)
Add one particle to the cluster.
std::vector< G4double > EnergyLevels
void removeParticle(Particle *const p, const G4double theProjectileCorrection)
Remove a nucleon from the projectile remnant.
G4INCL::ThreeVector theMomentum
double G4double
Definition: G4Types.hh:76
#define INCL_DEBUG(x)
ParticleList::iterator ParticleMutableIter
G4double thePotentialEnergy
ParticleList::const_iterator ParticleIter
long getID() const