Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4IntraNucleiCascader.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 // $Id$
27 //
28 // 20100114 M. Kelsey -- Remove G4CascadeMomentum, use G4LorentzVector directly
29 // 20100307 M. Kelsey -- Bug fix: momentum_out[0] should be momentum_out.e()
30 // 20100309 M. Kelsey -- Eliminate some unnecessary std::pow()
31 // 20100407 M. Kelsey -- Pass "all_particles" as argument to initializeCascad,
32 // following recent change to G4NucleiModel.
33 // 20100413 M. Kelsey -- Pass G4CollisionOutput by ref to ::collide()
34 // 20100517 M. Kelsey -- Inherit from common base class, make other colliders
35 // simple data members
36 // 20100616 M. Kelsey -- Add reporting of final residual particle
37 // 20100617 M. Kelsey -- Remove "RUN" preprocessor flag and all "#else" code,
38 // pass verbosity to collider. Make G4NucleiModel a data member,
39 // instead of creating and deleting on every cycle.
40 // 20100620 M. Kelsey -- Improved diagnostic messages. Simplify kinematics
41 // of recoil nucleus.
42 // 20100622 M. Kelsey -- Use local "bindingEnergy()" to call through.
43 // 20100623 M. Kelsey -- Undo G4NucleiModel change from 0617. Does not work
44 // properly across multiple interactions.
45 // 20100627 M. Kelsey -- Protect recoil nucleus energy from floating roundoff
46 // by setting small +ve or -ve values to zero.
47 // 20100701 M. Kelsey -- Let excitation energy be handled by G4InuclNuclei,
48 // allow for ground-state recoil (goodCase == true for Eex==0.)
49 // 20100702 M. Kelsey -- Negative energy recoil should be rejected
50 // 20100706 D. Wright -- Copy "abandoned" cparticles to output list, copy
51 // mesonic "excitons" to output list; should be absorbed, fix up
52 // diagnostic messages.
53 // 20100713 M. Kelsey -- Add more diagnostics for Dennis' changes.
54 // 20100714 M. Kelsey -- Switch to new G4CascadeColliderBase class, remove
55 // sanity check on afin/zfin (not valid).
56 // 20100715 M. Kelsey -- Add diagnostic for ekin_in vs. actual ekin; reduce
57 // KE across Coulomb barrier. Rearrange end-of-loop if blocks,
58 // add conservation check at end.
59 // 20100716 M. Kelsey -- Eliminate inter_case; use base-class functionality.
60 // Add minimum-fragment requirement for recoil, in order to
61 // allow for momentum balancing
62 // 20100720 M. Kelsey -- Make EPCollider pointer member
63 // 20100721 M. Kelsey -- Turn on conservation checks unconditionally (override
64 // new G4CASCADE_CHECK_ECONS setting
65 // 20100722 M. Kelsey -- Move cascade output buffers to .hh file
66 // 20100728 M. Kelsey -- Make G4NucleiModel data member for persistence,
67 // delete colliders in destructor
68 // 20100906 M. Kelsey -- Hide "non-physical fragment" behind verbose flag
69 // 20100907 M. Kelsey -- Add makeResidualFragment function to create object
70 // 20100909 M. Kelsey -- Remove all local "fragment" stuff, use RecoilMaker.
71 // move goodCase() to RecoilMaker.
72 // 20100910 M. Kelsey -- Use RecoilMaker::makeRecoilFragment().
73 // 20100915 M. Kelsey -- Define functions to deal with trapped particles,
74 // move the exciton container to a data member
75 // 20100916 M. Kelsey -- Put decay photons directly onto output list
76 // 20100921 M. Kelsey -- Migrate to RecoilMaker::makeRecoilNuclei().
77 // 20100924 M. Kelsey -- Minor shuffling of post-cascade recoil building.
78 // Create G4Fragment for recoil and store in output.
79 // 20110131 M. Kelsey -- Move "momentum_in" calculation inside verbosity
80 // 20110214 M. Kelsey -- Follow G4InuclParticle::Model enumerator migration
81 // 20110224 M. Kelsey -- Add ::rescatter() function which takes a list of
82 // pre-existing secondaries as input. Split ::collide() into
83 // separate utility functions. Move cascade parameters to static
84 // data members. Add setVerboseLevel().
85 // 20110302 M. Kelsey -- Move G4NucleiModel::printModel() call to G4NucleiModel
86 // 20110303 M. Kelsey -- Add more cascade functions to support rescattering
87 // 20110304 M. Kelsey -- Get original Propagate() arguments here in rescatter()
88 // and convert to particles, nuclei and G4NucleiModel state.
89 // 20110308 M. Kelsey -- Don't put recoiling fragment onto output list any more
90 // 20110308 M. Kelsey -- Decay unstable hadrons from pre-cascade, use daughters
91 // 20110324 M. Kelsey -- Get locations of hit nuclei in ::rescatter(), pass
92 // to G4NucleiModel::reset().
93 // 20110404 M. Kelsey -- Reduce maximum number of retries to 100, reflection
94 // cut to 50.
95 // 20110721 M. Kelsey -- Put unusable pre-cascade particles directly on output,
96 // do not decay.
97 // 20110722 M. Kelsey -- Deprecate "output_particles" list in favor of using
98 // output directly (will help with pre-cascade issues).
99 // 20110801 M. Kelsey -- Use G4Inucl(Particle)::fill() functions to reduce
100 // creation of temporaries. Add local target buffer for
101 // rescattering, to avoid memory leak.
102 // 20110808 M. Kelsey -- Pass buffer to generateParticleFate() to avoid copy
103 // 20110919 M. Kelsey -- Add optional final-state clustering, controlled (for
104 // now) with compiler flag G4CASCADE_DO_COALESCENCE
105 // 20110922 M. Kelsey -- Follow migrations G4InuclParticle::print(ostream&)
106 // and G4CascadParticle::print(ostream&); drop Q,B printing
107 // 20110926 M. Kelsey -- Replace compiler flag with one-time envvar in ctor
108 // for final-state clustering.
109 // 20111003 M. Kelsey -- Prepare for gamma-N interactions by checking for
110 // final-state tables instead of particle "isPhoton()"
111 // 20120521 A. Ribon -- Specify mass when decay trapped particle.
112 // 20120822 M. Kelsey -- Move envvars to G4CascadeParameters.
113 
114 #include <algorithm>
115 
116 #include "G4IntraNucleiCascader.hh"
117 #include "G4SystemOfUnits.hh"
118 #include "G4CascadeChannelTables.hh"
119 #include "G4CascadeCoalescence.hh"
120 #include "G4CascadeParameters.hh"
121 #include "G4CascadeRecoilMaker.hh"
122 #include "G4CascadParticle.hh"
123 #include "G4CollisionOutput.hh"
124 #include "G4DecayProducts.hh"
125 #include "G4DecayTable.hh"
127 #include "G4ExitonConfiguration.hh"
128 #include "G4HadTmpUtil.hh"
130 #include "G4InuclNuclei.hh"
131 #include "G4InuclParticleNames.hh"
133 #include "G4KineticTrack.hh"
134 #include "G4KineticTrackVector.hh"
135 #include "G4LorentzConvertor.hh"
136 #include "G4Neutron.hh"
137 #include "G4NucleiModel.hh"
138 #include "G4ParticleLargerEkin.hh"
139 #include "G4Proton.hh"
140 #include "G4V3DNucleus.hh"
141 #include "Randomize.hh"
142 
143 using namespace G4InuclParticleNames;
144 using namespace G4InuclSpecialFunctions;
145 
146 
147 // Configuration parameters for cascade production
148 const G4int G4IntraNucleiCascader::itry_max = 100;
149 const G4int G4IntraNucleiCascader::reflection_cut = 50;
150 const G4double G4IntraNucleiCascader::small_ekin = 0.001*MeV;
151 const G4double G4IntraNucleiCascader::quasielast_cut = 1*MeV;
152 
153 
154 typedef std::vector<G4InuclElementaryParticle>::iterator particleIterator;
155 
157  : G4CascadeColliderBase("G4IntraNucleiCascader"), model(new G4NucleiModel),
158  theElementaryParticleCollider(new G4ElementaryParticleCollider),
159  theRecoilMaker(new G4CascadeRecoilMaker), theClusterMaker(0),
160  tnuclei(0), bnuclei(0), bparticle(0),
161  minimum_recoil_A(0.), coulombBarrier(0.),
162  nucleusTarget(new G4InuclNuclei),
163  protonTarget(new G4InuclElementaryParticle) {
165  theClusterMaker = new G4CascadeCoalescence;
166 }
167 
169  delete model;
170  delete theElementaryParticleCollider;
171  delete theRecoilMaker;
172  delete theClusterMaker;
173  delete nucleusTarget;
174  delete protonTarget;
175 }
176 
179  model->setVerboseLevel(verbose);
180  theElementaryParticleCollider->setVerboseLevel(verbose);
181  theRecoilMaker->setVerboseLevel(verbose);
182 }
183 
184 
185 
188  G4CollisionOutput& globalOutput) {
189  if (verboseLevel) G4cout << " >>> G4IntraNucleiCascader::collide " << G4endl;
190 
191  if (!initialize(bullet, target)) return; // Load buffers and drivers
192 
193  G4int itry = 0;
194  do {
195  newCascade(++itry);
196  setupCascade();
197  generateCascade();
198  } while (!finishCascade() && itry<itry_max);
199 
200  finalize(itry, bullet, target, globalOutput);
201 }
202 
203 // For use with Propagate to preload a set of secondaries
204 // FIXME: So far, we don't have any bullet information from Propagate!
205 
207  G4KineticTrackVector* theSecondaries,
208  G4V3DNucleus* theNucleus,
209  G4CollisionOutput& globalOutput) {
210  if (verboseLevel)
211  G4cout << " >>> G4IntraNucleiCascader::rescatter " << G4endl;
212 
213  G4InuclParticle* target = createTarget(theNucleus);
214  if (!initialize(bullet, target)) return; // Load buffers and drivers
215 
216  G4int itry = 0;
217  do {
218  newCascade(++itry);
219  preloadCascade(theNucleus, theSecondaries);
220  generateCascade();
221  } while (!finishCascade() && itry<itry_max);
222 
223  finalize(itry, bullet, target, globalOutput);
224 }
225 
226 
229  if (verboseLevel>1)
230  G4cout << " >>> G4IntraNucleiCascader::initialize " << G4endl;
231 
232  // Configure processing modules
233  theRecoilMaker->setTolerance(small_ekin);
234 
235  interCase.set(bullet,target); // Classify collision type
236 
237  if (verboseLevel > 3) {
238  G4cout << *interCase.getBullet() << G4endl
239  << *interCase.getTarget() << G4endl;
240  }
241 
242  // Bullet may be nucleus or simple particle
243  bnuclei = dynamic_cast<G4InuclNuclei*>(interCase.getBullet());
244  bparticle = dynamic_cast<G4InuclElementaryParticle*>(interCase.getBullet());
245 
246  if (!bnuclei && !bparticle) {
247  G4cerr << " G4IntraNucleiCascader: projectile is not a valid particle."
248  << G4endl;
249  return false;
250  }
251 
252  // Target _must_ be nucleus
253  tnuclei = dynamic_cast<G4InuclNuclei*>(interCase.getTarget());
254  if (!tnuclei) {
255  if (verboseLevel)
256  G4cerr << " Target is not a nucleus. Abandoning." << G4endl;
257  return false;
258  }
259 
260  model->generateModel(tnuclei);
261  coulombBarrier = 0.00126*tnuclei->getZ() / (1.+G4cbrt(tnuclei->getA()));
262 
263  // Energy/momentum conservation usually requires a recoiling nuclear fragment
264  // This cut will be increased on each "itry" if momentum could not balance.
265  minimum_recoil_A = 0.;
266 
267  if (verboseLevel > 3) {
268  G4LorentzVector momentum_in = bullet->getMomentum() + target->getMomentum();
269  G4cout << " intitial momentum E " << momentum_in.e() << " Px "
270  << momentum_in.x() << " Py " << momentum_in.y() << " Pz "
271  << momentum_in.z() << G4endl;
272  }
273 
274  return true;
275 }
276 
277 // Re-initialize buffers for new attempt at cascade
278 
280  if (verboseLevel > 1) {
281  G4cout << " IntraNucleiCascader itry " << itry << " inter_case "
282  << interCase.code() << G4endl;
283  }
284 
285  model->reset(); // Start new cascade process
286  output.reset();
287  new_cascad_particles.clear();
288  theExitonConfiguration.clear();
289 
290  cascad_particles.clear(); // List of initial secondaries
291 }
292 
293 
294 // Load initial cascade using nuclear-model calculations
295 
297  if (verboseLevel > 1)
298  G4cout << " >>> G4IntraNucleiCascader::setupCascade" << G4endl;
299 
300  if (interCase.hadNucleus()) { // particle with nuclei
301  if (verboseLevel > 3)
302  G4cout << " bparticle charge " << bparticle->getCharge()
303  << " baryon number " << bparticle->baryon() << G4endl;
304 
305  cascad_particles.push_back(model->initializeCascad(bparticle));
306  } else { // nuclei with nuclei
307  G4int ab = bnuclei->getA();
308  G4int zb = bnuclei->getZ();
309 
310  G4NucleiModel::modelLists all_particles; // Buffer to receive lists
311  model->initializeCascad(bnuclei, tnuclei, all_particles);
312 
313  cascad_particles = all_particles.first;
314  output.addOutgoingParticles(all_particles.second);
315 
316  if (cascad_particles.size() == 0) { // compound nuclei
317  G4int i;
318 
319  for (i = 0; i < ab; i++) {
320  G4int knd = i < zb ? 1 : 2;
321  theExitonConfiguration.incrementQP(knd);
322  };
323 
324  G4int ihn = G4int(2 * (ab-zb) * inuclRndm() + 0.5);
325  G4int ihz = G4int(2 * zb * inuclRndm() + 0.5);
326 
327  for (i = 0; i < ihn; i++) theExitonConfiguration.incrementHoles(2);
328  for (i = 0; i < ihz; i++) theExitonConfiguration.incrementHoles(1);
329  }
330  } // if (interCase ...
331 }
332 
333 
334 // Generate one possible cascade (all secondaries, etc.)
335 
337  if (verboseLevel>1) G4cout << " generateCascade " << G4endl;
338 
339  G4int iloop = 0;
340  while (!cascad_particles.empty() && !model->empty()) {
341  iloop++;
342 
343  if (verboseLevel > 2) {
344  G4cout << " Iteration " << iloop << ": Number of cparticles "
345  << cascad_particles.size() << " last one: \n"
346  << cascad_particles.back() << G4endl;
347  }
348 
349  model->generateParticleFate(cascad_particles.back(),
350  theElementaryParticleCollider,
351  new_cascad_particles);
352 
353  if (verboseLevel > 2) {
354  G4cout << " After generate fate: New particles "
355  << new_cascad_particles.size() << G4endl
356  << " Discarding last cparticle from list " << G4endl;
357  }
358 
359  cascad_particles.pop_back();
360 
361  // handle the result of a new step
362 
363  if (new_cascad_particles.size() == 1) { // last particle goes without interaction
364  const G4CascadParticle& currentCParticle = new_cascad_particles[0];
365 
366  if (model->stillInside(currentCParticle)) {
367  if (verboseLevel > 3)
368  G4cout << " particle still inside nucleus " << G4endl;
369 
370  if (currentCParticle.getNumberOfReflections() < reflection_cut &&
371  model->worthToPropagate(currentCParticle)) {
372  if (verboseLevel > 3) G4cout << " continue reflections " << G4endl;
373  cascad_particles.push_back(currentCParticle);
374  } else {
375  processTrappedParticle(currentCParticle);
376  } // reflection or exciton
377 
378  } else { // particle about to leave nucleus - check for Coulomb barrier
379  if (verboseLevel > 3) G4cout << " possible escape " << G4endl;
380 
381  const G4InuclElementaryParticle& currentParticle =
382  currentCParticle.getParticle();
383 
384  G4double KE = currentParticle.getKineticEnergy();
385  G4double mass = currentParticle.getMass();
386  G4double Q = currentParticle.getCharge();
387 
388  if (verboseLevel > 3)
389  G4cout << " KE " << KE << " barrier " << Q*coulombBarrier << G4endl;
390 
391  if (KE < Q*coulombBarrier) {
392  // Calculate barrier penetration
393  G4double CBP = 0.0;
394 
395  // if (KE > 0.0001) CBP = std::exp(-0.00126*tnuclei->getZ()*0.25*
396  // (1./KE - 1./coulombBarrier));
397  if (KE > 0.0001) CBP = std::exp(-0.0181*0.5*tnuclei->getZ()*
398  (1./KE - 1./coulombBarrier)*
399  std::sqrt(mass*(coulombBarrier-KE)) );
400 
401  if (G4UniformRand() < CBP) {
402  if (verboseLevel > 3)
403  G4cout << " tunneled\n" << currentParticle << G4endl;
404 
405  // Tunnelling through barrier leaves KE unchanged
406  output.addOutgoingParticle(currentParticle);
407  } else {
408  processTrappedParticle(currentCParticle);
409  }
410  } else {
411  output.addOutgoingParticle(currentParticle);
412 
413  if (verboseLevel > 3)
414  G4cout << " Goes out\n" << output.getOutgoingParticles().back()
415  << G4endl;
416  }
417  }
418  } else { // interaction
419  if (verboseLevel > 3)
420  G4cout << " interacted, adding new to list " << G4endl;
421 
422  cascad_particles.insert(cascad_particles.end(),
423  new_cascad_particles.begin(),
424  new_cascad_particles.end());
425 
426  std::pair<G4int, G4int> holes = model->getTypesOfNucleonsInvolved();
427  if (verboseLevel > 3)
428  G4cout << " adding new exciton holes " << holes.first << ","
429  << holes.second << G4endl;
430 
431  theExitonConfiguration.incrementHoles(holes.first);
432 
433  if (holes.second > 0)
434  theExitonConfiguration.incrementHoles(holes.second);
435  } // if (new_cascad_particles ...
436 
437  // Evaluate nuclear residue
438  theRecoilMaker->collide(interCase.getBullet(), interCase.getTarget(),
439  output, cascad_particles);
440 
441  G4double aresid = theRecoilMaker->getRecoilA();
442  if (verboseLevel > 2) {
443  G4cout << " cparticles remaining " << cascad_particles.size()
444  << " nucleus (model) has "
445  << model->getNumberOfNeutrons() << " n, "
446  << model->getNumberOfProtons() << " p "
447  << " residual fragment A " << aresid << G4endl;
448  }
449 
450  if (aresid <= minimum_recoil_A) return; // Must have minimum fragment
451  } // while cascade-list and model
452 }
453 
454 
455 // Conslidate results of cascade and evaluate success
456 
458  if (verboseLevel > 1)
459  G4cout << " >>> G4IntraNucleiCascader::finishCascade ?" << G4endl;
460 
461  // Add left-over cascade particles to output
462  output.addOutgoingParticles(cascad_particles);
463  cascad_particles.clear();
464 
465  // Cascade is finished. Check if it's OK.
466  if (verboseLevel>3) {
467  G4cout << " G4IntraNucleiCascader finished" << G4endl;
468  output.printCollisionOutput();
469  }
470 
471  // Apply cluster coalesence model to produce light ions
472  if (theClusterMaker) {
473  theClusterMaker->setVerboseLevel(verboseLevel);
474  theClusterMaker->FindClusters(output);
475 
476  // Update recoil fragment after generating light ions
477  if (verboseLevel>3) G4cout << " Recomputing recoil fragment" << G4endl;
478  theRecoilMaker->collide(interCase.getBullet(), interCase.getTarget(),
479  output);
480  if (verboseLevel>3) {
481  G4cout << " After cluster coalescence" << G4endl;
482  output.printCollisionOutput();
483  }
484  }
485 
486  // Use last created recoil fragment instead of re-constructing
487  G4int afin = theRecoilMaker->getRecoilA();
488  G4int zfin = theRecoilMaker->getRecoilZ();
489 
490  // FIXME: Should we deal with unbalanced (0,0) case before rejecting?
491 
492  // Sanity check before proceeding
493  if (!theRecoilMaker->goodFragment() && !theRecoilMaker->wholeEvent()) {
494  if (verboseLevel > 1)
495  G4cerr << " Recoil nucleus is not physical: A=" << afin << " Z="
496  << zfin << G4endl;
497  return false; // Discard event and try again
498  }
499 
500  const G4LorentzVector& presid = theRecoilMaker->getRecoilMomentum();
501 
502  if (verboseLevel > 1) {
503  G4cout << " afin " << afin << " zfin " << zfin << G4endl;
504  }
505 
506  if (afin == 0) return true; // Whole event fragmented, exit
507 
508  if (afin == 1) { // Add bare nucleon to particle list
509  G4int last_type = (zfin==1) ? 1 : 2; // proton=1, neutron=2
510 
512  G4double mres = presid.m();
513 
514  // Check for sensible kinematics
515  if (mres-mass < -small_ekin) { // Insufficient recoil energy
516  if (verboseLevel > 2) G4cerr << " unphysical recoil nucleon" << G4endl;
517  return false;
518  }
519 
520  if (mres-mass > small_ekin) { // Too much extra energy
521  if (verboseLevel > 2)
522  G4cerr << " extra energy with recoil nucleon" << G4endl;
523 
524  // FIXME: For now, we add the nucleon as unbalanced, and let
525  // "SetOnShell" fudge things. This should be abandoned.
526  }
527 
528  G4InuclElementaryParticle last_particle(presid, last_type,
530 
531  if (verboseLevel > 3) {
532  G4cout << " adding recoiling nucleon to output list\n"
533  << last_particle << G4endl;
534  }
535 
536  output.addOutgoingParticle(last_particle);
537 
538  // Update recoil to include residual nucleon
539  theRecoilMaker->collide(interCase.getBullet(), interCase.getTarget(),
540  output);
541  }
542 
543  // Process recoil fragment for consistency, exit or reject
544  if (output.numberOfOutgoingParticles() == 1) {
545  G4double Eex = theRecoilMaker->getRecoilExcitation();
546  if (std::abs(Eex) < quasielast_cut) {
547  if (verboseLevel > 3) {
548  G4cout << " quasi-elastic scatter with " << Eex << " MeV recoil"
549  << G4endl;
550  }
551 
552  theRecoilMaker->setRecoilExcitation(Eex=0.);
553  if (verboseLevel > 3) {
554  G4cout << " Eex reset to " << theRecoilMaker->getRecoilExcitation()
555  << G4endl;
556  }
557  }
558  }
559 
560  if (theRecoilMaker->goodNucleus()) {
561  theRecoilMaker->addExcitonConfiguration(theExitonConfiguration);
562 
563  G4Fragment* recoilFrag = theRecoilMaker->makeRecoilFragment();
564  if (!recoilFrag) {
565  G4cerr << "Got null pointer for recoil fragment!" << G4endl;
566  return false;
567  }
568 
569  if (verboseLevel > 2)
570  G4cout << " adding recoil fragment to output list" << G4endl;
571 
572  output.addRecoilFragment(*recoilFrag);
573  }
574 
575  // Put final-state particles in "leading order" for return
576  std::vector<G4InuclElementaryParticle>& opart = output.getOutgoingParticles();
577  std::sort(opart.begin(), opart.end(), G4ParticleLargerEkin());
578 
579  // Adjust final state to balance momentum and energy if necessary
580  if (theRecoilMaker->wholeEvent() || theRecoilMaker->goodNucleus()) {
583  output.setVerboseLevel(0);
584 
585  if (output.acceptable()) return true;
586  else if (verboseLevel>2) G4cerr << " Cascade setOnShell failed." << G4endl;
587  }
588 
589  // Cascade not physically reasonable
590  if (afin <= minimum_recoil_A && minimum_recoil_A < tnuclei->getA()) {
591  ++minimum_recoil_A;
592  if (verboseLevel > 3) {
593  G4cout << " minimum recoil fragment increased to A " << minimum_recoil_A
594  << G4endl;
595  }
596  }
597 
598  if (verboseLevel>2) G4cerr << " Cascade failed. Retrying..." << G4endl;
599  return false;
600 }
601 
602 
603 // Transfer finished cascade to return buffer
604 
605 void
608  G4CollisionOutput& globalOutput) {
609  if (itry >= itry_max) {
610  if (verboseLevel) {
611  G4cout << " IntraNucleiCascader-> no inelastic interaction after "
612  << itry << " attempts " << G4endl;
613  }
614 
615  output.trivialise(bullet, target);
616  } else if (verboseLevel) {
617  G4cout << " IntraNucleiCascader output after trials " << itry << G4endl;
618  }
619 
620  // Copy final generated cascade to output buffer for return
621  globalOutput.add(output);
622 }
623 
624 
625 // Create simple nucleus from rescattering target
626 
629  G4int theNucleusA = theNucleus->GetMassNumber();
630  G4int theNucleusZ = theNucleus->GetCharge();
631 
632  if (theNucleusA > 1) {
633  if (!nucleusTarget) nucleusTarget = new G4InuclNuclei; // Just in case
634  nucleusTarget->fill(0., theNucleusA, theNucleusZ, 0.);
635  return nucleusTarget;
636  } else {
637  if (!protonTarget) protonTarget = new G4InuclElementaryParticle;
638  protonTarget->fill(0., (theNucleusZ==1)?proton:neutron);
639  return protonTarget;
640  }
641 
642  return 0; // Can never actually get here
643 }
644 
645 // Copy existing (rescattering) cascade for propagation
646 
647 void
649  G4KineticTrackVector* theSecondaries) {
650  if (verboseLevel > 1)
651  G4cout << " >>> G4IntraNucleiCascader::preloadCascade" << G4endl;
652 
653  copyWoundedNucleus(theNucleus); // Update interacted nucleon counts
654  copySecondaries(theSecondaries); // Copy original to internal list
655 }
656 
658  if (verboseLevel > 1)
659  G4cout << " >>> G4IntraNucleiCascader::copyWoundedNucleus" << G4endl;
660 
661  // Loop over nucleons and count hits as exciton holes
662  theExitonConfiguration.clear();
663  hitNucleons.clear();
664  if (theNucleus->StartLoop()) {
665  G4Nucleon* nucl = 0;
666  G4int nuclType = 0;
667  while ((nucl = theNucleus->GetNextNucleon())) {
668  if (nucl->AreYouHit()) { // Found previously interacted nucleon
670  theExitonConfiguration.incrementHoles(nuclType);
671  hitNucleons.push_back(nucl->GetPosition());
672  }
673  }
674  }
675 
676  if (verboseLevel > 3)
677  G4cout << " nucleus has " << theExitonConfiguration.neutronHoles
678  << " neutrons hit, " << theExitonConfiguration.protonHoles
679  << " protons hit" << G4endl;
680 
681  // Preload nuclear model with confirmed hits, including locations
682  model->reset(theExitonConfiguration.neutronHoles,
683  theExitonConfiguration.protonHoles, &hitNucleons);
684 }
685 
686 void
688  if (verboseLevel > 1)
689  G4cout << " >>> G4IntraNucleiCascader::copySecondaries" << G4endl;
690 
691  for (size_t i=0; i<secondaries->size(); i++) {
692  if (verboseLevel > 3) G4cout << " processing secondary " << i << G4endl;
693 
694  processSecondary((*secondaries)[i]); // Copy to cascade or to output
695  }
696 
697  // Sort list of secondaries to put leading particle first
698  std::sort(cascad_particles.begin(), cascad_particles.end(),
700 
701  if (verboseLevel > 2) {
702  G4cout << " Original list of " << secondaries->size() << " secondaries"
703  << " produced " << cascad_particles.size() << " cascade, "
704  << output.numberOfOutgoingParticles() << " released particles, "
705  << output.numberOfOutgoingNuclei() << " fragments" << G4endl;
706  }
707 }
708 
709 
710 // Convert from pre-cascade secondary to local version
711 
713  if (!ktrack) return; // Sanity check
714 
715  // Get particle type to determine whether to keep or release
716  G4ParticleDefinition* kpd = ktrack->GetDefinition();
717  if (!kpd) return;
718 
720  if (!ktype) {
721  releaseSecondary(ktrack);
722  return;
723  }
724 
725  if (verboseLevel > 1) {
726  G4cout << " >>> G4IntraNucleiCascader::processSecondary "
727  << kpd->GetParticleName() << G4endl;
728  }
729 
730  // Allocate next local particle in buffer and fill
731  cascad_particles.resize(cascad_particles.size()+1); // Like push_back();
732  G4CascadParticle& cpart = cascad_particles.back();
733 
734  // Convert momentum to Bertini internal units
735  cpart.getParticle().fill(ktrack->Get4Momentum()/GeV, ktype);
736  cpart.setGeneration(0);
737  cpart.setMovingInsideNuclei();
738  cpart.initializePath(0);
739 
740  // Convert position units to Bertini's internal scale
741  G4ThreeVector cpos = ktrack->GetPosition()/model->getRadiusUnits();
742 
743  cpart.updatePosition(cpos);
744  cpart.updateZone(model->getZone(cpos.mag()));
745 
746  if (verboseLevel > 2)
747  G4cout << " Created cascade particle \n" << cpart << G4endl;
748 }
749 
750 
751 // Transfer unusable pre-cascade secondaries directly to output
752 
754  G4ParticleDefinition* kpd = ktrack->GetDefinition();
755 
756  if (verboseLevel > 1) {
757  G4cout << " >>> G4IntraNucleiCascader::releaseSecondary "
758  << kpd->GetParticleName() << G4endl;
759  }
760 
761  // Convert light ion into nucleus on fragment list
762  if (dynamic_cast<G4Ions*>(kpd)) {
763  // Use resize() and fill() to avoid memory churn
764  output.getOutgoingNuclei().resize(output.numberOfOutgoingNuclei()+1);
765  G4InuclNuclei& inucl = output.getOutgoingNuclei().back();
766 
767  inucl.fill(ktrack->Get4Momentum()/GeV,
768  kpd->GetAtomicMass(), kpd->GetAtomicNumber());
769  if (verboseLevel > 2)
770  G4cout << " Created pre-cascade fragment\n" << inucl << G4endl;
771  } else {
772  // Use resize() and fill() to avoid memory churn
773  output.getOutgoingParticles().resize(output.numberOfOutgoingParticles()+1);
775 
776  // SPECIAL: Use G4PartDef directly, allowing unknown type code
777  ipart.fill(ktrack->Get4Momentum()/GeV, ktrack->GetDefinition());
778  if (verboseLevel > 2)
779  G4cout << " Created invalid pre-cascade particle\n" << ipart << G4endl;
780  }
781 }
782 
783 
784 // Convert particles which cannot escape into excitons (or eject/decay them)
785 
788  const G4InuclElementaryParticle& trappedP = trapped.getParticle();
789 
790  G4int xtype = trappedP.type();
791  if (verboseLevel > 3) G4cout << " exciton of type " << xtype << G4endl;
792 
793  if (trappedP.nucleon()) { // normal exciton (proton or neutron)
794  theExitonConfiguration.incrementQP(xtype);
795  return;
796  }
797 
798  if (trappedP.hyperon()) { // Not nucleon, so must be hyperon
799  decayTrappedParticle(trapped);
800  return;
801  }
802 
803  // non-standard exciton; release it
804  // FIXME: this is a meson, so need to absorb it
805  if (verboseLevel > 3) {
806  G4cout << " non-standard should be absorbed, now released\n"
807  << trapped << G4endl;
808  }
809 
810  output.addOutgoingParticle(trappedP);
811 }
812 
813 
814 // Decay unstable trapped particles, and add secondaries to processing list
815 
818  if (verboseLevel > 3)
819  G4cout << " unstable must be decayed in flight" << G4endl;
820 
821  const G4InuclElementaryParticle& trappedP = trapped.getParticle();
822 
823  G4DecayTable* unstable = trappedP.getDefinition()->GetDecayTable();
824  if (!unstable) { // No decay table; cannot decay!
825  if (verboseLevel > 3)
826  G4cerr << " no decay table! Releasing trapped particle" << G4endl;
827 
828  output.addOutgoingParticle(trappedP);
829  return;
830  }
831 
832  // Get secondaries from decay in particle's rest frame
833  G4DecayProducts* daughters = unstable->SelectADecayChannel()->DecayIt( trappedP.getDefinition()->GetPDGMass() );
834  if (!daughters) { // No final state; cannot decay!
835  if (verboseLevel > 3)
836  G4cerr << " no daughters! Releasing trapped particle" << G4endl;
837 
838  output.addOutgoingParticle(trappedP);
839  return;
840  }
841 
842  if (verboseLevel > 3)
843  G4cout << " " << daughters->entries() << " decay daughters" << G4endl;
844 
845  // Convert secondaries to lab frame
846  G4double decayEnergy = trappedP.getEnergy();
847  G4ThreeVector decayDir = trappedP.getMomentum().vect().unit();
848  daughters->Boost(decayEnergy, decayDir);
849 
850  // Put all the secondaries onto the list for propagation
851  const G4ThreeVector& decayPos = trapped.getPosition();
852  G4int zone = trapped.getCurrentZone();
853  G4int gen = trapped.getGeneration()+1;
854 
855  for (G4int i=0; i<daughters->entries(); i++) {
856  G4DynamicParticle* idaug = (*daughters)[i];
857 
859 
860  // Propagate hadronic secondaries with known interactions (tables)
861  if (G4CascadeChannelTables::GetTable(idaugEP.type())) {
862  if (verboseLevel > 3) G4cout << " propagating " << idaugEP << G4endl;
863  cascad_particles.push_back(G4CascadParticle(idaugEP,decayPos,zone,0.,gen));
864  } else {
865  if (verboseLevel > 3) G4cout << " releasing " << idaugEP << G4endl;
866  output.addOutgoingParticle(idaugEP);
867  }
868  }
869 }