Segmentation fault caused by G4Navigator and GDML structure

Dear Geant4 experts,

I am working with a rather complex geometry which is parsed from a GDML file. Some volumes need to have a magnetic field attached to them which is done with a custom G4MagneticField class called
“T2KLineCurrentMagField” (called this way since it is a straight up modified version of the G4LineCurrent class). The magnetic field needs to be using the coordinate system of the volume where the field is located.
In order to obtain the transformation, the G4Navigator class is used as shown in the documentation and some examples.

The transformation to local coordinates is obtained in the constructor of the Magnetic field class:

T2KLineCurrentMagField::T2KLineCurrentMagField(G4double pFieldConstant,G4ThreeVector hc)
{  
   fFieldConstant = pFieldConstant ;
   hornCenter = hc;


   G4Navigator* theNavigator = 
                    G4TransportationManager::GetTransportationManager()->
                                                 GetNavigatorForTracking();
   
   

   if ( theNavigator->GetWorldVolume() )
      fNavigator->SetWorldVolume(theNavigator->GetWorldVolume());
   
  // To make sure the Geometry is closed
  G4GeometryManager* geomManager = G4GeometryManager::GetInstance();

  if (!geomManager->IsGeometryClosed()) {
     geomManager->OpenGeometry();
     geomManager->CloseGeometry(true);
  }

   fNavigator->LocateGlobalPointAndSetup(hc); // This is the problematic line: causes segmentation fault
   
   fTouchable = fNavigator->CreateTouchableHistoryHandle(); // We can use fTouchable->GetHistory()->GetTopTransform() to go from global to local coords.

}

In the written code above a segmentation fault error occurs upon calling the “LocateGlobalPointAndSetup” method as Geant4 starts up. From my understanding, this method is important to obtain the volume whose local frame we are interested in.
A similar problem is described here: https://micewww.pp.rl.ac.uk/issues/1790.
The constructor is called in the detector construction to attach the magnetic field to relevant volumes.

Here is the output from valgrind:
"
==1301078== Invalid read of size 8
==1301078== at 0xC50F334: G4Navigator::LocateGlobalPointAndSetup(CLHEP::Hep3Vector const&, CLHEP::Hep3Vector const*, bool, bool) (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4geometry.so)
==1301078== by 0x412470: T2KLineCurrentMagField::T2KLineCurrentMagField(double, CLHEP::Hep3Vector) (T2KLineCurrentMagField.cc:78)
==1301078== by 0x40CA5B: DetectorConstruction::Construct() (DetectorConstruction.cc:370)
==1301078== by 0x8E48F75: G4RunManager::InitializeGeometry() (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4run.so)
==1301078== by 0x8E48D4F: G4RunManager::Initialize() (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4run.so)
==1301078== by 0x8E547D8: G4MTRunManager::Initialize() (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4run.so)
==1301078== by 0x8E63FF5: G4RunMessenger::SetNewValue(G4UIcommand*, G4String) (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4run.so)
==1301078== by 0xD01DFB6: G4UIcommand::DoIt(G4String) (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4intercoms.so)
==1301078== by 0xD0355EF: G4UImanager::ApplyCommand(char const*) (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4intercoms.so)
==1301078== by 0xD00E3F6: G4UIbatch::ExecCommand(G4String const&) (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4intercoms.so)
==1301078== by 0xD00F6E7: G4UIbatch::SessionStart() (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4intercoms.so)
==1301078== by 0xD0365EB: G4UImanager::ExecuteMacroFile(char const*) (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4intercoms.so)
==1301078== Address 0x10 is not stack’d, malloc’d or (recently) free’d
==1301078==
==1301078==
==1301078== Process terminating with default action of signal 11 (SIGSEGV)
==1301078== Access not within mapped region at address 0x10
==1301078== at 0xC50F334: G4Navigator::LocateGlobalPointAndSetup(CLHEP::Hep3Vector const&, CLHEP::Hep3Vector const*, bool, bool) (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4geometry.so)
==1301078== by 0x412470: T2KLineCurrentMagField::T2KLineCurrentMagField(double, CLHEP::Hep3Vector) (T2KLineCurrentMagField.cc:78)
==1301078== by 0x40CA5B: DetectorConstruction::Construct() (DetectorConstruction.cc:370)
==1301078== by 0x8E48F75: G4RunManager::InitializeGeometry() (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4run.so)
==1301078== by 0x8E48D4F: G4RunManager::Initialize() (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4run.so)
==1301078== by 0x8E547D8: G4MTRunManager::Initialize() (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4run.so)
==1301078== by 0x8E63FF5: G4RunMessenger::SetNewValue(G4UIcommand*, G4String) (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4run.so)
==1301078== by 0xD01DFB6: G4UIcommand::DoIt(G4String) (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4intercoms.so)
==1301078== by 0xD0355EF: G4UImanager::ApplyCommand(char const*) (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4intercoms.so)
==1301078== by 0xD00E3F6: G4UIbatch::ExecCommand(G4String const&) (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4intercoms.so)
==1301078== by 0xD00F6E7: G4UIbatch::SessionStart() (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4intercoms.so)
==1301078== by 0xD0365EB: G4UImanager::ExecuteMacroFile(char const*) (in /home/ppe/t/tmaurin/geant4_fs/geant4.10.07-install2/lib64/libG4intercoms.so)
==1301078== If you believe this happened as a result of a stack
==1301078== overflow in your program’s main thread (unlikely but
==1301078== possible), you can try to increase the size of the
==1301078== main thread stack using the --main-stacksize= flag.
==1301078== The main thread stack size used in this run was 8388608.
==1301078==
==1301078== HEAP SUMMARY:
==1301078== in use at exit: 5,523,386 bytes in 80,438 blocks
==1301078== total heap usage: 810,961 allocs, 730,523 frees, 291,770,843 bytes allocated
==1301078==
==1301078== LEAK SUMMARY:
==1301078== definitely lost: 0 bytes in 0 blocks
==1301078== indirectly lost: 0 bytes in 0 blocks
==1301078== possibly lost: 308,764 bytes in 2,833 blocks
==1301078== still reachable: 5,214,622 bytes in 77,605 blocks
==1301078== of which reachable via heuristic:
==1301078== stdstring : 674,344 bytes in 17,033 blocks
==1301078== newarray : 400 bytes in 2 blocks
==1301078== suppressed: 0 bytes in 0 blocks
==1301078== Rerun with --leak-check=full to see details of leaked memory
==1301078==
==1301078== For lists of detected and suppressed errors, rerun with: -s
==1301078== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
"

I have made sure that the “hc” G4ThreeVector describes the coordinates of an actual volume present in the World Volume.

Is there a big mistake or something that I’m missing that could solve this segmentation fault to occur? (I have just started using Geant4 this September so I know very little about its intricaties).
Thank you for your time and for any help available.

Théo Maurin

Don’t use the “NavigatorForTracking()” for this purpose: the Navigator maintains a cache of the last position information, so that following a track can be fast. If you interfere with that by finding a point yourself, it can cause problems down the road.

Instead, create your own G4Navigator instance. To avoid memory churn, you can make it a G4ThreadLocal data member (pointer), and instantiate it on the first call through via the usual “if pointer==0” condition.

Second, you need to set the world volume of your local G4Navigator after doing the “geometry closed” test. You can use the tracking navigator to get the world volume, as you do above, and then pass that into your local navigator.

1 Like

Thank you very much for your quick response!

I understand that I should not play around with the Tracking Navigator in this case but here it seems to be used only to get the World Volume. (I could also pass in the world volume through the constructor since the field object is created in the Detector Construction step.)
I have stolen this approach from there (line 67 - 87):

fNavigator is the local navigator I use to get the transformation. It is an attribute of the Magnetic Field class and is created like so : “G4Navigator* fNavigator = new G4Navigator();”

I have swap the world volume allocation as you indicated!

However it seems that the segmentation fault is still here and still comes from fNavigator’s method call “LocateGlobalPointAndSetup”. If this line is commented, there is no segmentation fault upon running.
I’m really not sure why that is the case.

1 Like

Oh! Sorry, I misunderstood. You’re doing exactly the right thing, then. In my own code, I don’t use LocateGlobalPointAndSetup. Instead, we instantiate a new Touchable (ownership is transferred to the calling code), and we call

    LocateGlobalPointAndUpdateTouchable(pos, touchable, false);

No worries! Thank you for the input. I’m still not sure about how to solve this segmentation fault.
Do you think doing like in your own code (instantiate a new Touchable and then going through “LocateGlobalPointAndUpdateTouchable” ) could solve it? I see it as very equivalent in this case.

What you are trying to do is tricky. You are trying to ensure that the Navigator is in a fit state before Geant4 itself has initialised it.

Instead it is best to avoid trying to do this. Your local field requires a touchable in order to transform from the global coordinate system to the local one. In the constructor you can use a (smart, reference counted) handle to a null touchable, and the first time that the field is called capture it. The touchable will have been set by Geant4, and by holding a handle to it, you will ensure that this object will not be deleted by G4.

// In the class declaration
G4TouchableHistoryHandle fRegionTouchableHdl( nullptr );
G4Navigator  *fNavigatorForTracking;

In the constructor initialise fNavigatorForTracking as you did.

Then in the method where it is used (during tracking or in the first step):

if( fRegionTouchableHdl->() == nullptr ){ 
   fRegionTouchableHdl = navigatorForTracking->CreateTouchableHistoryHandle();
}

If your region contains other volume, you will need to take more care.
As the first particle which encounters happens to be inside a daughter volume of the ‘top’ volume of your region, you would need to add code to check this, and to ‘go up’ the touchable until it represents the top volume of your region.

2 Likes

Thank you for your advices!
I have changed the code such that there is no need to get the NavigatorForTracking which removes potential initialisation issues. The world volume is obtained as a parameter of the constructor and fNavigator is a pointer to a G4Navigator object dynamically initialised in the class declaration.

The G4TouchableHistoryHandle seems to be created and obtained from the G4Navigator without problem when I omit the line calling the method “LocateGlobalPointAndUpdateTouchable” (which causes the segmentation fault).

Going up the touchable to get the relevant volume (I assume using MoveUpHistory() and logicalVolume comparison with string name or directly with the object) is a nice suggestion to get the frame we want, thank you!

The problem remains with that segmentation fault that I cannot understand that really comes from the LocateGlobalPointAndSetup method which is quite important to obtain the volume of interest.

Here is the class declaration:

#ifndef T2KLINECURRENTMAGFIELD_HH
#define T2KLINECURRENTMAGFIELD_HH

#include "G4MagneticField.hh"
#include "globals.hh"
#include "G4Navigator.hh"
#include "G4TransportationManager.hh"

class T2KLineCurrentMagField : public G4MagneticField
{
  public:  // with description

    T2KLineCurrentMagField(G4double pFieldConstant);
    T2KLineCurrentMagField(G4double pFieldConstant, G4ThreeVector hc,G4VPhysicalVolume* worldVolume); // hc : "Horn Center", this is the constructor I would like to use
   ~T2KLineCurrentMagField();

    void GetFieldValue(const G4double yTrack[],
                             G4double B[] ) const;                                                 
    G4Field* Clone() const;

  private:
    G4double fFieldConstant = 0.0;
    G4ThreeVector hornCenter; 
    G4TouchableHistoryHandle fTouchable;
    G4Navigator* fNavigator = new G4Navigator(); // Used to get touchables to then get the transformation from global to local
    
};

#endif

And this is the constructor definition where the segmentation fault occurs upon calling “LocateGlobalPointAndSetup”. Commenting the line out makes the code run fine, but of course there is no specification of the point at which the volume of interest is (the hornCenter or hc variables) :

T2KLineCurrentMagField::T2KLineCurrentMagField(G4double pFieldConstant,const G4ThreeVector hc,G4VPhysicalVolume* worldVolume)
{  
   fFieldConstant = pFieldConstant ;
   hornCenter = hc;

  G4GeometryManager* geomManager = G4GeometryManager::GetInstance();

  if (!geomManager->IsGeometryClosed()) {
     geomManager->OpenGeometry();
     geomManager->CloseGeometry(true);
  }

   fNavigator->LocateGlobalPointAndSetup(hc); // causes segmentation faults
   
   fTouchable = fNavigator->CreateTouchableHistoryHandle(); // We can use fTouchable->GetHistory()->GetTopTransform() to go from global to local coords.
   

}

Dear everyone,

As I wrote my message just above I realise that I removed the line that attributed a world volume to fNavigator when I removed my dependance on getting the NavigatorForTracking. This is what caused problems, fNavigator would still have a nullptr as a world volume. Upon attributing the world volume by simply writing:
fNavigator->SetWorldVolume(worldVolume);

the segmentation faults disappeared. Sorry about that!

Thank you for all the help, it seems that the code runs now and probably with a more conventional approach than how I initially wrote it! The problem was indeed linked to getting the NavigatorForTracking too early!

Cheers,
Théo Maurin

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.