Geant4 10.7.0
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
G4CascadeInterface.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//
27// 20100114 M. Kelsey -- Remove G4CascadeMomentum, use G4LorentzVector directly
28// 20100413 M. Kelsey -- Pass G4CollisionOutput by ref to ::collide()
29// 20100414 M. Kelsey -- Check for K0L/K0S before using G4InuclElemPart::type
30// 20100418 M. Kelsey -- Reference output particle lists via const-ref, use
31// const_iterator for both.
32// 20100428 M. Kelsey -- Use G4InuclParticleNames enum
33// 20100429 M. Kelsey -- Change "case gamma:" to "case photon:"
34// 20100517 M. Kelsey -- Follow new ctors for G4*Collider family.
35// 20100520 M. Kelsey -- Simplify collision loop, move momentum rotations to
36// G4CollisionOutput, copy G4DynamicParticle directly from
37// G4InuclParticle, no switch-block required.
38// 20100615 M. Kelsey -- Bug fix: For K0's need ekin in GEANT4 units
39// 20100617 M. Kelsey -- Rename "debug_" preprocessor flag to G4CASCADE_DEBUG,
40// and "BERTDEV" to "G4CASCADE_COULOMB_DEV"
41// 20100617 M. Kelsey -- Make G4InuclCollider a local data member
42// 20100618 M. Kelsey -- Deploy energy-conservation test on final state, with
43// preprocessor flag G4CASCADE_SKIP_ECONS to skip test.
44// 20100620 M. Kelsey -- Use new energy-conservation pseudo-collider
45// 20100621 M. Kelsey -- Fix compiler warning from GCC 4.5
46// 20100624 M. Kelsey -- Fix cascade loop to check nTries every time (had
47// allowed for infinite loop on E-violation); dump event data
48// to output if E-violation exceeds maxTries; use CheckBalance
49// for baryon and charge conservation.
50// 20100701 M. Kelsey -- Pass verbosity through to G4CollisionOutput
51// 20100714 M. Kelsey -- Report number of iterations before success
52// 20100720 M. Kelsey -- Use G4CASCADE_SKIP_ECONS flag for reporting
53// 20100723 M. Kelsey -- Move G4CollisionOutput to .hh file for reuse
54// 20100914 M. Kelsey -- Migrate to integer A and Z
55// 20100916 M. Kelsey -- Simplify ApplyYourself() by encapsulating code blocks
56// into numerous functions; make data-member colliders pointers;
57// provide support for projectile nucleus
58// 20100919 M. Kelsey -- Fix incorrect logic in retryInelasticNucleus()
59// 20100922 M. Kelsey -- Add functions to select de-excitation method
60// 20100924 M. Kelsey -- Migrate to "OutgoingNuclei" names in CollisionOutput
61// 20110224 M. Kelsey -- Add createTarget() for use with Propagate(); split
62// conservation law messages to separate function; begin to add
63// infrastructure code to Propagate. Move verbose
64// setting to .cc file, and apply to all member objects.
65// 20110301 M. Kelsey -- Add copyPreviousCascade() for use with Propagate()
66// along with new buffers and related particle-conversion
67// functions. Encapulate buffer deletion in clear(). Add some
68// diagnostic messages.
69// 20110302 M. Kelsey -- Redo diagnostics inside G4CASCADE_DEBUG_INTERFACE
70// 20110304 M. Kelsey -- Drop conversion of Propagate() arguments; pass
71// directly to collider for processing. Rename makeReactionProduct
72// to makeDynamicParticle.
73// 20110316 M. Kelsey -- Move kaon-mixing for type-code into G4InuclParticle;
74// add placeholders to capture and use bullet in Propagte
75// 20110327 G. Folger -- Set up for E/p checking by G4HadronicProcess in ctor
76// 20110328 M. Kelsey -- Modify balance() initialization to match Gunter's
77// 20110404 M. Kelsey -- Get primary projectile from base class (ref-03)
78// 20110502 M. Kelsey -- Add interface to capture random seeds for user
79// 20110719 M. Kelsey -- Use trivialise() in case maximum retries are reached
80// 20110720 M. Kelsey -- Discard elastic-cut array (no longer needed),
81// discard local "theFinalState" (in base as "theParticleChange"),
82// Modify createBullet() to set null pointer if bullet unusable,
83// return empty final-state on failures.
84// Fix charge violation report before throwing exception.
85// 20110722 M. Kelsey -- In makeDynamicParticle(), allow invalid type codes
86// in order to process, e.g., resonances from Propagate() input
87// 20110728 M. Kelsey -- Per V.Ivantchenko, change NoInteraction to return
88// zero particles, but set kinetic energy from projectile.
89// 20110801 M. Kelsey -- Make bullet, target point to local buffers, no delete
90// 20110802 M. Kelsey -- Use new decay handler for Propagate interface
91// 20110922 M. Kelsey -- Follow migration of G4InuclParticle::print(), use
92// G4ExceptionDescription for reporting before throwing exception
93// 20120125 M. Kelsey -- In retryInelasticProton() check for empty output
94// 20120525 M. Kelsey -- In NoInteraction, check for Ekin<0., set to zero;
95// use SetEnergyChange(0.) explicitly for good final states.
96// 20120822 M. Kelsey -- Move envvars to G4CascadeParameters.
97// 20130508 D. Wright -- Add support for muon capture
98// 20130804 M. Kelsey -- Fix bug #1513 -- "(Z=1)" in boolean expression
99// 20140116 M. Kelsey -- Move statics to const data members to avoid weird
100// interactions with MT.
101// 20140929 M. Kelsey -- Explicitly call useCascadeDeexcitation() in ctor
102// 20150506 M. Kelsey -- Call Initialize() in ctor for master thread only
103// 20150608 M. Kelsey -- Label all while loops as terminating.
104
105#include <cmath>
106#include <iostream>
107
108#include "G4CascadeInterface.hh"
109#include "globals.hh"
110#include "G4SystemOfUnits.hh"
113#include "G4CascadeParameters.hh"
114#include "G4CollisionOutput.hh"
116#include "G4DynamicParticle.hh"
117#include "G4HadronicException.hh"
118#include "G4InuclCollider.hh"
121#include "G4InuclNuclei.hh"
122#include "G4InuclParticle.hh"
124#include "G4KaonZeroLong.hh"
125#include "G4KaonZeroShort.hh"
126#include "G4KineticTrack.hh"
128#include "G4Nucleus.hh"
131#include "G4Threading.hh"
132#include "G4Track.hh"
133#include "G4V3DNucleus.hh"
134#include "G4UnboundPN.hh"
135#include "G4Dineutron.hh"
136#include "G4Diproton.hh"
137
138using namespace G4InuclParticleNames;
139
140typedef std::vector<G4InuclElementaryParticle>::const_iterator particleIterator;
141typedef std::vector<G4InuclNuclei>::const_iterator nucleiIterator;
142
143
144// Constructor and destrutor
145
148 randomFile(G4CascadeParameters::randomFile()),
149 maximumTries(20), numberOfTries(0),
150 collider(new G4InuclCollider), balance(new G4CascadeCheckBalance(name)),
151 ltcollider(new G4LightTargetCollider),
152 bullet(0), target(0), output(new G4CollisionOutput)
153{
154 // Set up global objects for master thread or sequential build
156
157 SetEnergyMomentumCheckLevels(5*perCent, 10*MeV);
158 balance->setLimits(5*perCent, 10*MeV/GeV); // Bertini internal units
160
163 else
165}
166
168 clear();
169 delete collider; collider=0;
170 delete ltcollider; ltcollider = 0;
171 delete balance; balance=0;
172 delete output; output=0;
173}
174
175void G4CascadeInterface::ModelDescription(std::ostream& outFile) const
176{
177 outFile << "The Bertini-style cascade implements the inelastic scattering\n"
178 << "of hadrons by nuclei. Nucleons, pions, kaons and hyperons\n"
179 << "from 0 to 15 GeV may be used as projectiles in this model.\n"
180 << "Final state hadrons are produced by a classical cascade\n"
181 << "consisting of individual hadron-nucleon scatterings which use\n"
182 << "free-space partial cross sections, corrected for various\n"
183 << "nuclear medium effects. The target nucleus is modeled as a\n"
184 << "set of 1, 3 or 6 spherical shells, in which scattered hadrons\n"
185 << "travel in straight lines until they are reflected from or\n"
186 << "transmitted through shell boundaries.\n";
187}
188
189void G4CascadeInterface::DumpConfiguration(std::ostream& outFile) const {
191}
192
194 bullet=0;
195 target=0;
196}
197
198
199// Initialize shared objects for use across multiple threads
200
206 if (!ch || !pn || !nn || !pp) return; // Avoid "unused variables"
207}
208
209
210// Select post-cascade processing (default will be CascadeDeexcitation)
211// NOTE: Currently just calls through to Collider, in future will do something
212
214 collider->useCascadeDeexcitation();
215}
216
218 collider->usePreCompoundDeexcitation();
219}
220
221
222// Apply verbosity to all member objects (overrides base class version)
223
226 collider->setVerboseLevel(verbose);
227 balance->setVerboseLevel(verbose);
228 output->setVerboseLevel(verbose);
229}
230
231
232// Test whether inputs are valid for this model
233
235 G4Nucleus& /* theNucleus */) {
236 return IsApplicable(aTrack.GetDefinition());
237}
238
240 if (aPD->GetAtomicMass() > 1) return true; // Nuclei are okay
241
242 // Valid particle and have interactions available
245}
246
247
248// Main Actions
249
252 G4Nucleus& theNucleus) {
253 if (verboseLevel)
254 G4cout << " >>> G4CascadeInterface::ApplyYourself" << G4endl;
255
256 if (aTrack.GetKineticEnergy() < 0.) {
257 G4cerr << " >>> G4CascadeInterface got negative-energy track: "
258 << aTrack.GetDefinition()->GetParticleName() << " Ekin = "
259 << aTrack.GetKineticEnergy() << G4endl;
260 }
261
262#ifdef G4CASCADE_DEBUG_INTERFACE
263 static G4int counter(0);
264 counter++;
265 G4cerr << "Reaction number "<< counter << " "
266 << aTrack.GetDefinition()->GetParticleName() << " "
267 << aTrack.GetKineticEnergy() << " MeV" << G4endl;
268#endif
269
270 if (!randomFile.empty()) { // User requested random-seed capture
271 if (verboseLevel>1)
272 G4cout << " Saving random engine state to " << randomFile << G4endl;
274 }
275
277 clear();
278
279 // Abort processing if no interaction is possible
280 if (!IsApplicable(aTrack, theNucleus)) {
281 if (verboseLevel) G4cerr << " No interaction possible " << G4endl;
282 return NoInteraction(aTrack, theNucleus);
283 }
284
285 // If target A < 3 skip all cascade machinery and do scattering on
286 // nucleons
287
288 if (aTrack.GetDefinition() == G4Gamma::Gamma() &&
289 theNucleus.GetA_asInt() < 3) {
290 output->reset();
291 createBullet(aTrack);
292 createTarget(theNucleus);
293 // Due to binning, gamma-p cross sections between 130 MeV and the inelastic threshold
294 // (144 for pi0 p, 152 for pi+ n) are non-zero, causing energy non-conservation
295 // So, if Egamma is between 144 and 152, only pi0 p is allowed.
296
297 // Also, inelastic gamma-p cross section from G4PhotoNuclearCrossSection seems to be
298 // non-zero below between pi0 mass (135 MeV) and threshold (144 MeV)
299 ltcollider->collide(bullet, target, *output);
300
301 } else {
302
303 // Make conversion between native Geant4 and Bertini cascade classes.
304 if (!createBullet(aTrack)) {
305 if (verboseLevel) G4cerr << " Unable to create usable bullet" << G4endl;
306 return NoInteraction(aTrack, theNucleus);
307 }
308
309 if (!createTarget(theNucleus)) {
310 if (verboseLevel) G4cerr << " Unable to create usable target" << G4endl;
311 return NoInteraction(aTrack, theNucleus);
312 }
313
314 // Different retry conditions for proton target vs. nucleus
315 const G4bool isHydrogen = (theNucleus.GetA_asInt() == 1);
316
317 numberOfTries = 0;
318 do { // we try to create inelastic interaction
319 if (verboseLevel > 1)
320 G4cout << " Generating cascade attempt " << numberOfTries << G4endl;
321
322 output->reset();
323 collider->collide(bullet, target, *output);
324 balance->collide(bullet, target, *output);
325
326 numberOfTries++;
327 /* Loop checking 08.06.2015 MHK */
328 } while ( isHydrogen ? retryInelasticProton() : retryInelasticNucleus() );
329
330 // Null event if unsuccessful
331 if (numberOfTries >= maximumTries) {
332 if (verboseLevel)
333 G4cout << " Cascade aborted after trials " << numberOfTries << G4endl;
334 return NoInteraction(aTrack, theNucleus);
335 }
336
337 // Abort job if energy or momentum are not conserved
338 if (!balance->okay()) {
340 return NoInteraction(aTrack, theNucleus);
341 }
342
343 // Successful cascade -- clean up and return
344 if (verboseLevel) {
345 G4cout << " Cascade output after trials " << numberOfTries << G4endl;
346 if (verboseLevel > 1) output->printCollisionOutput();
347 }
348
349 } // end cascade-style collisions
350
352
353 // Report violations of conservation laws in original frame
355
356 // Clean up and return final result;
357 clear();
358/*
359 G4int nSec = theParticleChange.GetNumberOfSecondaries();
360 for (G4int i = 0; i < nSec; i++) {
361 G4HadSecondary* sec = theParticleChange.GetSecondary(i);
362 G4DynamicParticle* dp = sec->GetParticle();
363 if (dp->GetDefinition()->GetParticleName() == "neutron")
364 G4cout << dp->GetDefinition()->GetParticleName() << " has "
365 << dp->GetKineticEnergy()/MeV << " MeV " << G4endl;
366 }
367*/
368 return &theParticleChange;
369}
370
373 G4V3DNucleus* theNucleus) {
374 if (verboseLevel) G4cout << " >>> G4CascadeInterface::Propagate" << G4endl;
375
376#ifdef G4CASCADE_DEBUG_INTERFACE
377 if (verboseLevel>1) {
378 G4cout << " G4V3DNucleus A " << theNucleus->GetMassNumber()
379 << " Z " << theNucleus->GetCharge()
380 << "\n " << theSecondaries->size() << " secondaries:" << G4endl;
381 for (size_t i=0; i<theSecondaries->size(); i++) {
382 G4KineticTrack* kt = (*theSecondaries)[i];
383 G4cout << " " << i << ": " << kt->GetDefinition()->GetParticleName()
384 << " p " << kt->Get4Momentum() << " @ " << kt->GetPosition()
385 << " t " << kt->GetFormationTime() << G4endl;
386 }
387 }
388#endif
389
390 if (!randomFile.empty()) { // User requested random-seed capture
391 if (verboseLevel>1)
392 G4cout << " Saving random engine state to " << randomFile << G4endl;
394 }
395
397 clear();
398
399 // Process input secondaries list to eliminate resonances
400 G4DecayKineticTracks decay(theSecondaries);
401
402 // NOTE: Requires 9.4-ref-03 mods to base class and G4TheoFSGenerator
403 const G4HadProjectile* projectile = GetPrimaryProjectile();
404 if (projectile) createBullet(*projectile);
405
406 if (!createTarget(theNucleus)) {
407 if (verboseLevel) G4cerr << " Unable to create usable target" << G4endl;
408 return 0; // FIXME: This will cause a segfault later
409 }
410
411 numberOfTries = 0;
412 do {
413 if (verboseLevel > 1)
414 G4cout << " Generating rescatter attempt " << numberOfTries << G4endl;
415
416 output->reset();
417 collider->rescatter(bullet, theSecondaries, theNucleus, *output);
418 balance->collide(bullet, target, *output);
419
420 numberOfTries++;
421 // FIXME: retry checks will SEGFAULT until we can define the bullet!
422 } while (retryInelasticNucleus()); /* Loop checking 08.06.2015 MHK */
423
424 // Check whether repeated attempts have all failed; report and exit
425 if (numberOfTries >= maximumTries && !balance->okay()) {
426 throwNonConservationFailure(); // This terminates the job
427 }
428
429 // Successful cascade -- clean up and return
430 if (verboseLevel) {
431 G4cout << " Cascade rescatter after trials " << numberOfTries << G4endl;
432 if (verboseLevel > 1) output->printCollisionOutput();
433 }
434
435 // Does calling code take ownership? I hope so!
437
438 // Clean up and and return final result
439 clear();
440 return propResult;
441}
442
443
444// Replicate input particles onto output
445
448 G4Nucleus& /*theNucleus*/) {
449 if (verboseLevel)
450 G4cout << " >>> G4CascadeInterface::NoInteraction" << G4endl;
451
454
455 G4double ekin = aTrack.GetKineticEnergy()>0. ? aTrack.GetKineticEnergy() : 0.;
456 theParticleChange.SetEnergyChange(ekin); // Protect against rounding
457
458 return &theParticleChange;
459}
460
461
462// Convert input projectile to Bertini internal object
463
465 const G4ParticleDefinition* trkDef = aTrack.GetDefinition();
466 G4int bulletType = 0; // For elementary particles
467 G4int bulletA = 0, bulletZ = 0; // For nucleus projectile
468
469 if (trkDef->GetAtomicMass() <= 1) {
470 bulletType = G4InuclElementaryParticle::type(trkDef);
471 } else {
472 bulletA = trkDef->GetAtomicMass();
473 bulletZ = trkDef->GetAtomicNumber();
474 }
475
476 if (0 == bulletType && 0 == bulletA*bulletZ) {
477 if (verboseLevel) {
478 G4cerr << " G4CascadeInterface: " << trkDef->GetParticleName()
479 << " not usable as bullet." << G4endl;
480 }
481 bullet = 0;
482 return false;
483 }
484
485 // Code momentum and energy -- Bertini wants z-axis and GeV units
486 G4LorentzVector projectileMomentum = aTrack.Get4Momentum()/GeV;
487
488 // Rotation/boost to get from z-axis back to original frame
489 // According to bug report #1990 this rotation is unnecessary and causes
490 // irreproducibility. Verifed and fixed by DHW 27 Nov 2017
491 // bulletInLabFrame = G4LorentzRotation::IDENTITY; // Initialize
492 // bulletInLabFrame.rotateZ(-projectileMomentum.phi());
493 // bulletInLabFrame.rotateY(-projectileMomentum.theta());
494 // bulletInLabFrame.invert();
495
496 G4LorentzVector momentumBullet(0., 0., projectileMomentum.rho(),
497 projectileMomentum.e());
498
499 if (G4InuclElementaryParticle::valid(bulletType)) {
500 hadronBullet.fill(momentumBullet, bulletType);
501 bullet = &hadronBullet;
502 } else {
503 nucleusBullet.fill(momentumBullet, bulletA, bulletZ);
504 bullet = &nucleusBullet;
505 }
506
507 if (verboseLevel > 2) G4cout << "Bullet: \n" << *bullet << G4endl;
508
509 return true;
510}
511
512
513// Convert input nuclear target to Bertini internal object
514
516 return createTarget(theNucleus.GetA_asInt(), theNucleus.GetZ_asInt());
517}
518
520 return createTarget(theNucleus->GetMassNumber(), theNucleus->GetCharge());
521}
522
524 if (A > 1) {
525 nucleusTarget.fill(A, Z);
526 target = &nucleusTarget;
527 } else {
528 hadronTarget.fill(0., (Z==1?proton:neutron));
529 target = &hadronTarget;
530 }
531
532 if (verboseLevel > 2) G4cout << "Target: \n" << *target << G4endl;
533
534 return true; // Right now, target never fails
535}
536
537
538// Convert Bertini particle to output (G4DynamicParticle)
539
542 G4int outgoingType = iep.type();
543
544 if (iep.quasi_deutron()) {
545 G4cerr << " ERROR: G4CascadeInterface incompatible particle type "
546 << outgoingType << G4endl;
547 return 0;
548 }
549
550 // Copy local G4DynPart to public output (handle kaon mixing specially)
551 if (outgoingType == kaonZero || outgoingType == kaonZeroBar) {
552 G4ThreeVector momDir = iep.getMomentum().vect().unit();
553 G4double ekin = iep.getKineticEnergy()*GeV; // Bertini -> G4 units
554
556 if (G4UniformRand() > 0.5) pd = G4KaonZeroLong::Definition();
557
558 return new G4DynamicParticle(pd, momDir, ekin);
559 } else {
560 return new G4DynamicParticle(iep.getDynamicParticle());
561 }
562
563 return 0; // Should never get here!
564}
565
568 if (verboseLevel > 2) {
569 G4cout << " Nuclei fragment: \n" << inuc << G4endl;
570 }
571
572 // Copy local G4DynPart to public output
573 return new G4DynamicParticle(inuc.getDynamicParticle());
574}
575
576
577// Transfer Bertini internal final state to hadronics interface
578
580 if (verboseLevel > 1)
581 G4cout << " >>> G4CascadeInterface::copyOutputToHadronicResult" << G4endl;
582
583 const std::vector<G4InuclNuclei>& outgoingNuclei = output->getOutgoingNuclei();
584 const std::vector<G4InuclElementaryParticle>& particles = output->getOutgoingParticles();
585
588
589 // Get outcoming particles
590 if (!particles.empty()) {
591 particleIterator ipart = particles.begin();
592 for (; ipart != particles.end(); ipart++) {
594 }
595 }
596
597 // get nuclei fragments
598 if (!outgoingNuclei.empty()) {
599 nucleiIterator ifrag = outgoingNuclei.begin();
600 for (; ifrag != outgoingNuclei.end(); ifrag++) {
602 }
603 }
604}
605
607 if (verboseLevel > 1)
608 G4cout << " >>> G4CascadeInterface::copyOutputToReactionProducts" << G4endl;
609
610 const std::vector<G4InuclElementaryParticle>& particles = output->getOutgoingParticles();
611 const std::vector<G4InuclNuclei>& fragments = output->getOutgoingNuclei();
612
614
615 G4ReactionProduct* rp = 0; // Buffers to create outgoing tracks
616 G4DynamicParticle* dp = 0;
617
618 // Get outcoming particles
619 if (!particles.empty()) {
620 particleIterator ipart = particles.begin();
621 for (; ipart != particles.end(); ipart++) {
622 rp = new G4ReactionProduct;
623 dp = makeDynamicParticle(*ipart);
624 (*rp) = (*dp); // This does all the necessary copying
625 propResult->push_back(rp);
626 delete dp;
627 }
628 }
629
630 // get nuclei fragments
631 if (!fragments.empty()) {
632 nucleiIterator ifrag = fragments.begin();
633 for (; ifrag != fragments.end(); ifrag++) {
634 rp = new G4ReactionProduct;
635 dp = makeDynamicParticle(*ifrag);
636 (*rp) = (*dp); // This does all the necessary copying
637 propResult->push_back(rp);
638 delete dp;
639 }
640 }
641
642 return propResult;
643}
644
645
646// Report violations of conservation laws in original frame
647
649 balance->collide(bullet, target, *output);
650
651 if (verboseLevel > 2) {
652 if (!balance->baryonOkay()) {
653 G4cerr << "ERROR: no baryon number conservation, sum of baryons = "
654 << balance->deltaB() << G4endl;
655 }
656
657 if (!balance->chargeOkay()) {
658 G4cerr << "ERROR: no charge conservation, sum of charges = "
659 << balance->deltaQ() << G4endl;
660 }
661
662 if (std::abs(balance->deltaKE()) > 0.01 ) { // GeV
663 G4cerr << "Kinetic energy conservation violated by "
664 << balance->deltaKE() << " GeV" << G4endl;
665 }
666
667 G4double eInit = bullet->getEnergy() + target->getEnergy();
668 G4double eFinal = eInit + balance->deltaE();
669
670 G4cout << "Initial energy " << eInit << " final energy " << eFinal
671 << "\nTotal energy conservation at level "
672 << balance->deltaE() * GeV << " MeV" << G4endl;
673
674 if (balance->deltaKE() > 5.0e-5 ) { // 0.05 MeV
675 G4cerr << "FATAL ERROR: kinetic energy created "
676 << balance->deltaKE() * GeV << " MeV" << G4endl;
677 }
678 }
679}
680
681
682// Evaluate whether any outgoing particles penetrated Coulomb barrier
683
685 G4bool violated = false; // by default coulomb analysis is OK
686
687 const G4double coulumbBarrier = 8.7 * MeV/GeV; // Bertini uses GeV
688
689 const std::vector<G4InuclElementaryParticle>& p =
690 output->getOutgoingParticles();
691
692 for (particleIterator ipart=p.begin(); ipart != p.end(); ipart++) {
693 if (ipart->type() == proton) {
694 violated |= (ipart->getKineticEnergy() < coulumbBarrier);
695 }
696 }
697
698 return violated;
699}
700
701// Check whether inelastic collision on proton failed
702
704 const std::vector<G4InuclElementaryParticle>& out =
705 output->getOutgoingParticles();
706
707#ifdef G4CASCADE_DEBUG_INTERFACE
708 // Report on all retry conditions, in order of return logic
709 G4cout << " retryInelasticProton: number of Tries "
710 << ((numberOfTries < maximumTries) ? "RETRY (t)" : "EXIT (f)")
711 << "\n retryInelasticProton: AND collision type ";
712 if (out.empty()) G4cout << "FAILED" << G4endl;
713 else {
714 G4cout << (out.size() == 2 ? "ELASTIC (t)" : "INELASTIC (f)")
715 << "\n retryInelasticProton: AND Leading particles bullet "
716 << (out.size() >= 2 &&
717 (out[0].getDefinition() == bullet->getDefinition() ||
718 out[1].getDefinition() == bullet->getDefinition())
719 ? "YES (t)" : "NO (f)")
720 << G4endl;
721 }
722#endif
723
724 return ( (numberOfTries < maximumTries) &&
725 (out.empty() ||
726 (out.size() == 2 &&
727 (out[0].getDefinition() == bullet->getDefinition() ||
728 out[1].getDefinition() == bullet->getDefinition())))
729 );
730}
731
732// Check whether generic inelastic collision failed
733// NOTE: some conditions are set by compiler flags
734
736 // Quantities necessary for conditional block below
737 G4int npart = output->numberOfOutgoingParticles();
738 G4int nfrag = output->numberOfOutgoingNuclei();
739
740 const G4ParticleDefinition* firstOut = (npart == 0) ? 0 :
741 output->getOutgoingParticles().begin()->getDefinition();
742
743#ifdef G4CASCADE_DEBUG_INTERFACE
744 // Report on all retry conditions, in order of return logic
745 G4cout << " retryInelasticNucleus: numberOfTries "
746 << ((numberOfTries < maximumTries) ? "RETRY (t)" : "EXIT (f)")
747 << "\n retryInelasticNucleus: AND outputParticles "
748 << ((npart != 0) ? "NON-ZERO (t)" : "EMPTY (f)")
749#ifdef G4CASCADE_COULOMB_DEV
750 << "\n retryInelasticNucleus: AND coulombBarrier (COULOMB_DEV) "
751 << (coulombBarrierViolation() ? "VIOLATED (t)" : "PASSED (f)")
752 << "\n retryInelasticNucleus: AND collision type (COULOMB_DEV) "
753 << ((npart+nfrag > 2) ? "INELASTIC (t)" : "ELASTIC (f)")
754#else
755 << "\n retryInelasticNucleus: AND collision type "
756 << ((npart+nfrag < 3) ? "ELASTIC (t)" : "INELASTIC (f)")
757 << "\n retryInelasticNucleus: AND Leading particle bullet "
758 << ((firstOut == bullet->getDefinition()) ? "YES (t)" : "NO (f)")
759#endif
760 << "\n retryInelasticNucleus: OR conservation "
761 << (!balance->okay() ? "FAILED (t)" : "PASSED (f)")
762 << G4endl;
763#endif
764
765 return ( (numberOfTries < maximumTries) &&
766 ( ((npart != 0) &&
767#ifdef G4CASCADE_COULOMB_DEV
768 (coulombBarrierViolation() && npart+nfrag > 2)
769#else
770 (npart+nfrag < 3 && firstOut == bullet->getDefinition())
771#endif
772 )
773#ifndef G4CASCADE_SKIP_ECONS
774 || (!balance->okay())
775#endif
776 )
777 );
778}
779
780
781// Terminate job in case of persistent non-conservation
782// FIXME: Need to migrate to G4ExceptionDescription
783
785 // NOTE: Once G4HadronicException is changed, use the following line!
786 // G4ExceptionDescription errInfo;
787 std::ostream& errInfo = G4cerr;
788
789 errInfo << " >>> G4CascadeInterface has non-conserving"
790 << " cascade after " << numberOfTries << " attempts." << G4endl;
791
792 G4String throwMsg = "G4CascadeInterface - ";
793 if (!balance->energyOkay()) {
794 throwMsg += "Energy";
795 errInfo << " Energy conservation violated by " << balance->deltaE()
796 << " GeV (" << balance->relativeE() << ")" << G4endl;
797 }
798
799 if (!balance->momentumOkay()) {
800 throwMsg += "Momentum";
801 errInfo << " Momentum conservation violated by " << balance->deltaP()
802 << " GeV/c (" << balance->relativeP() << ")" << G4endl;
803 }
804
805 if (!balance->baryonOkay()) {
806 throwMsg += "Baryon number";
807 errInfo << " Baryon number violated by " << balance->deltaB() << G4endl;
808 }
809
810 if (!balance->chargeOkay()) {
811 throwMsg += "Charge";
812 errInfo << " Charge conservation violated by " << balance->deltaQ()
813 << G4endl;
814 }
815
816 errInfo << " Final event output, for debugging:\n"
817 << " Bullet: \n" << *bullet << G4endl
818 << " Target: \n" << *target << G4endl;
819 output->printCollisionOutput(errInfo);
820
821 throwMsg += " non-conservation. More info in output.";
822 throw G4HadronicException(__FILE__, __LINE__, throwMsg); // Job ends here!
823}
std::vector< G4InuclElementaryParticle >::iterator particleIterator
Definition: G4BigBanger.cc:64
std::vector< G4InuclElementaryParticle >::const_iterator particleIterator
std::vector< G4InuclNuclei >::const_iterator nucleiIterator
double A(double temperature)
@ isAlive
@ stopAndKill
std::vector< G4ReactionProduct * > G4ReactionProductVector
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition: Randomize.hh:52
Hep3Vector unit() const
Hep3Vector vect() const
static void saveEngineStatus(const char filename[]="Config.conf")
Definition: Random.cc:278
static const G4CascadeChannel * GetTable(G4int initialState)
void setLimits(G4double relative, G4double absolute)
void collide(G4InuclParticle *bullet, G4InuclParticle *target, G4CollisionOutput &output)
virtual void ModelDescription(std::ostream &outFile) const
G4bool coulombBarrierViolation() const
G4bool retryInelasticNucleus() const
G4HadFinalState * ApplyYourself(const G4HadProjectile &aTrack, G4Nucleus &theNucleus)
G4bool IsApplicable(const G4HadProjectile &aTrack, G4Nucleus &theNucleus)
G4HadFinalState * NoInteraction(const G4HadProjectile &aTrack, G4Nucleus &theNucleus)
G4bool createBullet(const G4HadProjectile &aTrack)
G4bool createTarget(G4Nucleus &theNucleus)
G4ReactionProductVector * copyOutputToReactionProducts()
virtual void DumpConfiguration(std::ostream &outFile) const
void SetVerboseLevel(G4int verbose)
G4ReactionProductVector * Propagate(G4KineticTrackVector *theSecondaries, G4V3DNucleus *theNucleus)
G4bool retryInelasticProton() const
G4DynamicParticle * makeDynamicParticle(const G4InuclElementaryParticle &iep) const
G4CascadeInterface(const G4String &name="BertiniCascade")
static void DumpConfiguration(std::ostream &os)
static G4bool usePreCompound()
G4int numberOfOutgoingParticles() const
const std::vector< G4InuclNuclei > & getOutgoingNuclei() const
void printCollisionOutput(std::ostream &os=G4cout) const
const std::vector< G4InuclElementaryParticle > & getOutgoingParticles() const
void setVerboseLevel(G4int verbose)
G4int numberOfOutgoingNuclei() const
static G4Dineutron * Definition()
Definition: G4Dineutron.cc:67
static G4Diproton * Definition()
Definition: G4Diproton.cc:67
static G4Gamma * Gamma()
Definition: G4Gamma.cc:85
void SetStatusChange(G4HadFinalStateStatus aS)
void AddSecondary(G4DynamicParticle *aP, G4int mod=-1)
void SetEnergyChange(G4double anEnergy)
const G4ParticleDefinition * GetDefinition() const
G4double GetKineticEnergy() const
const G4LorentzVector & Get4Momentum() const
void SetVerboseLevel(G4int value)
void SetEnergyMomentumCheckLevels(G4double relativeLevel, G4double absoluteLevel)
void useCascadeDeexcitation()
void usePreCompoundDeexcitation()
void collide(G4InuclParticle *bullet, G4InuclParticle *target, G4CollisionOutput &globalOutput)
void rescatter(G4InuclParticle *bullet, G4KineticTrackVector *theSecondaries, G4V3DNucleus *theNucleus, G4CollisionOutput &globalOutput)
void setVerboseLevel(G4int verbose=0)
void fill(G4int ityp, Model model=DefaultModel)
void fill(G4int a, G4int z, G4double exc=0., Model model=DefaultModel)
const G4ParticleDefinition * getDefinition() const
G4double getKineticEnergy() const
G4LorentzVector getMomentum() const
G4double getEnergy() const
const G4DynamicParticle & getDynamicParticle() const
static G4KaonZeroLong * Definition()
static G4KaonZeroShort * Definition()
G4double GetFormationTime() const
const G4ThreeVector & GetPosition() const
const G4ParticleDefinition * GetDefinition() const
const G4LorentzVector & Get4Momentum() const
void collide(G4InuclParticle *bullet, G4InuclParticle *target, G4CollisionOutput &globalOutput)
G4int GetA_asInt() const
Definition: G4Nucleus.hh:109
G4int GetZ_asInt() const
Definition: G4Nucleus.hh:115
G4int GetAtomicNumber() const
G4int GetAtomicMass() const
const G4String & GetParticleName() const
static G4UnboundPN * Definition()
Definition: G4UnboundPN.cc:66
virtual G4int GetCharge()=0
virtual G4int GetMassNumber()=0
virtual void setVerboseLevel(G4int verbose=0)
const G4HadProjectile * GetPrimaryProjectile() const
const char * name(G4int ptype)
G4bool IsMasterThread()
Definition: G4Threading.cc:124