Skip to content

Commit

Permalink
MT for JuliaAction example
Browse files Browse the repository at this point in the history
  • Loading branch information
peremato committed Dec 4, 2024
1 parent 90584bb commit 51c9f08
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 37 deletions.
47 changes: 44 additions & 3 deletions advanced/EmbedJulia/G4example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
//#include "G4SystemOfUnits.hh"
#include "globals.hh"
#include "G4VUserActionInitialization.hh"
#include "G4UserWorkerInitialization.hh"
#include <julia.h>
#include <iostream>

Expand All @@ -37,6 +38,7 @@ class DetectorConstruction : public G4VUserDetectorConstruction
new G4PVPlacement(0, G4ThreeVector(), logicCore, "Core", logicWorld, false, 0);
return physWorld;
}
void ConstructSDandField() override {}
};

//---Primary generator action class----------------------------------------------------------------
Expand Down Expand Up @@ -107,13 +109,32 @@ class RunAction : public G4UserRunAction
runaction_f endrun_jl;
};


class WorkerInitialization : public G4UserWorkerInitialization {
public:
WorkerInitialization() = default;
virtual ~WorkerInitialization() = default;
virtual void WorkerInitialize() const override {
if (jl_get_pgcstack() == NULL) jl_adopt_thread();
}
virtual void WorkerStart() const override {}
virtual void WorkerRunStart() const override {}
virtual void WorkerRunEnd() const override {
jl_ptls_t ptls = jl_current_task->ptls;
jl_gc_safe_enter(ptls);
}
virtual void WorkerStop() const override {}
};

//---Action initialization class-------------------------------------------------------------------
class ActionInitialization : public G4VUserActionInitialization
{
public:
ActionInitialization() = default;
~ActionInitialization() override = default;
void BuildForMaster() const override {}
void BuildForMaster() const override {
SetUserAction(new RunAction);
}
void Build() const override {
SetUserAction(new PrimaryGeneratorAction);
SetUserAction(new RunAction);
Expand All @@ -122,11 +143,16 @@ class ActionInitialization : public G4VUserActionInitialization
}
};



JULIA_DEFINE_FAST_TLS // only define this once, in an executable (not in a shared library) if you want fast code.

//----Main program---------------------------------------------------------------------------------
int main(int, char**)
{
int nthreads = 0; // Default number of threads
if (getenv("G4NUMTHREADS")) nthreads = atoi(getenv("G4NUMTHREADS"));

//--- Required to setup the Julia context
jl_init();
/* run Julia commands */
Expand All @@ -136,9 +162,19 @@ int main(int, char**)
}

//---Construct the default run manager
auto runManager = G4RunManagerFactory::CreateRunManager(G4RunManagerType::Serial);
G4RunManager* runManager;
if (nthreads > 0) {
runManager = G4RunManagerFactory::CreateRunManager(G4RunManagerType::MT);
runManager->SetNumberOfThreads(nthreads);
runManager->SetUserInitialization(new WorkerInitialization());
} else {
runManager = G4RunManagerFactory::CreateRunManager(G4RunManagerType::Serial);
}

//---Set mandatory initialization classes



// Detector construction
runManager->SetUserInitialization(new DetectorConstruction());

Expand All @@ -159,7 +195,12 @@ int main(int, char**)
//UImanager->ApplyCommand("/tracking/verbose 1");
UImanager->ApplyCommand("/gun/particle e+");
UImanager->ApplyCommand("/gun/energy 100 MeV");
UImanager->ApplyCommand("/run/beamOn 100000");

// Start a run (we need to enter GC safe region here because the worker threads
// will enter a wait state waiting for workers to finish and can block GC
auto state = jl_gc_safe_enter(jl_current_task->ptls);
runManager->BeamOn(100000);
jl_gc_safe_leave(jl_current_task->ptls, state);

// Job termination
delete runManager;
Expand Down
17 changes: 9 additions & 8 deletions advanced/EmbedJulia/JuliaAction.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
"source": [
"cd(@__DIR__)\n",
"g4prefix = Geant4_jll.artifact_dir\n",
"jlprefix = dirname(Sys.BINDIR)"
"jlprefix = dirname(Sys.BINDIR);"
],
"metadata": {},
"execution_count": null
Expand All @@ -103,7 +103,8 @@
"jllibs = read(`$jlprefix/share/julia/julia-config.jl --ldlibs`, String) |> split\n",
"append!(jllibs, [\"-L$jlprefix/lib\"])\n",
"cflags = read(`$g4prefix/bin/geant4-config --cflags`, String) |> split\n",
"ldflags = [\"-Wl,-rpath,$g4prefix/lib\", \"-Wl,-rpath,$jlprefix/lib\"];"
"ldflags = [\"-Wl,-rpath,$g4prefix/lib\", \"-Wl,-rpath,$jlprefix/lib\"];\n",
"Sys.KERNEL == :Linux && append!(ldflags, [\"-Wl,--no-as-needed\"]);"
],
"metadata": {},
"execution_count": null
Expand Down Expand Up @@ -137,8 +138,8 @@
"outputs": [],
"cell_type": "code",
"source": [
"withenv(\"JULIA_PROJECT\" => \"@.\") do\n",
" Base.run(`./G4example`).exitcode == 0 || error(\"Execution failed\");\n",
"withenv(\"JULIA_PROJECT\" => \"@.\", \"G4NUMTHREADS\" => \"8\") do\n",
" Base.run(`./G4example`).exitcode == 0 || error(\"Execution failed\")\n",
"end"
],
"metadata": {},
Expand All @@ -155,15 +156,15 @@
"outputs": [],
"cell_type": "code",
"source": [
"display(\"image/png\", read(\"edepHist.png\"))"
"println(\"=====> The file edepHist.png should have been saved\")"
],
"metadata": {},
"execution_count": null
},
{
"cell_type": "markdown",
"source": [
"next"
"![](edepHist.png)"
],
"metadata": {}
},
Expand All @@ -183,11 +184,11 @@
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.11.1"
"version": "1.11.2"
},
"kernelspec": {
"name": "julia-1.11",
"display_name": "Julia 1.11.1",
"display_name": "Julia 1.11.2",
"language": "julia"
}
},
Expand Down
11 changes: 5 additions & 6 deletions advanced/EmbedJulia/JuliaAction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,21 @@ using Geant4_jll # Needed to locate the Geant4 installation directory

cd(@__DIR__)
g4prefix = Geant4_jll.artifact_dir
jlprefix = dirname(Sys.BINDIR)
jlprefix = dirname(Sys.BINDIR);

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"]);

Base.run(`c++ -O2 -fPIC $cflags -I$jlprefix/include/julia $ldflags $g4libs $jllibs
-o G4example $(@__DIR__)/G4example.cpp`).exitcode == 0 || error("Compilation failed");

withenv("JULIA_PROJECT" => "@.") do
Base.run(`./G4example`).exitcode == 0 || error("Execution failed");
withenv("JULIA_PROJECT" => "@.", "G4NUMTHREADS" => "8") do
Base.run(`./G4example`).exitcode == 0 || error("Execution failed")
end

display("image/png", read("edepHist.png"))

display("image/png", read("edepHist.png"))
println("=====> The file edepHist.png should have been saved")
19 changes: 11 additions & 8 deletions advanced/EmbedJulia/JuliaAction_lit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@
#md # You can also download this example as a
#md # [Jupyter notebook](JuliaAction.ipynb) and a plain
#md # [Julia source file](JuliaAction.jl).
#
#md #
#md # The C++ code is available as a [source file](G4example.cpp) and the
#md # Julia code is available as a [source file](MyCode.jl).
#md #
#md # #### Table of contents
#md # ```@contents
#md # Pages = ["JuliaAction.md"]
Expand All @@ -63,7 +66,7 @@ using Geant4_jll # Needed to locate the Geant4 installation directory
# Sources are in the same location as this script.
cd(@__DIR__)
g4prefix = Geant4_jll.artifact_dir
jlprefix = dirname(Sys.BINDIR)
jlprefix = dirname(Sys.BINDIR);

# We use the executables `geant4-config` and `julia-config.jl` to get the needed
# libraries and compiler/linker flags.
Expand All @@ -74,19 +77,19 @@ 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 $(@__DIR__)/G4example.cpp`).exitcode == 0 || error("Compilation failed");

# ## Run the application
# We need to set the variable `JULIA_PROJECT` pointing to correctly setup Julia environment.
withenv("JULIA_PROJECT" => "@.") do
Base.run(`./G4example`).exitcode == 0 || error("Execution failed");
withenv("JULIA_PROJECT" => "@.", "G4NUMTHREADS" => "8") do
Base.run(`./G4example`).exitcode == 0 || error("Execution failed")
end

# ## Display the results
display("image/png", read("edepHist.png"))
# next
#jl display("image/png", read("edepHist.png"))
#md PNG(read("edepHist.png"))
println("=====> The file edepHist.png should have been saved")
#md # ![](edepHist.png)
#nb # ![](edepHist.png)
48 changes: 36 additions & 12 deletions advanced/EmbedJulia/MyCode.jl
Original file line number Diff line number Diff line change
@@ -1,39 +1,63 @@
#---Load the needed Julia modules------------------------------------------------------------------

using Geant4
using GeometryBasics
using FHist
using Plots
using Parameters

println("=====> Loading MyCode.jl")

edepHist = H1D("Event total Edep distribution", 100, 0., 110.)
edep = 0.0
#---Simulation data struct-------------------------------------------------------------------------
@with_kw mutable struct MyData
edep = 0.0
edepHist = H1D("Event total Edep distribution", 100, 0., 110.)
end
add!(d::MyData, d2::MyData) = (d.edep += d2.edep; merge!(d.edepHist, d2.edepHist))

const nthreads = ENV["G4NUMTHREADS"] == nothing ? 0 : parse(Int, ENV["G4NUMTHREADS"])
const simdata = [MyData() for i in 1:nthreads+1] # #workers + 1(master)

function getMyData()
tid = G4Threading!G4GetThreadId()
tid < 0 && (tid = -1) # master thread (-2 for without multi-threading support)
simdata[tid+2]
end

#---Actions----------------------------------------------------------------------------------------
function end_of_event_action(event)
push!(edepHist, edep)
data = getMyData()
push!(data.edepHist, data.edep)
return # This is mandatory to force to return nothing
end

function begin_of_event_action(event)
global edep = 0.0
data = getMyData()
data.edep = 0.0
return # This is mandatory to force to return nothing
end

function stepping_action(step)
global edep += GetTotalEnergyDeposit(step)
data = getMyData()
data.edep += GetTotalEnergyDeposit(step)
return # This is mandatory to force to return nothing
end

function begin_of_run_action(run)
return # This is mandatory to force to return nothing
end

function end_of_run_action(run)
println("=====> End of run")
h = edepHist
img = plot(h.hist, title=h.title)
savefig(img, "edepHist.png")
println("=====> edepHist.png saved")
function end_of_run_action(run)
if G4Threading!G4GetThreadId() < 0
println("=====> End of run")
data = simdata[1]
##---This is the master thread, so we need to add all the simulation results-----------------
for d in simdata[2:end]
add!(data, d)
end
h = data.edepHist
img = plot(h.hist, title=h.title)
savefig(img, "edepHist.png")
println("=====> edepHist.png saved")
end
return # This is mandatory to force to return nothing
end

0 comments on commit 51c9f08

Please sign in to comment.