ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4CascadeInterface.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4CascadeInterface.cc
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"
111 #include "G4CascadeChannelTables.hh"
112 #include "G4CascadeCheckBalance.hh"
113 #include "G4CascadeParameters.hh"
114 #include "G4CollisionOutput.hh"
115 #include "G4DecayKineticTracks.hh"
116 #include "G4DynamicParticle.hh"
117 #include "G4HadronicException.hh"
118 #include "G4InuclCollider.hh"
119 #include "G4LightTargetCollider.hh"
121 #include "G4InuclNuclei.hh"
122 #include "G4InuclParticle.hh"
123 #include "G4InuclParticleNames.hh"
124 #include "G4KaonZeroLong.hh"
125 #include "G4KaonZeroShort.hh"
126 #include "G4KineticTrack.hh"
127 #include "G4KineticTrackVector.hh"
128 #include "G4Nucleus.hh"
129 #include "G4ParticleDefinition.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 
138 using namespace G4InuclParticleNames;
139 
140 typedef std::vector<G4InuclElementaryParticle>::const_iterator particleIterator;
141 typedef 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 
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 
175 void 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 
189 void 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 
215 }
216 
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
244  return (G4CascadeChannelTables::GetTable(type));
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)
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();
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;
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);
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;
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);
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);
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 
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 =
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 =
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
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 }