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