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