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