B2a example crash

Please fill out the following information to help in answering your question, and also see tips for posting code snippets. If you don’t provide this information it will take more time to help with your problem!

Geant4 Version: 11.2.0
Operating System: MacOS 14.2


Just by changing the direction of the particle gun in basic/B2/Ba2 example I get a EXC_BAD_ACCESS crash.

diff --git a/examples/basic/B2/B2a/src/PrimaryGeneratorAction.cc b/examples/basic/B2/B2a/src/PrimaryGeneratorAction.cc
index bb87b9b08e..19ae7902db 100644
--- a/examples/basic/B2/B2a/src/PrimaryGeneratorAction.cc
+++ b/examples/basic/B2/B2a/src/PrimaryGeneratorAction.cc
@@ -55,7 +55,7 @@ PrimaryGeneratorAction::PrimaryGeneratorAction()
     = G4ParticleTable::GetParticleTable()->FindParticle("proton");
 
   fParticleGun->SetParticleDefinition(particleDefinition);
-  fParticleGun->SetParticleMomentumDirection(G4ThreeVector(0.,0.,1.));
+  fParticleGun->SetParticleMomentumDirection(G4ThreeVector(0.,0.,-1.));
   fParticleGun->SetParticleEnergy(3.0*GeV);
 }

The trace back is:

* thread #2, stop reason = EXC_BAD_ACCESS (code=1, address=0x3b7f61480)
  * frame #0: 0x0000000101491f98 libG4geometry.dylib`G4VPhysicalVolume::GetRotation() + 40
    frame #1: 0x00000001014d1370 libG4geometry.dylib`G4VoxelNavigation::ComputeStep(CLHEP::Hep3Vector const&, CLHEP::Hep3Vector const&, double, double&, G4NavigationHistory&, bool&, CLHEP::Hep3Vector&, bool&, bool&, G4VPhysicalVolume**, int&) + 760
    frame #2: 0x00000001014b2aec libG4geometry.dylib`G4Navigator::ComputeStep(CLHEP::Hep3Vector const&, CLHEP::Hep3Vector const&, double, double&) + 1080
    frame #3: 0x000000010335e6d8 libG4processes.dylib`G4Transportation::AlongStepGetPhysicalInteractionLength(G4Track const&, double, double, double&, G4GPILSelection*) + 1080
    frame #4: 0x0000000100c188b4 libG4tracking.dylib`G4SteppingManager::DefinePhysicalStepLength() + 600
    frame #5: 0x0000000100c1822c libG4tracking.dylib`G4SteppingManager::Stepping() + 388
    frame #6: 0x0000000100c2aeb8 libG4tracking.dylib`G4TrackingManager::ProcessOneTrack(G4Track*) + 872
    frame #7: 0x0000000100b98afc libG4event.dylib`G4EventManager::DoProcessing(G4Event*) + 1888
    frame #8: 0x0000000100e25410 libG4run.dylib`G4WorkerTaskRunManager::ProcessOneEvent(int) + 60
    frame #9: 0x0000000100e25380 libG4run.dylib`G4WorkerTaskRunManager::DoEventLoop(int, char const*, int) + 232
    frame #10: 0x0000000100e26bec libG4run.dylib`G4WorkerTaskRunManager::DoWork() + 408
    frame #11: 0x0000000100e11b4c libG4run.dylib`std::__1::__packaged_task_func<std::__1::enable_if<std::is_void<void>::value, void>::type PTL::TaskGroup<void, void, 0l>::exec<G4TaskRunManager::AddEventTask(int)::$_4, void>(G4TaskRunManager::AddEventTask(int)::$_4)::'lambda'(), std::__1::allocator<std::__1::enable_if<std::is_void<void>::value, void>::type PTL::TaskGroup<void, vG4TaskRunManager::AddEventTask(int)::$_4)::'lambda'(), std::__1::allocator<std::__1::enable_if<std::is_void<void>::value, void>::type PTL::TaskGroup<void, void, 0l>::exec<G4TaskRunManager::AddEventTask(int)::$_4, void>(G4TaskRunManager::AddEventTask(int)::$_4)::'lambda'()>, void ()>::operator()() + 44
    frame #12: 0x0000000100e11c28 libG4run.dylib`std::__1::packaged_task<void ()>::operator()() + 80
    frame #13: 0x0000000100c5d668 libG4ptl.2.dylib`PTL::ThreadPool::execute_thread(PTL::VUserTaskQueue*) + 996
    frame #14: 0x0000000100c5cda4 libG4ptl.2.dylib`PTL::ThreadPool::start_thread(PTL::ThreadPool*, std::__1::vector<std::__1::shared_ptr<PTL::ThreadData>, std::__1::allocator<std::__1::shared_ptr<PTL::ThreadData>>>*, long) + 688
    frame #15: 0x0000000100c63afc libG4ptl.2.dylib`void* std::__1::__thread_proxy[abi:v160006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(PTL::ThreadPool*, std::__1::vector<std::__1::shared_ptr<PTL::ThreadData>, std::__1::allocator<std::__1::shared_ptr<PTL::ThreadData>>>*, long), PTL::ThreadPool*, std::__1::vector<std::__1::shared_ptr<PTL::ThreadData>, std::__1::allocator<std::__1::shared_ptr<PTL::ThreadData>>>*, unsigned long>>(void*) + 56
    frame #16: 0x0000000185132034 libsystem_pthread.dylib`_pthread_start + 136
(lldb) 
* thread #2, stop reason = EXC_BAD_ACCESS (code=1, address=0x3b7f61480)
  * frame #0: 0x0000000101491f98 libG4geometry.dylib`G4VPhysicalVolume::GetRotation() + 40
    frame #1: 0x00000001014d1370 libG4geometry.dylib`G4VoxelNavigation::ComputeStep(CLHEP::Hep3Vector const&, CLHEP::Hep3Vector const&, double, double&, G4NavigationHistory&, bool&, CLHEP::Hep3Vector&, bool&, bool&, G4VPhysicalVolume**, int&) + 760
    frame #2: 0x00000001014b2aec libG4geometry.dylib`G4Navigator::ComputeStep(CLHEP::Hep3Vector const&, CLHEP::Hep3Vector const&, double, double&) + 1080
    frame #3: 0x000000010335e6d8 libG4processes.dylib`G4Transportation::AlongStepGetPhysicalInteractionLength(G4Track const&, double, double, double&, G4GPILSelection*) + 1080
    frame #4: 0x0000000100c188b4 libG4tracking.dylib`G4SteppingManager::DefinePhysicalStepLength() + 600
    frame #5: 0x0000000100c1822c libG4tracking.dylib`G4SteppingManager::Stepping() + 388
    frame #6: 0x0000000100c2aeb8 libG4tracking.dylib`G4TrackingManager::ProcessOneTrack(G4Track*) + 872
    frame #7: 0x0000000100b98afc libG4event.dylib`G4EventManager::DoProcessing(G4Event*) + 1888
    frame #8: 0x0000000100e25410 libG4run.dylib`G4WorkerTaskRunManager::ProcessOneEvent(int) + 60
    frame #9: 0x0000000100e25380 libG4run.dylib`G4WorkerTaskRunManager::DoEventLoop(int, char const*, int) + 232
    frame #10: 0x0000000100e26bec libG4run.dylib`G4WorkerTaskRunManager::DoWork() + 408
    frame #11: 0x0000000100e11b4c libG4run.dylib`std::__1::__packaged_task_func<std::__1::enable_if<std::is_void<void>::value, void>::type PTL::TaskGroup<void, void, 0l>::exec<G4TaskRunManager::AddEventTask(int)::$_4, void>(G4TaskRunManager::AddEventTask(int)::$_4)::'lambda'(), std::__1::allocator<std::__1::enable_if<std::is_void<void>::value, void>::type PTL::TaskGroup<void, void, 0l>::exec<G4TaskRunManager::AddEventTask(int)::$_4, void>(G4TaskRunManager::AddEventTask(int)::$_4)::'lambda'()>, void ()>::operator()() + 44
    frame #12: 0x0000000100e11c28 libG4run.dylib`std::__1::packaged_task<void ()>::operator()() + 80
    frame #13: 0x0000000100c5d668 libG4ptl.2.dylib`PTL::ThreadPool::execute_thread(PTL::VUserTaskQueue*) + 996
    frame #14: 0x0000000100c5cda4 libG4ptl.2.dylib`PTL::ThreadPool::start_thread(PTL::ThreadPool*, std::__1::vector<std::__1::shared_ptr<PTL::ThreadData>, std::__1::allocator<std::__1::shared_ptr<PTL::ThreadData>>>*, long) + 688
    frame #15: 0x0000000100c63afc libG4ptl.2.dylib`void* std::__1::__thread_proxy[abi:v160006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(PTL::ThreadPool*, std::__1::vector<std::__1::shared_ptr<PTL::ThreadData>, std::__1::allocator<std::__1::shared_ptr<PTL::ThreadData>>>*, long), PTL::ThreadPool*, std::__1::vector<std::__1::shared_ptr<PTL::ThreadData>, std::__1::allocator<std::__1::shared_ptr<PTL::ThreadData>>>*, unsigned long>>(void*) + 56
    frame #16: 0x0000000185132034 libsystem_pthread.dylib`_pthread_start + 136

This is because, by default in the example the initial position is located on the world boundary (which, I agree, makes no sense), so shooting in the opposite direction you’re shooting directly outside the world, without entering the geometry…

Quoting the code in the example (PrimaryGeneratorAction.cc:91)…

  // Note that this particular case of starting a primary particle on the world boundary
  // requires shooting in a direction towards inside the world.
  fParticleGun->SetParticlePosition(G4ThreeVector(0., 0., -worldZHalfLength));

Thanks. The question is, should it crash? or just return a out of world step?

@mato, I don’t think it “should” crash, but this is a pretty weird edge case (pun intended).

The “out of world” step is generated for a G4Step that is already starting (pre-step point) in a valid volume, and the computed post-step point lands on the World boundary.

The problem is that when the primary particle (G4PrimaryParticle) is converted into a track, the attempt to map its position to the volume it is entering fails, because the direction vector is pointing outside the World. So you end up with a track where its own “current volume” is null, even before a single step gets taken.

I still think that crashing is bad. There are exceptions and other mechanisms to return to the user in a more user friendly, indicating for instance that the starting point is outside the world or wrong direction.

It is your code that crashes, not G4 internals. Based on the geometry “you” created (yes, I know you’ve started from an example, but by modifying it, you’re taking ownership), you need to ensure that you specify valid initial conditions. Starting a primary particle outside the world is not a valid initial condition.

Why do you assert that it crashes in my code? The crash is occurring within the libG4geometry library, as indicated by the traceback. Geant4 is designed to gracefully handle situations where assumptions are not met, it seems the current behavior is not consistent. If you think that a fix is not needed to make Geant4 more robust in this situation is fine with me. Passing the problem to the user, saying that he has taken ownership of some code may not be the most suitable approach in this context.

_ZN17G4VPhysicalVolume11GetRotationEv at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4geometry.dylib (unknown line)
_ZN17G4VoxelNavigation11ComputeStepERKN5CLHEP10Hep3VectorES3_dRdR19G4NavigationHistoryRbRS1_S7_S7_PP17G4VPhysicalVolumeRi at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4geometry.dylib (unknown line)
_ZN11G4Navigator11ComputeStepERKN5CLHEP10Hep3VectorES3_dRd at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4geometry.dylib (unknown line)
_ZN16G4Transportation37AlongStepGetPhysicalInteractionLengthERK7G4TrackddRdP15G4GPILSelection at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4processes.dylib (unknown line)
_ZN17G4SteppingManager24DefinePhysicalStepLengthEv at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4tracking.dylib (unknown line)
_ZN17G4SteppingManager8SteppingEv at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4tracking.dylib (unknown line)
_ZN17G4TrackingManager15ProcessOneTrackEP7G4Track at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4tracking.dylib (unknown line)
_ZN14G4EventManager12DoProcessingEP7G4Event at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4event.dylib (unknown line)
_ZN12G4RunManager15ProcessOneEventEi at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4run.dylib (unknown line)
_ZN12G4RunManager11DoEventLoopEiPKci at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4run.dylib (unknown line)
_ZN12G4RunManager6BeamOnEiPKci at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4run.dylib (unknown line)

In this case a user should eventually also read first the documentation, shouldn’t he? :wink:

I perfectly understand your concern, the point is that there’re edge cases like this one or like when a world surface gets shared with the detector geometry, that putting in place a proper fix to gracefully indicate the setup is ill defined, might not be that easy or not at all convenient in order not to impeach performance in general. It is important these edge cases are properly documented, though. And seems to me this is the case!

Gabriele, these are not edge cases. Any primary particle located outside the world volume causes a crash. This may happen by reading an input file of primary particles or some scan you do, or some misconfigured general particle source. Adding a G4VSolid::Inside(…) for the primary vertex does not probably add too much overhead, in particular since the World volume is usually quite trivial solid.
Can you point me where is documented that a primary vertex must be inside the world volume or the program will crash.

Checking if the initial point is outside the world is something that can be easily done, sure.
It is something different though from what discussed here… a point on the surface of the world is in principle not forbidden.

I do not know if the two cases are really different. The only thing I know is that the traceback is exactly the same. Point on surface & outside direction == point outside.

[95775] signal (11.2): Segmentation fault: 11
in expression starting at /Users/mato/Development/Geant4.jl/examples/basic/B2/B2a.jl:88
_ZN17G4VPhysicalVolume11GetRotationEv at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4geometry.dylib (unknown line)
_ZN17G4VoxelNavigation11ComputeStepERKN5CLHEP10Hep3VectorES3_dRdR19G4NavigationHistoryRbRS1_S7_S7_PP17G4VPhysicalVolumeRi at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4geometry.dylib (unknown line)
_ZN11G4Navigator11ComputeStepERKN5CLHEP10Hep3VectorES3_dRd at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4geometry.dylib (unknown line)
_ZN16G4Transportation37AlongStepGetPhysicalInteractionLengthERK7G4TrackddRdP15G4GPILSelection at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4processes.dylib (unknown line)
_ZN17G4SteppingManager24DefinePhysicalStepLengthEv at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4tracking.dylib (unknown line)
_ZN17G4SteppingManager8SteppingEv at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4tracking.dylib (unknown line)
_ZN17G4TrackingManager15ProcessOneTrackEP7G4Track at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4tracking.dylib (unknown line)
_ZN14G4EventManager12DoProcessingEP7G4Event at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4event.dylib (unknown line)
_ZN12G4RunManager15ProcessOneEventEi at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4run.dylib (unknown line)
_ZN12G4RunManager11DoEventLoopEiPKci at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4run.dylib (unknown line)
_ZN12G4RunManager6BeamOnEiPKci at /Users/mato/.julia/artifacts/4afb5743b029965f72ec5a970d92d5344ce830d2/lib/libG4run.dylib (unknown line)

The effect is obviously the same (attempt to locate a point outside the world), but the two cases are different, you name it!
In any case, a protection to address this last case is now proposed for inclusion in the master.

Thanks. But the proposed changes will only add a protection for G4ParticleGun if I understand correctly. To make it more general the protection would need to go to G4Event::AddPrimaryVertex (35 examples use this call directly) but it is a bit strange since there is no connection to geometry at this point, or in G4EventManager::DoProcessing(G4Event*), where there are already checks whether the geometry is closed and the navigator is reset.