Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4HadronicProcess.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// -------------------------------------------------------------------
29//
30// GEANT4 Class source file
31//
32// G4HadronicProcess
33//
34// original by H.P.Wellisch
35// J.L. Chuma, TRIUMF, 10-Mar-1997
36//
37// Modifications:
38// 05-Jul-2010 V.Ivanchenko cleanup commented lines
39// 20-Jul-2011 M.Kelsey -- null-pointer checks in DumpState()
40// 24-Sep-2011 M.Kelsey -- Use envvar G4HADRONIC_RANDOM_FILE to save random
41// engine state before each model call
42// 18-Oct-2011 M.Kelsey -- Handle final-state cases in conservation checks.
43// 14-Mar-2012 G.Folger -- enhance checks for conservation of energy, etc.
44// 28-Jul-2012 M.Maire -- add function GetTargetDefinition()
45// 14-Sep-2012 Inherit from RestDiscrete, use subtype code (now in ctor) to
46// configure base-class
47// 28-Sep-2012 Restore inheritance from G4VDiscreteProcess, remove enable-flag
48// changing, remove warning message from original ctor.
49
50#include "G4HadronicProcess.hh"
51
52#include "G4Types.hh"
53#include "G4SystemOfUnits.hh"
54#include "G4HadProjectile.hh"
55#include "G4ElementVector.hh"
56#include "G4Track.hh"
57#include "G4Step.hh"
58#include "G4Element.hh"
59#include "G4ParticleChange.hh"
61#include "G4Navigator.hh"
62#include "G4ProcessVector.hh"
63#include "G4ProcessManager.hh"
64#include "G4StableIsotopes.hh"
65#include "G4HadTmpUtil.hh"
66#include "G4NucleiProperties.hh"
67
70
71#include <typeinfo>
72#include <sstream>
73#include <iostream>
74
75#include <stdlib.h>
76
77// File-scope variable to capture environment variable at startup
78
79static const char* G4Hadronic_Random_File = getenv("G4HADRONIC_RANDOM_FILE");
80
81//////////////////////////////////////////////////////////////////
82
84 G4ProcessType procType)
85 : G4VDiscreteProcess(processName, procType)
86{
87 SetProcessSubType(fHadronInelastic); // Default unless subclass changes
88
91 theInteraction = 0;
92 theCrossSectionDataStore = new G4CrossSectionDataStore();
94 aScaleFactor = 1;
95 xBiasOn = false;
96 G4HadronicProcess_debug_flag = false;
97
98 GetEnergyMomentumCheckEnvvars();
99}
100
101//////////////////////////////////////////////////////////////////
102
104 G4HadronicProcessType aHadSubType)
105 : G4VDiscreteProcess(processName, fHadronic)
106{
107 SetProcessSubType(aHadSubType);
108
111 theInteraction = 0;
112 theCrossSectionDataStore = new G4CrossSectionDataStore();
114 aScaleFactor = 1;
115 xBiasOn = false;
116 G4HadronicProcess_debug_flag = false;
117
118 GetEnergyMomentumCheckEnvvars();
119}
120
121
123{
125 delete theTotalResult;
126 delete theCrossSectionDataStore;
127}
128
129void G4HadronicProcess::GetEnergyMomentumCheckEnvvars() {
130 levelsSetByProcess = false;
131
132 epReportLevel = getenv("G4Hadronic_epReportLevel") ?
133 strtol(getenv("G4Hadronic_epReportLevel"),0,10) : 0;
134
135 epCheckLevels.first = getenv("G4Hadronic_epCheckRelativeLevel") ?
136 strtod(getenv("G4Hadronic_epCheckRelativeLevel"),0) : DBL_MAX;
137
138 epCheckLevels.second = getenv("G4Hadronic_epCheckAbsoluteLevel") ?
139 strtod(getenv("G4Hadronic_epCheckAbsoluteLevel"),0) : DBL_MAX;
140}
141
143{
144 if(!a) { return; }
145 try{GetManagerPointer()->RegisterMe( a );}
146 catch(G4HadronicException & aE)
147 {
149 aE.Report(ed);
150 ed << "Unrecoverable error in " << GetProcessName()
151 << " to register " << a->GetModelName() << G4endl;
152 G4Exception("G4HadronicProcess::RegisterMe", "had001", FatalException,
153 ed);
154 }
156}
157
159{
160 if(getenv("G4HadronicProcess_debug")) {
161 G4HadronicProcess_debug_flag = true;
162 }
164}
165
167{
168 try
169 {
170 theCrossSectionDataStore->BuildPhysicsTable(p);
171 }
172 catch(G4HadronicException aR)
173 {
175 aR.Report(ed);
176 ed << " hadronic initialisation fails" << G4endl;
177 G4Exception("G4HadronicProcess::BuildPhysicsTable", "had000",
178 FatalException,ed);
179 }
181}
182
185{
186 try
187 {
188 theLastCrossSection = aScaleFactor*
189 theCrossSectionDataStore->GetCrossSection(aTrack.GetDynamicParticle(),
190 aTrack.GetMaterial());
191 }
192 catch(G4HadronicException aR)
193 {
195 aR.Report(ed);
196 DumpState(aTrack,"GetMeanFreePath",ed);
197 ed << " Cross section is not available" << G4endl;
198 G4Exception("G4HadronicProcess::GetMeanFreePath", "had002", FatalException,
199 ed);
200 }
201 G4double res = DBL_MAX;
202 if( theLastCrossSection > 0.0 ) { res = 1.0/theLastCrossSection; }
203 return res;
204}
205
208{
209 // if primary is not Alive then do nothing
211 theTotalResult->Initialize(aTrack);
213 if(aTrack.GetTrackStatus() != fAlive) { return theTotalResult; }
214
215 // Find cross section at end of step and check if <= 0
216 //
217 const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
218 G4Material* aMaterial = aTrack.GetMaterial();
219
220 G4Element* anElement = 0;
221 try
222 {
223 anElement = theCrossSectionDataStore->SampleZandA(aParticle,
224 aMaterial,
225 targetNucleus);
226 }
227 catch(G4HadronicException & aR)
228 {
230 aR.Report(ed);
231 DumpState(aTrack,"SampleZandA",ed);
232 ed << " PostStepDoIt failed on element selection" << G4endl;
233 G4Exception("G4HadronicProcess::PostStepDoIt", "had003", FatalException,
234 ed);
235 }
236
237 // check only for charged particles
238 if(aParticle->GetDefinition()->GetPDGCharge() != 0.0) {
239 if (GetElementCrossSection(aParticle, anElement, aMaterial) <= 0.0) {
240 // No interaction
241 return theTotalResult;
242 }
243 }
244
245 // Next check for illegal track status
246 //
247 if (aTrack.GetTrackStatus() != fAlive && aTrack.GetTrackStatus() != fSuspend) {
248 if (aTrack.GetTrackStatus() == fStopAndKill ||
252 ed << "G4HadronicProcess: track in unusable state - "
253 << aTrack.GetTrackStatus() << G4endl;
254 ed << "G4HadronicProcess: returning unchanged track " << G4endl;
255 DumpState(aTrack,"PostStepDoIt",ed);
256 G4Exception("G4HadronicProcess::PostStepDoIt", "had004", JustWarning, ed);
257 }
258 // No warning for fStopButAlive which is a legal status here
259 return theTotalResult;
260 }
261
262 // Go on to regular case
263 //
264 G4double originalEnergy = aParticle->GetKineticEnergy();
265 G4double kineticEnergy = originalEnergy;
266
267 // Get kinetic energy per nucleon for ions
268 if(aParticle->GetParticleDefinition()->GetBaryonNumber() > 1.5)
269 kineticEnergy/=aParticle->GetParticleDefinition()->GetBaryonNumber();
270
271 try
272 {
273 theInteraction =
274 ChooseHadronicInteraction( kineticEnergy, aMaterial, anElement );
275 }
276 catch(G4HadronicException & aE)
277 {
279 aE.Report(ed);
280 ed << "Target element "<<anElement->GetName()<<" Z= "
281 << targetNucleus.GetZ_asInt() << " A= "
282 << targetNucleus.GetA_asInt() << G4endl;
283 DumpState(aTrack,"ChooseHadronicInteraction",ed);
284 ed << " No HadronicInteraction found out" << G4endl;
285 G4Exception("G4HadronicProcess::PostStepDoIt", "had005", FatalException,
286 ed);
287 }
288
289 // Initialize the hadronic projectile from the track
290 thePro.Initialise(aTrack);
291 G4HadFinalState* result = 0;
292 G4int reentryCount = 0;
293
294 do
295 {
296 try
297 {
298 // Save random engine if requested for debugging
299 if (G4Hadronic_Random_File) {
300 CLHEP::HepRandom::saveEngineStatus(G4Hadronic_Random_File);
301 }
302 // Call the interaction
303 result = theInteraction->ApplyYourself( thePro, targetNucleus);
304 ++reentryCount;
305 }
306 catch(G4HadronicException aR)
307 {
309 aR.Report(ed);
310 ed << "Call for " << theInteraction->GetModelName() << G4endl;
311 ed << "Target element "<<anElement->GetName()<<" Z= "
312 << targetNucleus.GetZ_asInt()
313 << " A= " << targetNucleus.GetA_asInt() << G4endl;
314 DumpState(aTrack,"ApplyYourself",ed);
315 ed << " ApplyYourself failed" << G4endl;
316 G4Exception("G4HadronicProcess::PostStepDoIt", "had006", FatalException,
317 ed);
318 }
319
320 // Check the result for catastrophic energy non-conservation
321 result = CheckResult(thePro,targetNucleus, result);
322
323 if(reentryCount>100) {
325 ed << "Call for " << theInteraction->GetModelName() << G4endl;
326 ed << "Target element "<<anElement->GetName()<<" Z= "
327 << targetNucleus.GetZ_asInt()
328 << " A= " << targetNucleus.GetA_asInt() << G4endl;
329 DumpState(aTrack,"ApplyYourself",ed);
330 ed << " ApplyYourself does not completed after 100 attempts" << G4endl;
331 G4Exception("G4HadronicProcess::PostStepDoIt", "had006", FatalException,
332 ed);
333 }
334 }
335 while(!result);
336
338
340
341 FillResult(result, aTrack);
342
343 if (epReportLevel != 0) {
344 CheckEnergyMomentumConservation(aTrack, targetNucleus);
345 }
346 return theTotalResult;
347}
348
349
350void G4HadronicProcess::ProcessDescription(std::ostream& outFile) const
351{
352 outFile << "The description for this process has not been written yet.\n";
353}
354
355
356G4double G4HadronicProcess::XBiasSurvivalProbability()
357{
358 G4double result = 0;
360 G4double biasedProbability = 1.-std::exp(-nLTraversed);
361 G4double realProbability = 1-std::exp(-nLTraversed/aScaleFactor);
362 result = (biasedProbability-realProbability)/biasedProbability;
363 return result;
364}
365
366G4double G4HadronicProcess::XBiasSecondaryWeight()
367{
368 G4double result = 0;
370 result =
371 1./aScaleFactor*std::exp(-nLTraversed/aScaleFactor*(1-1./aScaleFactor));
372 return result;
373}
374
375void
377{
379
380 G4double rotation = CLHEP::twopi*G4UniformRand();
381 G4ThreeVector it(0., 0., 1.);
382
383 G4double efinal = aR->GetEnergyChange();
384 if(efinal < 0.0) { efinal = 0.0; }
385
386 // check status of primary
387 if(aR->GetStatusChange() == stopAndKill) {
390
391 // check its final energy
392 } else if(0.0 == efinal) {
395 ->GetAtRestProcessVector()->size() > 0)
398
399 // primary is not killed apply rotation and Lorentz transformation
400 } else {
403 G4double newE = efinal + mass;
404 G4double newP = std::sqrt(efinal*(efinal + 2*mass));
405 G4ThreeVector newPV = newP*aR->GetMomentumChange();
406 G4LorentzVector newP4(newE, newPV);
407 newP4.rotate(rotation, it);
408 newP4 *= aR->GetTrafoToLab();
410 newE = newP4.e() - mass;
411 if(G4HadronicProcess_debug_flag && newE <= 0.0) {
413 DumpState(aT,"Primary has zero energy after interaction",ed);
414 G4Exception("G4HadronicProcess::FillResults", "had011", JustWarning, ed);
415 }
416 if(newE < 0.0) { newE = 0.0; }
418 }
419
420 // check secondaries: apply rotation and Lorentz transformation
421 G4int nSec = aR->GetNumberOfSecondaries();
423 G4double weight = aT.GetWeight();
424
425 if (nSec > 0) {
426 G4double time0 = aT.GetGlobalTime();
427 for (G4int i = 0; i < nSec; ++i) {
429 theM.rotate(rotation, it);
430 theM *= aR->GetTrafoToLab();
431 aR->GetSecondary(i)->GetParticle()->Set4Momentum(theM);
432
433 // time of interaction starts from zero
434 G4double time = aR->GetSecondary(i)->GetTime();
435 if (time < 0.0) { time = 0.0; }
436
437 // take into account global time
438 time += time0;
439
440 G4Track* track = new G4Track(aR->GetSecondary(i)->GetParticle(),
441 time, aT.GetPosition());
442 G4double newWeight = weight*aR->GetSecondary(i)->GetWeight();
443 // G4cout << "#### ParticleDebug "
444 // <<GetProcessName()<<" "
445 // <<aR->GetSecondary(i)->GetParticle()->GetDefinition()->GetParticleName()<<" "
446 // <<aScaleFactor<<" "
447 // <<XBiasSurvivalProbability()<<" "
448 // <<XBiasSecondaryWeight()<<" "
449 // <<aT.GetWeight()<<" "
450 // <<aR->GetSecondary(i)->GetWeight()<<" "
451 // <<aR->GetSecondary(i)->GetParticle()->Get4Momentum()<<" "
452 // <<G4endl;
453 track->SetWeight(newWeight);
456 if (G4HadronicProcess_debug_flag) {
457 G4double e = track->GetKineticEnergy();
458 if (e <= 0.0) {
460 DumpState(aT,"Secondary has zero energy",ed);
461 ed << "Secondary " << track->GetDefinition()->GetParticleName()
462 << G4endl;
463 G4Exception("G4HadronicProcess::FillResults", "had011", JustWarning,ed);
464 }
465 }
466 }
467 }
468
469 aR->Clear();
470 return;
471}
472/*
473void
474G4HadronicProcess::FillTotalResult(G4HadFinalState* aR, const G4Track& aT)
475{
476 theTotalResult->Clear();
477 theTotalResult->ProposeLocalEnergyDeposit(0.);
478 theTotalResult->Initialize(aT);
479 theTotalResult->SetSecondaryWeightByProcess(true);
480 theTotalResult->ProposeTrackStatus(fAlive);
481 G4double rotation = CLHEP::twopi*G4UniformRand();
482 G4ThreeVector it(0., 0., 1.);
483
484 if(aR->GetStatusChange()==stopAndKill)
485 {
486 if( xBiasOn && G4UniformRand()<XBiasSurvivalProbability() )
487 {
488 theTotalResult->ProposeParentWeight( XBiasSurvivalProbability()*aT.GetWeight() );
489 }
490 else
491 {
492 theTotalResult->ProposeTrackStatus(fStopAndKill);
493 theTotalResult->ProposeEnergy( 0.0 );
494 }
495 }
496 else if(aR->GetStatusChange()!=stopAndKill )
497 {
498 if(aR->GetStatusChange()==suspend)
499 {
500 theTotalResult->ProposeTrackStatus(fSuspend);
501 if(xBiasOn)
502 {
503 G4ExceptionDescription ed;
504 DumpState(aT,"FillTotalResult",ed);
505 G4Exception("G4HadronicProcess::FillTotalResult", "had007", FatalException,
506 ed,"Cannot cross-section bias a process that suspends tracks.");
507 }
508 } else if (aT.GetKineticEnergy() == 0) {
509 theTotalResult->ProposeTrackStatus(fStopButAlive);
510 }
511
512 if(xBiasOn && G4UniformRand()<XBiasSurvivalProbability())
513 {
514 theTotalResult->ProposeParentWeight( XBiasSurvivalProbability()*aT.GetWeight() );
515 G4double newWeight = aR->GetWeightChange()*aT.GetWeight();
516 G4double newM=aT.GetParticleDefinition()->GetPDGMass();
517 G4double newE=aR->GetEnergyChange() + newM;
518 G4double newP=std::sqrt(newE*newE - newM*newM);
519 G4DynamicParticle * aNew =
520 new G4DynamicParticle(aT.GetParticleDefinition(), newE, newP*aR->GetMomentumChange());
521 aR->AddSecondary(G4HadSecondary(aNew, newWeight));
522 }
523 else
524 {
525 G4double newWeight = aR->GetWeightChange()*aT.GetWeight();
526 theTotalResult->ProposeParentWeight(newWeight); // This is multiplicative
527 if(aR->GetEnergyChange()>-.5)
528 {
529 theTotalResult->ProposeEnergy(aR->GetEnergyChange());
530 }
531 G4LorentzVector newDirection(aR->GetMomentumChange().unit(), 1.);
532 newDirection*=aR->GetTrafoToLab();
533 theTotalResult->ProposeMomentumDirection(newDirection.vect());
534 }
535 }
536 else
537 {
538 G4ExceptionDescription ed;
539 ed << "Call for " << theInteraction->GetModelName() << G4endl;
540 ed << "Target Z= "
541 << targetNucleus.GetZ_asInt()
542 << " A= " << targetNucleus.GetA_asInt() << G4endl;
543 DumpState(aT,"FillTotalResult",ed);
544 G4Exception("G4HadronicProcess", "had008", FatalException,
545 "use of unsupported track-status.");
546 }
547
548 if(GetProcessName() != "hElastic" && GetProcessName() != "HadronElastic"
549 && theTotalResult->GetTrackStatus()==fAlive
550 && aR->GetStatusChange()==isAlive)
551 {
552 // Use for debugging: G4double newWeight = theTotalResult->GetParentWeight();
553
554 G4double newKE = std::max(DBL_MIN, aR->GetEnergyChange());
555 G4DynamicParticle* aNew = new G4DynamicParticle(aT.GetParticleDefinition(),
556 aR->GetMomentumChange(),
557 newKE);
558 aR->AddSecondary(aNew);
559 aR->SetStatusChange(stopAndKill);
560
561 theTotalResult->ProposeTrackStatus(fStopAndKill);
562 theTotalResult->ProposeEnergy( 0.0 );
563
564 }
565 theTotalResult->ProposeLocalEnergyDeposit(aR->GetLocalEnergyDeposit());
566 theTotalResult->SetNumberOfSecondaries(aR->GetNumberOfSecondaries());
567
568 if(aR->GetStatusChange() != stopAndKill)
569 {
570 G4double newM=aT.GetParticleDefinition()->GetPDGMass();
571 G4double newE=aR->GetEnergyChange() + newM;
572 G4double newP=std::sqrt(newE*newE - newM*newM);
573 G4ThreeVector newPV = newP*aR->GetMomentumChange();
574 G4LorentzVector newP4(newE, newPV);
575 newP4.rotate(rotation, it);
576 newP4*=aR->GetTrafoToLab();
577 theTotalResult->ProposeMomentumDirection(newP4.vect().unit());
578 }
579
580 for(G4int i=0; i<aR->GetNumberOfSecondaries(); ++i)
581 {
582 G4LorentzVector theM = aR->GetSecondary(i)->GetParticle()->Get4Momentum();
583 theM.rotate(rotation, it);
584 theM*=aR->GetTrafoToLab();
585 aR->GetSecondary(i)->GetParticle()->Set4Momentum(theM);
586 G4double time = aR->GetSecondary(i)->GetTime();
587 if(time<0) time = aT.GetGlobalTime();
588
589 G4Track* track = new G4Track(aR->GetSecondary(i)->GetParticle(),
590 time,
591 aT.GetPosition());
592
593 G4double newWeight = aT.GetWeight()*aR->GetSecondary(i)->GetWeight();
594 if(xBiasOn) { newWeight *= XBiasSecondaryWeight(); }
595 track->SetWeight(newWeight);
596 track->SetTouchableHandle(aT.GetTouchableHandle());
597 theTotalResult->AddSecondary(track);
598 }
599
600 aR->Clear();
601 return;
602}
603*/
604
606{
607 xBiasOn = true;
608 aScaleFactor = aScale;
610 if( (it != "PhotonInelastic") &&
611 (it != "ElectroNuclear") &&
612 (it != "PositronNuclear") )
613 {
615 G4Exception("G4HadronicProcess::BiasCrossSectionByFactor", "had009", FatalException, ed,
616 "Cross-section biasing available only for gamma and electro nuclear reactions.");
617 }
618 if(aScale<100)
619 {
621 G4Exception("G4HadronicProcess::BiasCrossSectionByFactor", "had010", JustWarning,ed,
622 "Cross-section bias readjusted to be above safe limit. New value is 100");
623 aScaleFactor = 100.;
624 }
625}
626
628{
629 // check for catastrophic energy non-conservation, to re-sample the interaction
630
632 G4double nuclearMass(0);
633 if (theModel){
634
635 // Compute final-state total energy
636 G4double finalE(0.);
637 G4int nSec = result->GetNumberOfSecondaries();
638
639 nuclearMass = G4NucleiProperties::GetNuclearMass(aNucleus.GetA_asInt(),
640 aNucleus.GetZ_asInt());
641 if (result->GetStatusChange() != stopAndKill) {
642 // Interaction didn't complete, returned "do nothing" state => reset nucleus
643 // or the primary survived the interaction (e.g. electro-nuclear ) => keep nucleus
644 finalE=result->GetLocalEnergyDeposit() +
645 aPro.GetDefinition()->GetPDGMass() + result->GetEnergyChange();
646 if( nSec == 0 ){
647 // Since there are no secondaries, there is no recoil nucleus.
648 // To check energy balance we must neglect the initial nucleus too.
649 nuclearMass=0.0;
650 }
651 }
652 for (G4int i = 0; i < nSec; i++) {
653 finalE += result->GetSecondary(i)->GetParticle()->GetTotalEnergy();
654 }
655 G4double deltaE= nuclearMass + aPro.GetTotalEnergy() - finalE;
656
657 std::pair<G4double, G4double> checkLevels = theModel->GetFatalEnergyCheckLevels(); // (relative, absolute)
658 if (std::abs(deltaE) > checkLevels.second && std::abs(deltaE) > checkLevels.first*aPro.GetKineticEnergy()){
659 // do not delete result, this is a pointer to a data member;
660 result=0;
662 desc << "Warning: Bad energy non-conservation detected, will "
663 << (epReportLevel<0 ? "abort the event" : "re-sample the interaction") << G4endl
664 << " Process / Model: " << GetProcessName()<< " / " << theModel->GetModelName() << G4endl
665 << " Primary: " << aPro.GetDefinition()->GetParticleName()
666 << " (" << aPro.GetDefinition()->GetPDGEncoding() << "),"
667 << " E= " << aPro.Get4Momentum().e()
668 << ", target nucleus (" << aNucleus.GetZ_asInt() << ","<< aNucleus.GetA_asInt() << ")" << G4endl
669 << " E(initial - final) = " << deltaE << " MeV." << G4endl;
670 G4Exception("G4HadronicProcess:CheckResult()", "had012", epReportLevel<0 ? EventMustBeAborted : JustWarning,desc);
671 }
672 }
673 return result;
674}
675
676void
678 const G4Nucleus& aNucleus)
679{
680 G4int target_A=aNucleus.GetA_asInt();
681 G4int target_Z=aNucleus.GetZ_asInt();
682 G4double targetMass = G4NucleiProperties::GetNuclearMass(target_A,target_Z);
683 G4LorentzVector target4mom(0, 0, 0, targetMass);
684
685 G4LorentzVector projectile4mom = aTrack.GetDynamicParticle()->Get4Momentum();
686 G4int track_A = aTrack.GetDefinition()->GetBaryonNumber();
687 G4int track_Z = G4lrint(aTrack.GetDefinition()->GetPDGCharge());
688
689 G4int initial_A = target_A + track_A;
690 G4int initial_Z = target_Z + track_Z;
691
692 G4LorentzVector initial4mom = projectile4mom + target4mom;
693
694 // Compute final-state momentum for scattering and "do nothing" results
695 G4LorentzVector final4mom;
696 G4int final_A(0), final_Z(0);
697
699 if (theTotalResult->GetTrackStatus() != fStopAndKill) { // If it is Alive
700 // Either interaction didn't complete, returned "do nothing" state
701 // or the primary survived the interaction (e.g. electro-nucleus )
702 G4Track temp(aTrack);
703
704 // Use the final energy / momentum
707
708 if( nSec == 0 ){
709 // Interaction didn't complete, returned "do nothing" state
710 // - or suppressed recoil (e.g. Neutron elastic )
711 final4mom = temp.GetDynamicParticle()->Get4Momentum() + target4mom;
712 final_A = initial_A;
713 final_Z = initial_Z;
714 }else{
715 // The primary remains in final state (e.g. electro-nucleus )
716 final4mom = temp.GetDynamicParticle()->Get4Momentum();
717 final_A = track_A;
718 final_Z = track_Z;
719 // Expect that the target nucleus will have interacted,
720 // and its products, including recoil, will be included in secondaries.
721 }
722 }
723 if( nSec > 0 ) {
724 G4Track* sec;
725
726 for (G4int i = 0; i < nSec; i++) {
728 final4mom += sec->GetDynamicParticle()->Get4Momentum();
729 final_A += sec->GetDefinition()->GetBaryonNumber();
730 final_Z += G4lrint(sec->GetDefinition()->GetPDGCharge());
731 }
732 }
733
734 // Get level-checking information (used to cut-off relative checks)
735 G4String processName = GetProcessName();
737 G4String modelName("none");
738 if (theModel) modelName = theModel->GetModelName();
739 std::pair<G4double, G4double> checkLevels = epCheckLevels;
740 if (!levelsSetByProcess) {
741 if (theModel) checkLevels = theModel->GetEnergyMomentumCheckLevels();
742 checkLevels.first= std::min(checkLevels.first, epCheckLevels.first);
743 checkLevels.second=std::min(checkLevels.second, epCheckLevels.second);
744 }
745
746 // Compute absolute total-energy difference, and relative kinetic-energy
747 G4bool checkRelative = (aTrack.GetKineticEnergy() > checkLevels.second);
748
749 G4LorentzVector diff = initial4mom - final4mom;
750 G4double absolute = diff.e();
751 G4double relative = checkRelative ? absolute/aTrack.GetKineticEnergy() : 0.;
752
753 G4double absolute_mom = diff.vect().mag();
754 G4double relative_mom = checkRelative ? absolute_mom/aTrack.GetMomentum().mag() : 0.;
755
756 // Evaluate relative and absolute conservation
757 G4bool relPass = true;
758 G4String relResult = "pass";
759 if ( std::abs(relative) > checkLevels.first
760 || std::abs(relative_mom) > checkLevels.first) {
761 relPass = false;
762 relResult = checkRelative ? "fail" : "N/A";
763 }
764
765 G4bool absPass = true;
766 G4String absResult = "pass";
767 if ( std::abs(absolute) > checkLevels.second
768 || std::abs(absolute_mom) > checkLevels.second ) {
769 absPass = false ;
770 absResult = "fail";
771 }
772
773 G4bool chargePass = true;
774 G4String chargeResult = "pass";
775 if ( (initial_A-final_A)!=0
776 || (initial_Z-final_Z)!=0 ) {
777 chargePass = checkLevels.second < DBL_MAX ? false : true;
778 chargeResult = "fail";
779 }
780
781 G4bool conservationPass = (relPass || absPass) && chargePass;
782
783 std::stringstream Myout;
784 G4bool Myout_notempty(false);
785 // Options for level of reporting detail:
786 // 0. off
787 // 1. report only when E/p not conserved
788 // 2. report regardless of E/p conservation
789 // 3. report only when E/p not conserved, with model names, process names, and limits
790 // 4. report regardless of E/p conservation, with model names, process names, and limits
791 // negative -1.., as above, but send output to stderr
792
793 if( std::abs(epReportLevel) == 4
794 || ( std::abs(epReportLevel) == 3 && ! conservationPass ) ){
795 Myout << " Process: " << processName << " , Model: " << modelName << G4endl;
796 Myout << " Primary: " << aTrack.GetParticleDefinition()->GetParticleName()
797 << " (" << aTrack.GetParticleDefinition()->GetPDGEncoding() << "),"
798 << " E= " << aTrack.GetDynamicParticle()->Get4Momentum().e()
799 << ", target nucleus (" << aNucleus.GetZ_asInt() << ","
800 << aNucleus.GetA_asInt() << ")" << G4endl;
801 Myout_notempty=true;
802 }
803 if ( std::abs(epReportLevel) == 4
804 || std::abs(epReportLevel) == 2
805 || ! conservationPass ){
806
807 Myout << " "<< relResult <<" relative, limit " << checkLevels.first << ", values E/T(0) = "
808 << relative << " p/p(0)= " << relative_mom << G4endl;
809 Myout << " "<< absResult << " absolute, limit (MeV) " << checkLevels.second/MeV << ", values E / p (MeV) = "
810 << absolute/MeV << " / " << absolute_mom/MeV << G4endl;
811 Myout << " "<< chargeResult << " charge/baryon number balance " << (initial_Z-final_Z) << " / " << (initial_A-final_A) << " "<< G4endl;
812 Myout_notempty=true;
813
814 }
815 Myout.flush();
816 if ( Myout_notempty ) {
817 if (epReportLevel > 0) G4cout << Myout.str()<< G4endl;
818 else if (epReportLevel < 0) G4cerr << Myout.str()<< G4endl;
819 }
820}
821
822
824 const G4String& method,
826{
827 ed << "Unrecoverable error in the method " << method << " of "
828 << GetProcessName() << G4endl;
829 ed << "TrackID= "<< aTrack.GetTrackID() << " ParentID= "
830 << aTrack.GetParentID()
831 << " " << aTrack.GetParticleDefinition()->GetParticleName()
832 << G4endl;
833 ed << "Ekin(GeV)= " << aTrack.GetKineticEnergy()/CLHEP::GeV
834 << "; direction= " << aTrack.GetMomentumDirection() << G4endl;
835 ed << "Position(mm)= " << aTrack.GetPosition()/CLHEP::mm << ";";
836
837 if (aTrack.GetMaterial()) {
838 ed << " material " << aTrack.GetMaterial()->GetName();
839 }
840 ed << G4endl;
841
842 if (aTrack.GetVolume()) {
843 ed << "PhysicalVolume <" << aTrack.GetVolume()->GetName()
844 << ">" << G4endl;
845 }
846}
847/*
848G4ParticleDefinition* G4HadronicProcess::GetTargetDefinition()
849{
850 const G4Nucleus* nuc = GetTargetNucleus();
851 G4int Z = nuc->GetZ_asInt();
852 G4int A = nuc->GetA_asInt();
853 return G4ParticleTable::GetParticleTable()->GetIon(Z,A,0*eV);
854}
855*/
856/* end of file */
@ JustWarning
@ FatalException
@ EventMustBeAborted
G4ForceCondition
@ stopAndKill
G4HadronicProcessType
@ fHadronInelastic
G4ProcessType
@ fHadronic
@ fKillTrackAndSecondaries
@ fSuspend
@ fAlive
@ fStopAndKill
@ fStopButAlive
@ fPostponeToNextEvent
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
HepLorentzVector & rotate(double, const Hep3Vector &)
static void saveEngineStatus(const char filename[]="Config.conf")
Definition: Random.cc:175
void BuildPhysicsTable(const G4ParticleDefinition &)
G4Element * SampleZandA(const G4DynamicParticle *, const G4Material *, G4Nucleus &target)
G4double GetCrossSection(const G4DynamicParticle *, const G4Material *)
const G4ParticleDefinition * GetParticleDefinition() const
G4ParticleDefinition * GetDefinition() const
G4LorentzVector Get4Momentum() const
G4double GetKineticEnergy() const
G4double GetTotalEnergy() const
void Set4Momentum(const G4LorentzVector &momentum)
const G4String & GetName() const
Definition: G4Element.hh:127
void RegisterMe(G4HadronicInteraction *a)
G4double GetEnergyChange() const
const G4LorentzRotation & GetTrafoToLab() const
G4HadFinalStateStatus GetStatusChange() const
void SetTrafoToLab(const G4LorentzRotation &aT)
G4double GetLocalEnergyDeposit() const
G4int GetNumberOfSecondaries() const
const G4ThreeVector & GetMomentumChange() const
G4HadSecondary * GetSecondary(size_t i)
void Initialise(const G4Track &aT)
const G4ParticleDefinition * GetDefinition() const
G4LorentzRotation & GetTrafoToLab()
G4double GetKineticEnergy() const
const G4LorentzVector & Get4Momentum() const
G4double GetTotalEnergy() const
G4DynamicParticle * GetParticle()
G4double GetWeight() const
G4double GetTime() const
void Report(std::ostream &aS)
virtual const std::pair< G4double, G4double > GetFatalEnergyCheckLevels() const
virtual std::pair< G4double, G4double > GetEnergyMomentumCheckLevels() const
virtual G4HadFinalState * ApplyYourself(const G4HadProjectile &aTrack, G4Nucleus &targetNucleus)=0
const G4String & GetModelName() const
void DeRegister(G4HadronicProcess *)
void RegisterParticle(G4HadronicProcess *, const G4ParticleDefinition *)
static G4HadronicProcessStore * Instance()
void RegisterInteraction(G4HadronicProcess *, G4HadronicInteraction *)
void Register(G4HadronicProcess *)
void PrintInfo(const G4ParticleDefinition *)
void FillResult(G4HadFinalState *aR, const G4Track &aT)
G4HadProjectile thePro
void BiasCrossSectionByFactor(G4double aScale)
G4double GetMeanFreePath(const G4Track &aTrack, G4double, G4ForceCondition *)
G4HadronicInteraction * GetHadronicInteraction() const
G4ParticleChange * theTotalResult
virtual G4VParticleChange * PostStepDoIt(const G4Track &aTrack, const G4Step &aStep)
G4EnergyRangeManager * GetManagerPointer()
virtual void BuildPhysicsTable(const G4ParticleDefinition &)
G4HadronicProcess(const G4String &processName="Hadronic", G4ProcessType procType=fHadronic)
void CheckEnergyMomentumConservation(const G4Track &, const G4Nucleus &)
G4HadronicInteraction * ChooseHadronicInteraction(G4double kineticEnergy, G4Material *aMaterial, G4Element *anElement)
G4double GetElementCrossSection(const G4DynamicParticle *part, const G4Element *elm, const G4Material *mat=0)
void DumpState(const G4Track &, const G4String &, G4ExceptionDescription &)
G4HadFinalState * CheckResult(const G4HadProjectile &thePro, const G4Nucleus &targetNucleus, G4HadFinalState *result) const
virtual void ProcessDescription(std::ostream &outFile) const
void RegisterMe(G4HadronicInteraction *a)
virtual void PreparePhysicsTable(const G4ParticleDefinition &)
const G4String & GetName() const
Definition: G4Material.hh:177
static G4double GetNuclearMass(const G4double A, const G4double Z)
G4int GetA_asInt() const
Definition: G4Nucleus.hh:109
G4int GetZ_asInt() const
Definition: G4Nucleus.hh:115
void AddSecondary(G4Track *aSecondary)
G4double GetEnergy() const
const G4ThreeVector * GetMomentumDirection() const
void ProposeEnergy(G4double finalEnergy)
void ProposeMomentumDirection(G4double Px, G4double Py, G4double Pz)
virtual void Initialize(const G4Track &)
G4ProcessManager * GetProcessManager() const
G4double GetPDGCharge() const
const G4String & GetParticleName() const
G4ProcessVector * GetAtRestProcessVector(G4ProcessVectorTypeIndex typ=typeGPIL) const
G4int size() const
Definition: G4Step.hh:78
G4int first(char) const
G4TrackStatus GetTrackStatus() const
G4int GetTrackID() const
const G4ParticleDefinition * GetParticleDefinition() const
G4VPhysicalVolume * GetVolume() const
G4double GetWeight() const
void SetWeight(G4double aValue)
const G4ThreeVector & GetPosition() const
void SetTouchableHandle(const G4TouchableHandle &apValue)
G4double GetGlobalTime() const
G4ThreeVector GetMomentum() const
G4Material * GetMaterial() const
G4ParticleDefinition * GetDefinition() const
const G4DynamicParticle * GetDynamicParticle() const
const G4TouchableHandle & GetTouchableHandle() const
const G4ThreeVector & GetMomentumDirection() const
G4double GetKineticEnergy() const
G4int GetParentID() const
void SetKineticEnergy(const G4double aValue)
void SetMomentumDirection(const G4ThreeVector &aValue)
void ProposeTrackStatus(G4TrackStatus status)
void SetSecondaryWeightByProcess(G4bool)
void ProposeWeight(G4double finalWeight)
G4int GetNumberOfSecondaries() const
void ProposeLocalEnergyDeposit(G4double anEnergyPart)
void SetNumberOfSecondaries(G4int totSecondaries)
G4Track * GetSecondary(G4int anIndex) const
G4TrackStatus GetTrackStatus() const
const G4String & GetName() const
G4ParticleChange aParticleChange
Definition: G4VProcess.hh:289
void ClearNumberOfInteractionLengthLeft()
Definition: G4VProcess.hh:418
void SetProcessSubType(G4int)
Definition: G4VProcess.hh:403
G4double GetTotalNumberOfInteractionLengthTraversed() const
Definition: G4VProcess.hh:429
const G4String & GetProcessName() const
Definition: G4VProcess.hh:379
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *comments)
Definition: G4Exception.cc:41
std::ostringstream G4ExceptionDescription
Definition: globals.hh:76
int G4lrint(double ad)
Definition: templates.hh:163
#define DBL_MAX
Definition: templates.hh:83