Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4INCLClusterDecay.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 
44 #include "G4INCLClusterDecay.hh"
45 #include "G4INCLParticleTable.hh"
46 #include "G4INCLKinematicsUtils.hh"
47 #include "G4INCLRandom.hh"
48 // #include <cassert>
49 #include <algorithm>
50 
51 namespace G4INCL {
52 
54  ParticleList decayProducts;
55  recursiveDecay(c, &decayProducts);
56 
57  // Correctly update the particle type
58  if(c->getA()==1) {
59 // assert(c->getZ()==1 || c->getZ()==0);
60  if(c->getZ()==1)
61  c->setType(Proton);
62  else
63  c->setType(Neutron);
64  c->setTableMass();
65  }
66 
67  return decayProducts;
68  }
69 
70  void ClusterDecay::recursiveDecay(Cluster * const c, ParticleList *decayProducts) {
71  const G4int Z = c->getZ();
72  const G4int A = c->getA();
73 // assert(c->getExcitationEnergy()>-1.e-5);
74  if(c->getExcitationEnergy()<0.)
75  c->setExcitationEnergy(0.);
76 
79 
80  switch(theDecayMode) {
81  default:
82  ERROR("Unrecognized cluster-decay mode: " << theDecayMode << std::endl
83  << c->print());
85  // For stable clusters, just return
86  return;
87  break;
91  // Two-body decays
92  twoBodyDecay(c, theDecayMode, decayProducts);
93  break;
96  // Three-body decays
97  threeBodyDecay(c, theDecayMode, decayProducts);
98  break;
101  // Phase-space decays
102  phaseSpaceDecay(c, theDecayMode, decayProducts);
103  break;
104  }
105 
106  // Calls itself recursively in case the produced remnant is still unstable.
107  // Sneaky, isn't it.
108  recursiveDecay(c,decayProducts);
109 
110  } else {
111  // The cluster is too large for our decay-mode table. Decompose it only
112  // if Z==0 || Z==A.
113  DEBUG("Cluster is outside the decay-mode table." << c->print() << std::endl);
114  if(Z==A) {
115  DEBUG("Z==A, will decompose it in free protons." << std::endl);
116  phaseSpaceDecay(c, ParticleTable::ProtonUnbound, decayProducts);
117  } else if(Z==0) {
118  DEBUG("Z==0, will decompose it in free neutrons." << std::endl);
119  phaseSpaceDecay(c, ParticleTable::NeutronUnbound, decayProducts);
120  }
121  }
122  }
123 
124  void ClusterDecay::twoBodyDecay(Cluster * const c, ParticleTable::ClusterDecayType theDecayMode, ParticleList *decayProducts) {
125  Particle *decayParticle = 0;
126  const ThreeVector mom(0.0, 0.0, 0.0);
127  const ThreeVector pos = c->getPosition();
128 
129  // Create the emitted particle
130  switch(theDecayMode) {
132  decayParticle = new Particle(Proton, mom, pos);
133  break;
135  decayParticle = new Particle(Neutron, mom, pos);
136  break;
138  decayParticle = new Cluster(2,4);
139  break;
140  default:
141  ERROR("Unrecognized cluster-decay mode in two-body decay: " << theDecayMode << std::endl
142  << c->print());
143  return;
144  }
145  decayParticle->makeParticipant();
146  decayParticle->setNumberOfDecays(1);
147  decayParticle->setPosition(c->getPosition());
148  decayParticle->setEmissionTime(c->getEmissionTime());
149  decayParticle->setTableMass();
150 
151  // Save some variables of the mother cluster
152  G4double motherMass = c->getMass();
153  const ThreeVector velocity = -c->boostVector();
154 
155  // Characteristics of the daughter particle
156  const G4int daughterZ = c->getZ() - decayParticle->getZ();
157  const G4int daughterA = c->getA() - decayParticle->getA();
158  const G4double daughterMass = ParticleTable::getTableMass(daughterA,daughterZ);
159 
160  // The mother cluster becomes the daughter
161  c->setZ(daughterZ);
162  c->setA(daughterA);
163  c->setMass(daughterMass);
164  c->setExcitationEnergy(0.);
165 
166  // Decay kinematics in the mother rest frame
167  const G4double decayMass = decayParticle->getMass();
168 // assert(motherMass-daughterMass-decayMass>-1.e-5); // Q-value should be >0
169  G4double pCM = 0.;
170  if(motherMass-daughterMass-decayMass>0.)
171  pCM = KinematicsUtils::momentumInCM(motherMass, daughterMass, decayMass);
172  const ThreeVector momentum = Random::normVector(pCM);
173  c->setMomentum(momentum);
174  c->adjustEnergyFromMomentum();
175  decayParticle->setMomentum(-momentum);
176  decayParticle->adjustEnergyFromMomentum();
177 
178  // Boost to the lab frame
179  decayParticle->boost(velocity);
180  c->boost(velocity);
181 
182  // Add the decay particle to the list of decay products
183  decayProducts->push_back(decayParticle);
184  }
185 
186  void ClusterDecay::threeBodyDecay(Cluster * const c, ParticleTable::ClusterDecayType theDecayMode, ParticleList *decayProducts) {
187  Particle *decayParticle1 = 0;
188  Particle *decayParticle2 = 0;
189  const ThreeVector mom(0.0, 0.0, 0.0);
190  const ThreeVector pos = c->getPosition();
191 
192  // Create the emitted particles
193  switch(theDecayMode) {
195  decayParticle1 = new Particle(Proton, mom, pos);
196  decayParticle2 = new Particle(Proton, mom, pos);
197  break;
199  decayParticle1 = new Particle(Neutron, mom, pos);
200  decayParticle2 = new Particle(Neutron, mom, pos);
201  break;
202  default:
203  ERROR("Unrecognized cluster-decay mode in three-body decay: " << theDecayMode << std::endl
204  << c->print());
205  return;
206  }
207  decayParticle1->makeParticipant();
208  decayParticle2->makeParticipant();
209  decayParticle1->setNumberOfDecays(1);
210  decayParticle2->setNumberOfDecays(1);
211  decayParticle1->setTableMass();
212  decayParticle2->setTableMass();
213 
214  // Save some variables of the mother cluster
215  const G4double motherMass = c->getMass();
216  const ThreeVector velocity = -c->boostVector();
217 
218  // Masses and charges of the daughter particle and of the decay products
219  const G4int decayZ1 = decayParticle1->getZ();
220  const G4int decayA1 = decayParticle1->getA();
221  const G4int decayZ2 = decayParticle2->getZ();
222  const G4int decayA2 = decayParticle2->getA();
223  const G4int decayZ = decayZ1 + decayZ2;
224  const G4int decayA = decayA1 + decayA2;
225  const G4int daughterZ = c->getZ() - decayZ;
226  const G4int daughterA = c->getA() - decayA;
227  const G4double decayMass1 = decayParticle1->getMass();
228  const G4double decayMass2 = decayParticle2->getMass();
229  const G4double daughterMass = ParticleTable::getTableMass(daughterA,daughterZ);
230 
231  // Q-values
232  G4double qValue = motherMass - daughterMass - decayMass1 - decayMass2;
233 // assert(qValue > -1e-5); // Q-value should be >0
234  if(qValue<0.)
235  qValue=0.;
236  const G4double qValueB = qValue * Random::shoot();
237 
238  // The decay particles behave as if they had more mass until the second
239  // decay
240  const G4double decayMass = decayMass1 + decayMass2 + qValueB;
241 
242  /* Stage A: mother --> daughter + (decay1+decay2) */
243 
244  // The mother cluster becomes the daughter
245  c->setZ(daughterZ);
246  c->setA(daughterA);
247  c->setMass(daughterMass);
248  c->setExcitationEnergy(0.);
249 
250  // Decay kinematics in the mother rest frame
251  const G4double pCMA = KinematicsUtils::momentumInCM(motherMass, daughterMass, decayMass);
252  const ThreeVector momentumA = Random::normVector(pCMA);
253  c->setMomentum(momentumA);
254  c->adjustEnergyFromMomentum();
255  const ThreeVector decayBoostVector = momentumA/std::sqrt(decayMass*decayMass + momentumA.mag2());
256 
257  /* Stage B: (decay1+decay2) --> decay1 + decay2 */
258 
259  // Decay kinematics in the (decay1+decay2) rest frame
260  const G4double pCMB = KinematicsUtils::momentumInCM(decayMass, decayMass1, decayMass2);
261  const ThreeVector momentumB = Random::normVector(pCMB);
262  decayParticle1->setMomentum(momentumB);
263  decayParticle2->setMomentum(-momentumB);
264  decayParticle1->adjustEnergyFromMomentum();
265  decayParticle2->adjustEnergyFromMomentum();
266 
267  // Boost decay1 and decay2 to the Stage-A decay frame
268  decayParticle1->boost(decayBoostVector);
269  decayParticle2->boost(decayBoostVector);
270 
271  // Boost all particles to the lab frame
272  decayParticle1->boost(velocity);
273  decayParticle2->boost(velocity);
274  c->boost(velocity);
275 
276  // Add the decay particles to the list of decay products
277  decayProducts->push_back(decayParticle1);
278  decayProducts->push_back(decayParticle2);
279  }
280 
281  void ClusterDecay::phaseSpaceDecay(Cluster * const c, ParticleTable::ClusterDecayType theDecayMode, ParticleList *decayProducts) {
282  const G4int theA = c->getA();
283  const G4int theZ = c->getZ();
284  const ThreeVector mom(0.0, 0.0, 0.0);
285  const ThreeVector pos = c->getPosition();
286 
287  G4int theZStep;
288  ParticleType theEjectileType;
289  switch(theDecayMode) {
291  theZStep = 1;
292  theEjectileType = Proton;
293  break;
295  theZStep = 0;
296  theEjectileType = Neutron;
297  break;
298  default:
299  ERROR("Unrecognized cluster-decay mode in phase-space decay: " << theDecayMode << std::endl
300  << c->print());
301  return;
302  }
303 
304  // Find the daughter cluster (first cluster which is not
305  // proton/neutron-unbound, in the sense of the table)
306  G4int finalDaughterZ, finalDaughterA;
308  finalDaughterZ=theZ;
309  finalDaughterA=theA;
310  while(ParticleTable::clusterDecayMode[finalDaughterZ][finalDaughterA]==theDecayMode) {
311  finalDaughterA--;
312  finalDaughterZ -= theZStep;
313  }
314  } else {
315  finalDaughterA = 1;
316  if(theDecayMode==ParticleTable::ProtonUnbound)
317  finalDaughterZ = 1;
318  else
319  finalDaughterZ = 0;
320  }
321 // assert(finalDaughterZ<=theZ && finalDaughterA<theA && finalDaughterA>0 && finalDaughterZ>=0);
322  const G4double finalDaughterMass = ParticleTable::getTableMass(finalDaughterA, finalDaughterZ);
323 
324  // Compute the available decay energy
325  const G4int nSplits = theA-finalDaughterA;
326  const G4double ejectileMass = ParticleTable::getTableMass(1, theZStep);
327  // c->getMass() can possibly contain some excitation energy, too
328  G4double availableEnergy = c->getMass() - finalDaughterMass - nSplits*ejectileMass;
329 // assert(availableEnergy>-1.e-5);
330  if(availableEnergy<0.)
331  availableEnergy=0.;
332 
333  // Compute an estimate of the maximum event weight
334  G4double maximumWeight = 1.;
335  G4double eMax = finalDaughterMass + availableEnergy;
336  G4double eMin = finalDaughterMass - ejectileMass;
337  for(G4int iSplit=0; iSplit<nSplits; ++iSplit) {
338  eMax += ejectileMass;
339  eMin += ejectileMass;
340  maximumWeight *= KinematicsUtils::momentumInCM(eMax, eMin, ejectileMass);
341  }
342 
343  // Sample decays until the weight cutoff is satisfied
345  std::vector<G4double> theCMMomenta;
346  std::vector<G4double> invariantMasses;
347  G4int nTries=0;
348  /* Maximum number of trials dependent on nSplits. 50 trials seems to be
349  * sufficient for small nSplits. For nSplits>=5, maximumWeight is a gross
350  * overestimate of the actual maximum weight, leading to unreasonably high
351  * rejection rates. For these cases, we set nSplits=1000, although the sane
352  * thing to do would be to improve the importance sampling (maybe by
353  * parametrising maximumWeight?).
354  */
355  G4int maxTries;
356  if(nSplits<5)
357  maxTries=50;
358  else
359  maxTries=1000;
360  do {
361  if(nTries++>maxTries) {
362  WARN("Phase-space decay exceeded the maximum number of rejections (" << maxTries
363  << "). Z=" << theZ << ", A=" << theA << ", E*=" << c->getExcitationEnergy()
364  << ", availableEnergy=" << availableEnergy
365  << ", nSplits=" << nSplits
366  << std::endl);
367  break;
368  }
369 
370  // Construct a sorted vector of random numbers
371  std::vector<G4double> randomNumbers;
372  for(G4int iSplit=0; iSplit<nSplits-1; ++iSplit)
373  randomNumbers.push_back(Random::shoot0());
374  std::sort(randomNumbers.begin(), randomNumbers.end());
375 
376  // Divide the available decay energy in the right number of steps
377  invariantMasses.clear();
378  invariantMasses.push_back(finalDaughterMass);
379  for(G4int iSplit=0; iSplit<nSplits-1; ++iSplit)
380  invariantMasses.push_back(finalDaughterMass + (iSplit+1)*ejectileMass + randomNumbers.at(iSplit)*availableEnergy);
381  invariantMasses.push_back(c->getMass());
382 
383  weight = 1.;
384  theCMMomenta.clear();
385  for(G4int iSplit=0; iSplit<nSplits; ++iSplit) {
386  G4double motherMass = invariantMasses.at(nSplits-iSplit);
387  const G4double daughterMass = invariantMasses.at(nSplits-iSplit-1);
388 // assert(motherMass-daughterMass-ejectileMass>-1.e-5);
389  G4double pCM = 0.;
390  if(motherMass-daughterMass-ejectileMass>0.)
391  pCM = KinematicsUtils::momentumInCM(motherMass, daughterMass, ejectileMass);
392  theCMMomenta.push_back(pCM);
393  weight *= pCM;
394  }
395  } while(maximumWeight*Random::shoot()>weight);
396 
397  for(G4int iSplit=0; iSplit<nSplits; ++iSplit) {
398  ThreeVector const velocity = -c->boostVector();
399 
400 #if !defined(NDEBUG) && !defined(INCLXX_IN_GEANT4_MODE)
401  const G4double motherMass = c->getMass();
402 #endif
403  c->setA(c->getA() - 1);
404  c->setZ(c->getZ() - theZStep);
405  c->setMass(invariantMasses.at(nSplits-iSplit-1));
406 
407  Particle *ejectile = new Particle(theEjectileType, mom, pos);
408  ejectile->setTableMass();
409 
410 // assert(motherMass-c->getMass()-ejectileMass>-1.e-5);
411  ThreeVector momentum;
412  momentum = Random::normVector(theCMMomenta.at(iSplit));
413  c->setMomentum(momentum);
414  c->adjustEnergyFromMomentum();
415  ejectile->setMomentum(-momentum);
416  ejectile->adjustEnergyFromMomentum();
417 
418  // Boost to the lab frame
419  c->boost(velocity);
420  ejectile->boost(velocity);
421 
422  // Add the decay particle to the list of decay products
423  decayProducts->push_back(ejectile);
424  }
425 // assert(std::abs(c->getTableMass()-c->getMass())<1.e-3);
426  c->setExcitationEnergy(0.);
427  }
428 }
429