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