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