Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
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
117#include "G4SystemOfUnits.hh"
120#include "G4CascadeParameters.hh"
122#include "G4CascadParticle.hh"
123#include "G4CollisionOutput.hh"
124#include "G4DecayProducts.hh"
125#include "G4DecayTable.hh"
128#include "G4HadTmpUtil.hh"
130#include "G4InuclNuclei.hh"
133#include "G4KineticTrack.hh"
135#include "G4LorentzConvertor.hh"
136#include "G4Neutron.hh"
137#include "G4NucleiModel.hh"
139#include "G4Proton.hh"
140#include "G4V3DNucleus.hh"
141#include "Randomize.hh"
142
143using namespace G4InuclParticleNames;
144using namespace G4InuclSpecialFunctions;
145
146
147// Configuration parameters for cascade production
148const G4int G4IntraNucleiCascader::itry_max = 100;
149const G4int G4IntraNucleiCascader::reflection_cut = 50;
150const G4double G4IntraNucleiCascader::small_ekin = 0.001*MeV;
151const G4double G4IntraNucleiCascader::quasielast_cut = 1*MeV;
152
153
154typedef 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
187 G4InuclParticle* target,
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();
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);
221 } while (!finishCascade() && itry<itry_max);
222
223 finalize(itry, bullet, target, globalOutput);
224}
225
226
228 G4InuclParticle* target) {
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) {
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
605void
607 G4InuclParticle* target,
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
647void
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
686void
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);
774 G4InuclElementaryParticle& ipart = output.getOutgoingParticles().back();
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}
@ neutron
std::vector< G4InuclElementaryParticle >::iterator particleIterator
double G4double
Definition: G4Types.hh:64
int G4int
Definition: G4Types.hh:66
bool G4bool
Definition: G4Types.hh:67
#define G4endl
Definition: G4ios.hh:52
G4DLLIMPORT std::ostream G4cerr
G4DLLIMPORT std::ostream G4cout
#define G4UniformRand()
Definition: Randomize.hh:53
Hep3Vector unit() const
double mag() const
Hep3Vector vect() const
G4int getGeneration() const
void updateZone(G4int izone)
const G4InuclElementaryParticle & getParticle() const
void setGeneration(G4int gen)
void updatePosition(const G4ThreeVector &pos)
void setMovingInsideNuclei(G4bool isMovingIn=true)
G4int getNumberOfReflections() const
void initializePath(G4double npath)
G4int getCurrentZone() const
const G4ThreeVector & getPosition() const
static const G4CascadeChannel * GetTable(G4int initialState)
void FindClusters(G4CollisionOutput &finalState)
void setVerboseLevel(G4int verbose)
virtual void setVerboseLevel(G4int verbose=0)
static G4bool doCoalescence()
void addExcitonConfiguration(const G4ExitonConfiguration exciton)
void setTolerance(G4double tolerance)
const G4LorentzVector & getRecoilMomentum() const
void collide(G4InuclParticle *bullet, G4InuclParticle *target, G4CollisionOutput &output)
G4double getRecoilExcitation() const
void setRecoilExcitation(G4double Eexc)
G4Fragment * makeRecoilFragment()
G4int numberOfOutgoingParticles() const
void addRecoilFragment(const G4Fragment *aFragment)
const std::vector< G4InuclNuclei > & getOutgoingNuclei() const
void printCollisionOutput(std::ostream &os=G4cout) const
void addOutgoingParticle(const G4InuclElementaryParticle &particle)
const std::vector< G4InuclElementaryParticle > & getOutgoingParticles() const
void setOnShell(G4InuclParticle *bullet, G4InuclParticle *target)
void setVerboseLevel(G4int verbose)
G4int numberOfOutgoingNuclei() const
G4bool acceptable() const
void add(const G4CollisionOutput &right)
void trivialise(G4InuclParticle *bullet, G4InuclParticle *target)
void addOutgoingParticles(const std::vector< G4InuclElementaryParticle > &particles)
G4int entries() const
void Boost(G4double totalEnergy, const G4ThreeVector &momentumDirection)
G4VDecayChannel * SelectADecayChannel()
Definition: G4DecayTable.cc:81
G4InuclParticle * getBullet() const
void set(G4InuclParticle *part1, G4InuclParticle *part2)
G4bool hadNucleus() const
G4InuclParticle * getTarget() const
void processTrappedParticle(const G4CascadParticle &trapped)
void releaseSecondary(const G4KineticTrack *aSecondary)
void copyWoundedNucleus(G4V3DNucleus *theNucleus)
void rescatter(G4InuclParticle *bullet, G4KineticTrackVector *theSecondaries, G4V3DNucleus *theNucleus, G4CollisionOutput &globalOutput)
void setVerboseLevel(G4int verbose=0)
void decayTrappedParticle(const G4CascadParticle &trapped)
void collide(G4InuclParticle *bullet, G4InuclParticle *target, G4CollisionOutput &globalOutput)
G4bool initialize(G4InuclParticle *bullet, G4InuclParticle *target)
G4InuclParticle * createTarget(G4V3DNucleus *theNucleus)
void preloadCascade(G4V3DNucleus *theNucleus, G4KineticTrackVector *theSecondaries)
void copySecondaries(G4KineticTrackVector *theSecondaries)
void processSecondary(const G4KineticTrack *aSecondary)
void finalize(G4int itry, G4InuclParticle *bullet, G4InuclParticle *target, G4CollisionOutput &globalOutput)
void fill(G4int ityp, Model model=DefaultModel)
static G4double getParticleMass(G4int type)
G4int getZ() const
void fill(G4int a, G4int z, G4double exc=0., Model model=DefaultModel)
G4int getA() const
G4ParticleDefinition * getDefinition() const
G4double getKineticEnergy() const
G4double getMass() const
G4LorentzVector getMomentum() const
G4double getEnergy() const
G4double getCharge() const
Definition: G4Ions.hh:52
const G4ThreeVector & GetPosition() const
G4ParticleDefinition * GetDefinition() const
const G4LorentzVector & Get4Momentum() const
G4int getZone(G4double r) const
G4int getNumberOfNeutrons() const
G4CascadParticle initializeCascad(G4InuclElementaryParticle *particle)
G4bool worthToPropagate(const G4CascadParticle &cparticle) const
G4int getNumberOfProtons() const
void generateParticleFate(G4CascadParticle &cparticle, G4ElementaryParticleCollider *theEPCollider, std::vector< G4CascadParticle > &cascade)
G4bool empty() const
void reset(G4int nHitNeutrons=0, G4int nHitProtons=0, const std::vector< G4ThreeVector > *hitPoints=0)
G4bool stillInside(const G4CascadParticle &cparticle)
void generateModel(G4InuclNuclei *nuclei)
std::pair< std::vector< G4CascadParticle >, std::vector< G4InuclElementaryParticle > > modelLists
std::pair< G4int, G4int > getTypesOfNucleonsInvolved() const
G4double getRadiusUnits() const
void setVerboseLevel(G4int verbose)
G4bool AreYouHit() const
Definition: G4Nucleon.hh:97
G4ParticleDefinition * GetParticleType() const
Definition: G4Nucleon.hh:84
virtual const G4ThreeVector & GetPosition() const
Definition: G4Nucleon.hh:68
G4int GetAtomicNumber() const
G4int GetAtomicMass() const
G4DecayTable * GetDecayTable() const
const G4String & GetParticleName() const
virtual G4Nucleon * GetNextNucleon()=0
virtual G4int GetCharge()=0
virtual G4bool StartLoop()=0
virtual G4int GetMassNumber()=0
virtual void setVerboseLevel(G4int verbose=0)
virtual G4DecayProducts * DecayIt(G4double parentMass=-1.0)=0