Calling G4 actions in Julia
This is a very simple example of calling user actions in Julia from a C++ Geant4 application. We define the user actions in Julia language in the file MyCode.jl and call them from the C++ application. The name and signatures of the functions are important since the C++ will associate them in the corresponding inherited classes.
The C++ code is a single file G4example.cpp that defines the Geant4 the minimal set of classes to run a simulation.
- The main program is responsible of initializing Julia by calling
julia_initand loading the Julia code executing.jl_init() jl_eval_string("include(\"MyCode.jl\")"); - Each constructor of a user action class needs to initialize a C++ function pointer to the corresponding Julia function. This is done in the constructor to avoid any dynamic dispatch at runtime. For example, for the
EventActionclass:typedef void (*eventaction_f)(const G4Event*); class EventAction : public G4UserEventAction { public: EventAction() { beginevent_jl = (eventaction_f)(jl_unbox_voidpointer(jl_eval_string("@cfunction(begin_of_event_action, Nothing, (CxxPtr{G4Event},))"))); endevent_jl = (eventaction_f)(jl_unbox_voidpointer(jl_eval_string("@cfunction(end_of_event_action, Nothing, (CxxPtr{G4Event},))"))); } ... private: eventaction_f beginevent_jl; eventaction_f endevent_jl; }; - Finally the actions are called in the corresponding Geant4 classes. For example in the
EventActionclass:void EventAction::BeginOfEventAction(const G4Event* event) { beginevent_jl(event); } ...
You can also download this example as a Jupyter notebook and a plain Julia source file.
The C++ code is available as a source file and the Julia code is available as a source file.
Table of contents
- Loading the necessary Julia modules
- Building G4Example Application
- Run the application
- Display the results
Loading the necessary Julia modules
using Geant4_jll # Needed to locate the Geant4 installation directoryBuilding G4Example Application
The custom library is defined in the C++ file G4example.cpp. It is a single file to facilitate the building of the executable.
The attribute Geant4_jll.artifact_dir provides the path to the Geant4 installation directory. Sources are in the same location as this script.
cd(@__DIR__)
g4prefix = Geant4_jll.artifact_dir
jlprefix = dirname(Sys.BINDIR);We use the executables geant4-config and julia-config.jl to get the needed libraries and compiler/linker flags.
g4libs = read(`$g4prefix/bin/geant4-config --libs`, String) |> split
filter!(x -> x != "-lG4gdml", g4libs)
jllibs = read(`$jlprefix/share/julia/julia-config.jl --ldlibs`, String) |> split
append!(jllibs, ["-L$jlprefix/lib"])
cflags = read(`$g4prefix/bin/geant4-config --cflags`, String) |> split
ldflags = ["-Wl,-rpath,$g4prefix/lib", "-Wl,-rpath,$jlprefix/lib"];
Sys.KERNEL == :Linux && append!(ldflags, ["-Wl,--no-as-needed"]);Run the compilation and link command
Base.run(`c++ -O2 -fPIC $cflags -I$jlprefix/include/julia $ldflags $g4libs $jllibs
-o G4example.exe $(@__DIR__)/G4example.cpp`).exitcode == 0 || error("Compilation failed");In file included from /opt/hostedtoolcache/julia/1.12.2/x64/include/julia/julia.h:73,
from /home/runner/work/Geant4.jl/Geant4.jl/docs/src/examples/G4example.cpp:18:
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/gc-interface.h: In function ‘void jl_gc_wb_fresh(const void*, const void*)’:
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/gc-interface.h:243:47: warning: unused parameter ‘parent’ [-Wunused-parameter]
243 | STATIC_INLINE void jl_gc_wb_fresh(const void *parent, const void *ptr) JL_NOTSAFEPOINT {}
| ~~~~~~~~~~~~^~~~~~
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/gc-interface.h:243:67: warning: unused parameter ‘ptr’ [-Wunused-parameter]
243 | STATIC_INLINE void jl_gc_wb_fresh(const void *parent, const void *ptr) JL_NOTSAFEPOINT {}
| ~~~~~~~~~~~~^~~
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/gc-interface.h: In function ‘void jl_gc_wb_knownold(const void*, const void*)’:
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/gc-interface.h:246:50: warning: unused parameter ‘parent’ [-Wunused-parameter]
246 | STATIC_INLINE void jl_gc_wb_knownold(const void *parent, const void *ptr) JL_NOTSAFEPOINT {}
| ~~~~~~~~~~~~^~~~~~
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/gc-interface.h:246:70: warning: unused parameter ‘ptr’ [-Wunused-parameter]
246 | STATIC_INLINE void jl_gc_wb_knownold(const void *parent, const void *ptr) JL_NOTSAFEPOINT {}
| ~~~~~~~~~~~~^~~
In file included from /opt/hostedtoolcache/julia/1.12.2/x64/include/julia/julia.h:2446:
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/julia_locks.h: In constructor ‘jl_unique_gcsafe_lock::jl_unique_gcsafe_lock(std::mutex&)’:
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/julia_locks.h:115:48: warning: declaration of ‘native’ shadows a member of ‘jl_unique_gcsafe_lock’ [-Wshadow]
115 | explicit jl_unique_gcsafe_lock(std::mutex &native) JL_NOTSAFEPOINT_ENTER
| ~~~~~~~~~~~~^~~~~~
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/julia_locks.h:114:34: note: shadowed declaration is here
114 | std::unique_lock<std::mutex> native;
| ^~~~~~
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/julia_locks.h: In constructor ‘jl_unique_gcsafe_lock::jl_unique_gcsafe_lock(std::mutex&)’:
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/julia_locks.h:115:48: warning: declaration of ‘native’ shadows a member of ‘jl_unique_gcsafe_lock’ [-Wshadow]
115 | explicit jl_unique_gcsafe_lock(std::mutex &native) JL_NOTSAFEPOINT_ENTER
| ~~~~~~~~~~~~^~~~~~
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/julia_locks.h:114:34: note: shadowed declaration is here
114 | std::unique_lock<std::mutex> native;
| ^~~~~~
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/julia_locks.h: In constructor ‘jl_unique_gcsafe_lock::jl_unique_gcsafe_lock(std::mutex&)’:
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/julia_locks.h:115:48: warning: declaration of ‘native’ shadows a member of ‘jl_unique_gcsafe_lock’ [-Wshadow]
115 | explicit jl_unique_gcsafe_lock(std::mutex &native) JL_NOTSAFEPOINT_ENTER
| ~~~~~~~~~~~~^~~~~~
/opt/hostedtoolcache/julia/1.12.2/x64/include/julia/julia_locks.h:114:34: note: shadowed declaration is here
114 | std::unique_lock<std::mutex> native;
| ^~~~~~
Run the application
We need to set the variable JULIA_PROJECT pointing to correctly setup Julia environment.
withenv("JULIA_PROJECT" => "@.", "G4NUMTHREADS" => "4") do
Base.run(`./G4example.exe`).exitcode == 0 || error("Execution failed")
endtrueDisplay the results
println("=====> The file edepHist.png should have been saved")=====> The file edepHist.png should have been saved

This page was generated using Literate.jl.