Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
G4INCLClusteringModelIntercomparison.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// INCL++ revision: v5.1.8
34//
35#define INCLXX_IN_GEANT4_MODE 1
36
37#include "globals.hh"
38
40#include "G4INCLCluster.hh"
41#include "G4INCLRandom.hh"
42#include "G4INCLHashing.hh"
43#include <algorithm>
44
45namespace G4INCL {
46 const G4double ClusteringModelIntercomparison::limitCosEscapeAngle = 0.7;
47
48 static G4bool cascadingFirstPredicate(Particle *aParticle) {
49 return !aParticle->isTargetSpectator();
50 }
51
53 // Set the maximum clustering mass dynamically, based on the current nucleus
54 const G4int maxClusterAlgorithmMass = nucleus->getStore()->getConfig()->getClusterMaxMass();
55 runningMaxClusterAlgorithmMass = std::min(maxClusterAlgorithmMass, nucleus->getA()/2);
56
57 // Nucleus too small?
58 if(runningMaxClusterAlgorithmMass<=1)
59 return NULL;
60
61 theNucleus = nucleus;
62 Particle *theLeadingParticle = particle;
63
64 // Initialise sqtot to a large number
65 sqtot = 50000.0;
66 selectedA = 0;
67 selectedZ = 0;
68
69 // The distance parameter, known as h in publications.
70 // Default value is 1 fm.
71 const G4double transp = 1.0;
72
73 const G4double rmaxws = theNucleus->getUniverseRadius();
74
75 // Radius of the sphere where the leading particle is positioned.
76 const G4double Rprime = theNucleus->getDensity()->getNuclearRadius() + transp;
77
78 // Bring the leading particle back to the coalescence sphere
79 const G4double pk = theLeadingParticle->getMomentum().mag();
80 const G4double cospr = theLeadingParticle->getPosition().dot(theLeadingParticle->getMomentum())/(theNucleus->getUniverseRadius() * pk);
81 const G4double arg = rmaxws*rmaxws - Rprime*Rprime;
82 G4double translat;
83
84 if(arg > 0.0) {
85 // coalescence sphere smaller than Rmax
86 const G4double cosmin = std::sqrt(arg)/rmaxws;
87 if(cospr <= cosmin) {
88 // there is an intersection with the coalescence sphere
89 translat = rmaxws * cospr;
90 } else {
91 // no intersection with the coalescence sphere
92 translat = rmaxws * (cospr - std::sqrt(cospr*cospr - cosmin*cosmin));
93 }
94 } else {
95 // coalescence sphere larger than Rmax
96 translat = rmaxws * cospr - std::sqrt(Rprime*Rprime - rmaxws*rmaxws*(1.0 - cospr*cospr));
97 }
98
99 const ThreeVector oldLeadingParticlePosition = theLeadingParticle->getPosition();
100 const ThreeVector leadingParticlePosition = oldLeadingParticlePosition - theLeadingParticle->getMomentum() * (translat/pk);
101 const ThreeVector &leadingParticleMomentum = theLeadingParticle->getMomentum();
102 theLeadingParticle->setPosition(leadingParticlePosition);
103
104 // Initialise the array of considered nucleons
105 const G4int theNucleusA = theNucleus->getA();
106 if(nConsideredMax < theNucleusA) {
107 delete [] consideredPartners;
108 delete [] isInRunningConfiguration;
109 nConsideredMax = 2*theNucleusA;
110 consideredPartners = new Particle *[nConsideredMax];
111 isInRunningConfiguration = new G4bool [nConsideredMax];
112 std::fill(isInRunningConfiguration,
113 isInRunningConfiguration + nConsideredMax,
114 false);
115 }
116
117 // Select the subset of nucleons that will be considered in the
118 // cluster production:
119 cascadingEnergyPool = 0.;
120 nConsidered = 0;
121 const ParticleList particles = theNucleus->getStore()->getParticles();
122 for(ParticleIter i = particles.begin(); i != particles.end(); ++i) {
123 if (!(*i)->isNucleon()) continue; // Only nucleons are allowed in clusters
124 if ((*i)->getID() == theLeadingParticle->getID()) continue; // Don't count the leading particle
125
126 G4double space = ((*i)->getPosition() - leadingParticlePosition).mag2();
127 G4double momentum = ((*i)->getMomentum() - leadingParticleMomentum).mag2();
128 G4double size = space*momentum*ParticleTable::clusterPosFact2[runningMaxClusterAlgorithmMass];
129 // Nucleons are accepted only if they are "close enough" in phase space
130 // to the leading nucleon. The selected phase-space parameter corresponds
131 // to the running maximum cluster mass.
132 if(size < ParticleTable::clusterPhaseSpaceCut[runningMaxClusterAlgorithmMass]) {
133 consideredPartners[nConsidered] = *i;
134 // Keep trace of how much energy is carried by cascading nucleons. This
135 // is used to stop the clustering algorithm as soon as possible.
136 if(!(*i)->isTargetSpectator())
137 cascadingEnergyPool += (*i)->getEnergy() - (*i)->getPotentialEnergy() - 931.3;
138 nConsidered++;
139 // Make sure we don't exceed the array size
140// assert(nConsidered<=nConsideredMax);
141 }
142 }
143 // Sort the list of considered partners so that we give priority
144 // to participants. As soon as we encounter the first spectator in
145 // the list we know that all the remaining nucleons will be
146 // spectators too.
147 std::partition(consideredPartners, consideredPartners+nConsidered, cascadingFirstPredicate);
148
149 // Clear the sets of checked configurations
150 // We stop caching two masses short of the max mass -- there seems to be a
151 // performance hit above
152 maxMassConfigurationSkipping = runningMaxClusterAlgorithmMass-2;
153 for(G4int i=0; i<runningMaxClusterAlgorithmMass-2; ++i) // no caching for A=1,2
154 checkedConfigurations[i].clear();
155
156 // Initialise position, momentum and energy of the running cluster
157 // configuration
158 runningPositions[1] = leadingParticlePosition;
159 runningMomenta[1] = leadingParticleMomentum;
160 runningEnergies[1] = theLeadingParticle->getEnergy();
161 runningPotentials[1] = theLeadingParticle->getPotentialEnergy();
162
163 // Make sure that all the elements of isInRunningConfiguration are false.
164// assert(std::count(isInRunningConfiguration, isInRunningConfiguration+nConsidered, true)==0);
165
166 // Start the cluster search!
167 findClusterStartingFrom(1, theLeadingParticle->getZ());
168
169 // Again, make sure that all the elements of isInRunningConfiguration have
170 // been reset to false. This is a sanity check.
171// assert(std::count(isInRunningConfiguration, isInRunningConfiguration+nConsidered, true)==0);
172
173 Cluster *chosenCluster = 0;
174 if(selectedA!=0) { // A cluster was found!
175 candidateConfiguration[selectedA-1] = theLeadingParticle;
176 chosenCluster = new Cluster(candidateConfiguration,
177 candidateConfiguration + selectedA);
178 }
179
180 // Restore the original position of the leading particle
181 theLeadingParticle->setPosition(oldLeadingParticlePosition);
182
183 return chosenCluster;
184 }
185
186 inline G4double ClusteringModelIntercomparison::getPhaseSpace(const G4int oldA, Particle const * const p) {
187 const G4double psSpace = (p->getPosition() - runningPositions[oldA]).mag2();
188 const G4double psMomentum = (p->getMomentum()*oldA - runningMomenta[oldA]).mag2();
189 return psSpace * psMomentum * ParticleTable::clusterPosFact2[oldA + 1];
190 }
191
192 void ClusteringModelIntercomparison::findClusterStartingFrom(const G4int oldA, const G4int oldZ) {
193 const G4int newA = oldA + 1;
194 const G4int oldAMinusOne = oldA - 1;
195 G4int newZ;
196 G4int newN;
197
198 // Look up the phase-space cut
199 const G4double phaseSpaceCut = ParticleTable::clusterPhaseSpaceCut[newA];
200
201 // Configuration caching enabled only for a certain mass interval
202 const G4bool cachingEnabled = (newA<=maxMassConfigurationSkipping && newA>=3);
203
204 // Set the pointer to the container of cached configurations
205#if defined(INCL_CACHING_CLUSTERING_MODEL_INTERCOMPARISON_HashMask)
206 HashContainer *theHashContainer;
207 if(cachingEnabled)
208 theHashContainer = &(checkedConfigurations[oldA-2]);
209 else
210 theHashContainer = NULL;
211#elif defined(INCL_CACHING_CLUSTERING_MODEL_INTERCOMPARISON_Set)
212 SortedNucleonConfigurationContainer *theConfigContainer;
213 if(cachingEnabled)
214 theConfigContainer = &(checkedConfigurations[oldA-2]);
215 else
216 theConfigContainer = NULL;
217#else
218#error Unrecognized INCL_CACHING_CLUSTERING_MODEL_INTERCOMPARISON. Allowed values are: Set, HashMask.
219#endif
220
221 // Minimum and maximum Z values for this mass
222 const G4int ZMinForNewA = ParticleTable::clusterZMin[newA];
223 const G4int ZMaxForNewA = ParticleTable::clusterZMax[newA];
224
225 for(G4int i=0; i<nConsidered; ++i) {
226 // Only accept particles that are not already part of the cluster
227 if(isInRunningConfiguration[i]) continue;
228
229 Particle * const candidateNucleon = consideredPartners[i];
230
231 // Z and A of the new cluster
232 newZ = oldZ + candidateNucleon->getZ();
233 newN = newA - newZ;
234
235 // Skip this nucleon if we already have too many protons or neutrons
236 if(newZ > clusterZMaxAll || newN > clusterNMaxAll)
237 continue;
238
239 // Compute the phase space factor for a new cluster which
240 // consists of the previous running cluster and the new
241 // candidate nucleon:
242 const G4double phaseSpace = getPhaseSpace(oldA, candidateNucleon);
243 if(phaseSpace > phaseSpaceCut) continue;
244
245 // Store the candidate nucleon in the running configuration
246 runningConfiguration[oldAMinusOne] = i;
247#if defined(INCL_CACHING_CLUSTERING_MODEL_INTERCOMPARISON_HashMask)
248 Hashing::HashType configHash;
249 HashIterator aHashIter;
250#elif defined(INCL_CACHING_CLUSTERING_MODEL_INTERCOMPARISON_Set)
251 SortedNucleonConfiguration thisConfig;
252 SortedNucleonConfigurationIterator thisConfigIter;
253#endif
254 if(cachingEnabled) {
255#if defined(INCL_CACHING_CLUSTERING_MODEL_INTERCOMPARISON_HashMask)
256 configHash = Hashing::hashConfig(runningConfiguration, oldA);
257 aHashIter = theHashContainer->lower_bound(configHash);
258 // If we have already checked this configuration, skip it
259 if(aHashIter!=theHashContainer->end()
260 && !(configHash < *aHashIter))
261 continue;
262#elif defined(INCL_CACHING_CLUSTERING_MODEL_INTERCOMPARISON_Set)
263 thisConfig.fill(runningConfiguration,oldA);
264 thisConfigIter = theConfigContainer->lower_bound(thisConfig);
265 // If we have already checked this configuration, skip it
266 if(thisConfigIter!=theConfigContainer->end()
267 && !(thisConfig < *thisConfigIter))
268 continue;
269#endif
270 }
271
272 // Sum of the total energies of the cluster components
273 runningEnergies[newA] = runningEnergies[oldA] + candidateNucleon->getEnergy();
274 // Sum of the potential energies of the cluster components
275 runningPotentials[newA] = runningPotentials[oldA] + candidateNucleon->getPotentialEnergy();
276
277 // Update the available cascading kinetic energy
278 G4double oldCascadingEnergyPool = cascadingEnergyPool;
279 if(!candidateNucleon->isTargetSpectator())
280 cascadingEnergyPool -= candidateNucleon->getEnergy() - candidateNucleon->getPotentialEnergy() - 931.3;
281
282 // Check an approximate Coulomb barrier. If the cluster is below
283 // 0.5*barrier and the remaining available energy from cascading nucleons
284 // will not bring it above, reject the cluster.
285 const G4double halfB = 0.72 * newZ *
286 theNucleus->getZ()/(theNucleus->getDensity()->getNuclearRadius()+1.7);
287 const G4double tout = runningEnergies[newA] - runningPotentials[newA] -
288 931.3*newA;
289 if(tout<=halfB && tout+cascadingEnergyPool<=halfB) {
290 cascadingEnergyPool = oldCascadingEnergyPool;
291 continue;
292 }
293
294 // Here the nucleon has passed all the tests. Accept it in the cluster.
295 runningPositions[newA] = (runningPositions[oldA] * oldA + candidateNucleon->getPosition())*ParticleTable::clusterPosFact[newA];
296 runningMomenta[newA] = runningMomenta[oldA] + candidateNucleon->getMomentum();
297
298 // Add the config to the container
299 if(cachingEnabled)
300#if defined(INCL_CACHING_CLUSTERING_MODEL_INTERCOMPARISON_HashMask)
301 theHashContainer->insert(aHashIter, configHash);
302#elif defined(INCL_CACHING_CLUSTERING_MODEL_INTERCOMPARISON_Set)
303 theConfigContainer->insert(thisConfigIter, thisConfig);
304#endif
305
306 // Set the flag that reminds us that this nucleon has already been taken
307 // in the running configuration
308 isInRunningConfiguration[i] = true;
309
310 // Keep track of the best physical cluster
311 if(newZ >= ZMinForNewA && newZ <= ZMaxForNewA) {
312 // Note: sqc is real kinetic energy, not the square of the kinetic energy!
313 const G4double sqc = KinematicsUtils::invariantMass(runningEnergies[newA],
314 runningMomenta[newA]);
315 const G4double sqct = (sqc - 2.*newZ*protonMass - 2.*(newA-newZ)*neutronMass
316 + ParticleTable::getRealMass(newA, newZ))
318
319 if(sqct < sqtot) {
320 // This is the best cluster we have found so far. Store its
321 // kinematics.
322 sqtot = sqct;
323 selectedA = newA;
324 selectedZ = newZ;
325
326 // Store the running configuration in a ParticleList
327 for(G4int j=0; j<oldA; ++j)
328 candidateConfiguration[j] = consideredPartners[runningConfiguration[j]];
329
330 // Sanity check on number of nucleons in running configuration
331// assert(std::count(isInRunningConfiguration, isInRunningConfiguration+nConsidered, true)==selectedA-1);
332 }
333 }
334
335 // The method recursively calls itself for the next mass
336 if(newA < runningMaxClusterAlgorithmMass && newA+1 < theNucleus->getA()) {
337 findClusterStartingFrom(newA, newZ);
338 }
339
340 // Reset the running configuration flag and the cascading energy pool
341 isInRunningConfiguration[i] = false;
342 cascadingEnergyPool = oldCascadingEnergyPool;
343 }
344 }
345
347 // Forbid emission of the whole nucleus
348 if(c->getA()>=n->getA())
349 return false;
350
351 // Check the escape angle of the cluster
352 const ThreeVector &pos = c->getPosition();
353 const ThreeVector &mom = c->getMomentum();
354 const G4double cosEscapeAngle = pos.dot(mom) / std::sqrt(pos.mag2()*mom.mag2());
355 if(cosEscapeAngle < limitCosEscapeAngle)
356 return false;
357
358 return true;
359 }
360
361}
Functions for hashing a collection of NucleonItems.
double G4double
Definition: G4Types.hh:64
int G4int
Definition: G4Types.hh:66
bool G4bool
Definition: G4Types.hh:67
virtual G4bool clusterCanEscape(Nucleus const *const, Cluster const *const)
virtual Cluster * getCluster(Nucleus *, Particle *)
G4int getClusterMaxMass() const
Get the maximum mass for production of clusters.
static G4double invariantMass(const G4double E, const ThreeVector &p)
Store * getStore() const
NuclearDensity * getDensity() const
Getter for theDensity.
G4double getUniverseRadius() const
Getter for theUniverseRadius.
static const G4double clusterPosFact2[maxClusterMass+1]
static const G4int clusterZMin[maxClusterMass+1]
static const G4double clusterPosFact[maxClusterMass+1]
static G4double getRealMass(const G4INCL::ParticleType t)
Get particle mass (in MeV/c^2)
static const G4double clusterPhaseSpaceCut[maxClusterMass+1]
static const G4int clusterZMax[maxClusterMass+1]
G4double getEnergy() const
G4double getPotentialEnergy() const
Get the particle potential energy.
G4int getZ() const
Returns the charge number.
const G4INCL::ThreeVector & getPosition() const
const G4INCL::ThreeVector & getMomentum() const
virtual void setPosition(const G4INCL::ThreeVector &position)
long getID() const
G4int getA() const
Returns the baryon number.
ParticleList const & getParticles() const
Definition: G4INCLStore.hh:237
Config const * getConfig()
Definition: G4INCLStore.hh:257
G4double mag() const
G4double dot(const ThreeVector &v) const
G4double mag2() const
std::list< G4INCL::Particle * > ParticleList
std::list< G4INCL::Particle * >::const_iterator ParticleIter