Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
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