Building Applications#
What is still missing to build complete applications is to add user actions or sensitive detectors or scorers. In this tutorial we have a look at the user actions.
User Actions#
User actions are native Julia functions that will be called by the Geant4 toolkit at the defined moment during the simulation. They
The following are the possible user actions:
stepping action. Called on each simulation step. The signature is
(::G4Step, ::G4JLApplication)::Nothing
. Consult the G4Step reference manual to see what you can get from it.pre-tracking action. Called at the creation of a new participle being tracked. The signature is
(::G4Track, ::G4JLApplication)::Nothing
. Consult the G4Step reference manual to see what you can get from it.post-tracking action. Called at the end of the particle being tracked. The signature is
(::G4Track, ::G4JLApplication)::Nothing
. Consult the G4Track reference manual to see what you can get from it.begin-event action. Called at the beginning of each event. The signature is
(::G4Event, ::G4JLApplication)::Nothing
. Consult the G4Event reference manual to see what you can get from it.end-event action. Called at the end of each event. The signature is
(::G4Event, ::G4JLApplication)::Nothing
. Consult the G4Event reference manual to see what you can get from it.begin-run action. Called at the beginning of a run. The signature is
(::G4Run, ::G4JLApplication)::Nothing
. Consult the G4Run reference manual to see what you can get from it.end-run action. Called at the end of a run. The signature is
(::G4Run, ::G4JLApplication)::Nothing
. Consult the G4Run reference manual to see what you can get from it.stack action. Called when a particle is going to be put back on the particle stack. The signature is
(::G4Track, ::G4JLApplication)::G4ClassificationOfNewTrack
. Consult the G4Track reference manual to see what you can get from it.
All user actions receive in addition to the standard G4 arguments a reference to the G4JLApplication object from which the user can get additional information on the application. These are the available field:
detector - user defined detector parameters object
simdata - vector of the user defined simulation data objects (one per worker thread plus the accumulated one). The function
getSIMdata(app)
return the simulation data corresponding to thethreadid
of the worker calling the user action.generator - primary particle generator
field - magnetic field
nthreads - number of worker threads
verbose - verbosity level
Ploase note that: user actions need to be coded as thread-safe (global data should not be modified without any protection). However, this notebook not use multi-threading in order to be able to re-configure the G4JLApplication
with different actions.
using Geant4
Let’s begin with something very simple. To define a begin event action that prints a message (notice that we use G4JL_println
instead of the native println
to ensure thread safety.)
function beginevent(evt::G4Event, app::G4JLApplication)
G4JL_println("started event $(evt |> GetEventID)")
end
beginevent (generic function with 1 method)
app = G4JLApplication(begineventaction_method=beginevent)
configure(app)
initialize(app)
**************************************************************
Geant4 version Name: geant4-11-02-patch-01 [MT] (16-February-2024)
Copyright : Geant4 Collaboration
References : NIM A 506 (2003), 250-303
: IEEE-TNS 53 (2006), 270-278
: NIM A 835 (2016), 186-225
WWW : http://geant4.org/
**************************************************************
beamOn(app,5)
started event 0
started event 1
started event 2
started event 3
started event 4
Please notice that the output message would be prefixed by the working thread ID and the order of execution of the events is not sequential in case we enable multi-threading.
function endevent(evt::G4Event, app::G4JLApplication)
G4JL_println("end event $(evt |> GetEventID)")
end
endevent (generic function with 1 method)
app = G4JLApplication(begineventaction_method = beginevent,
endeventaction_method = endevent)
configure(app)
initialize(app)
beamOn(app,5)
started event 0
end event 0
started event 1
end event 1
started event 2
end event 2
started event 3
end event 3
started event 4
end event 4
function stepaction(step::G4Step, app::G4JLApplication)
G4JL_println("step with length $(step |> GetStepLength)")
end
stepaction (generic function with 1 method)
app = G4JLApplication(begineventaction_method = beginevent,
endeventaction_method = endevent,
stepaction_method = stepaction)
configure(app)
initialize(app)
beamOn(app,5)
started event 0
step with length 1000.0
end event 0
started event 1
step with length 1000.0
end event 1
started event 2
step with length 1000.0
end event 2
started event 3
step with length 1000.0
end event 3
started event 4
step with length 1000.0
end event 4
Defining Simulation Data#
The user can define a custom data structure to collect simulation data during the execution of the user actions. Here is an example:
using DataFrames
mutable struct MySimData <: G4JLSimulationData
steps::DataFrame
MySimData() = new(DataFrame( X = Float64[], Y = Float64[], Z = Float64[],
KinE = Float64[], dE = Float64[], StepLeng = Float64[]))
end
function stepaction(step::G4Step, app::G4JLApplication)
steps = getSIMdata(app).steps # Get it own copy of the simdata (avoid data racing in MT mode)
point = step |> GetPreStepPoint |> GetPosition
push!(steps, (point |> x, point |> y, point |> z,
step |> GetTrack |> GetKineticEnergy, step |> GetTotalEnergyDeposit, step |> GetStepLength ))
return
end
app = G4JLApplication(simdata = MySimData(),
begineventaction_method = beginevent,
endeventaction_method = endevent,
stepaction_method = stepaction)
configure(app)
initialize(app)
beamOn(app,5)
started event 0
end event 0
started event 1
end event 1
started event 2
end event 2
started event 3
end event 3
started event 4
end event 4
To get the results we can access app.simdata[1]
app.simdata[1]
MySimData(5×6 DataFrame
Row │ X Y Z KinE dE StepLeng
│ Float64 Float64 Float64 Float64 Float64 Float64
─────┼───────────────────────────────────────────────────────────
1 │ 0.0 0.0 0.0 10.0 3.03438e-23 1000.0
2 │ 0.0 0.0 0.0 10.0 3.03438e-23 1000.0
3 │ 0.0 0.0 0.0 10.0 3.03438e-23 1000.0
4 │ 0.0 0.0 0.0 10.0 3.03438e-23 1000.0
5 │ 0.0 0.0 0.0 10.0 3.03438e-23 1000.0)