Scoring Meshes

Scoring Meshes#

The user can specify scoring meshes to obtain quantities on the defined grid. In Geant4 this is achieved using a set of UI commands. In this Julia interface this functionality has been encapsulated in a number of data structures. The function to create a scoring mesh is G4JLScoringMesh and receive as arguments the the type and dimensions of the mesh, the position, the rotation, the number of bins in each dimension, and the quantities to accumulate with eventually some filter conditions.

using Geant4
using Geant4.SystemOfUnits
using CairoMakie

Let’s define a simple detector (from the previous notebook on sensitive detectors)

struct SimpleDetector <: G4JLDetector ; end

#---Materials----------------------------------------------------------------------------------
nist = G4NistManager!Instance()
m_air = FindOrBuildMaterial(nist, "G4_AIR")
m_bgo = FindOrBuildMaterial(nist, "G4_BGO")

#---Volumes------------------------------------------------------------------------------------
worldS = G4Box("world", 1m, 1m, 1m)
worldLV = G4LogicalVolume(worldS, m_air, "World")
worldPV = G4PVPlacement(nothing, G4ThreeVector(), worldLV, "World", nothing, false, 0, false)

crystalS = G4Box("world", 5cm, 5cm, 10cm)
crystalLV = G4LogicalVolume(crystalS, m_bgo, "Crystal")
crystalPV = G4PVPlacement(nothing, G4ThreeVector(), crystalLV, "Crystal", worldLV, false, 0, false)

#---define getConstructor
Geant4.getConstructor(::SimpleDetector)::Function = (::SimpleDetector) -> worldPV

We create a scoring mesh of the same size as the crystal and with bins 20, 20 and 40 in z direction to collect energy deposit, number of steps produced by gammas, electrons and positrons.

sc1 = G4JLScoringMesh("boxMesh_1",
                      BoxMesh(5cm,5cm,20cm),
                      bins = (20, 20, 40),
                      quantities = [ energyDeposit("eDep")
                                     nOfStep("nOfStepGamma", filters=[ParticleFilter("gammafilter", "gamma")])
                                     nOfStep("nOfStepEMinus", filters=[ParticleFilter("eMinusFilter", "e-")])
                                     nOfStep("nOfStepEPlus", filters=[ParticleFilter("ePlusFilter", "e+")])
                                   ]
                      );

Let’s initialize now the application

particlegun = G4JLGunGenerator(particle = "e-", 
                               energy = 3GeV, 
                               direction = G4ThreeVector(0,0,1), 
                               position = G4ThreeVector(0,0,-1m))

app = G4JLApplication(;detector = SimpleDetector(),                  # detector with parameters
                       generator = particlegun,                      # primary particle generator
                       nthreads = 4,                                 # number of threads (MT)
                       physics_type = FTFP_BERT,                     # what physics list to instantiate
                       scorers = [sc1]                               # list of scorers 
                      );
**************************************************************
 Geant4 version Name: geant4-11-02-patch-01 [MT]   (16-February-2024)
  << in Multi-threaded mode >> 
                       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/
**************************************************************
configure(app)
initialize(app)
--- G4CoupledTransportation is used 
.... G4ScoringMessenger::MeshBinCommand - G4ScoringBox
G4ScoringManager has 1 scoring meshes.
G4ScoringBox : boxMesh_1 --- Shape: Box mesh
 Size (x, y, z): (5, 5, 20) [cm]
 # of segments: (20, 20, 40)
 displacement: (0, 0, 0) [cm]
 registered primitve scorers : 
   0  eDep
   1  nOfStepGamma     with  gammafilter
   2  nOfStepEMinus     with  eMinusFilter
   3  nOfStepEPlus     with  ePlusFilter

run for 1000 events

beamOn(app,1000)
G4WT3 > .... G4ScoringMessenger::MeshBinCommand - G4ScoringBox
G4WT0 > .... G4ScoringMessenger::MeshBinCommand - G4ScoringBox
G4WT1 > .... G4ScoringMessenger::MeshBinCommand - G4ScoringBox
G4WT2 > .... G4ScoringMessenger::MeshBinCommand - G4ScoringBox
G4WT0 > G4ScoringManager has 1 scoring meshes.
G4WT0 > G4ScoringBox : boxMesh_1 --- Shape: Box mesh
G4WT0 >  Size (x, y, z): (5, 5, 20) [cm]
G4WT0 >  # of segments: (20, 20, 40)
G4WT0 >  displacement: (0, 0, 0) [cm]
G4WT0 >  registered primitve scorers : 
G4WT0 >    0  eDep
G4WT1 > G4ScoringManager has 1 scoring meshes.
G4WT1 > G4ScoringBox : boxMesh_1 --- Shape: Box mesh
G4WT0 >    1  nOfStepGamma     with  gammafilter
G4WT2 > G4ScoringManager has 1 scoring meshes.
G4WT0 >    2  nOfStepEMinus     with  eMinusFilter
G4WT2 > G4ScoringBox : boxMesh_1 --- Shape: Box mesh
G4WT3 > G4ScoringManager has 1 scoring meshes.
G4WT1 >  Size (x, y, z): (5, 5, 20) [cm]
G4WT3 > G4ScoringBox : boxMesh_1 --- Shape: Box mesh
G4WT0 >    3  nOfStepEPlus     with  ePlusFilter
G4WT2 >  Size (x, y, z): (5, 5, 20) [cm]
G4WT2 >  # of segments: (20, 20, 40)
G4WT1 >  # of segments: (20, 20, 40)
G4WT2 >  displacement: (0, 0, 0) [cm]
G4WT3 >  Size (x, y, z): (5, 5, 20) [cm]
G4WT1 >  displacement: (0, 0, 0) [cm]
G4WT1 >  registered primitve scorers : 
G4WT3 >  # of segments: (20, 20, 40)
G4WT1 >    0  eDep
G4WT3 >  displacement: (0, 0, 0) [cm]
G4WT2 >  registered primitve scorers : 
G4WT2 >    0  eDep
G4WT2 >    1  nOfStepGamma     with  gammafilter
G4WT2 >    2  nOfStepEMinus     with  eMinusFilter
G4WT1 >    1  nOfStepGamma     with  gammafilter
G4WT3 >  registered primitve scorers : 
G4WT1 >    2  nOfStepEMinus     with  eMinusFilter
G4WT2 >    3  nOfStepEPlus     with  ePlusFilter
G4WT1 >    3  nOfStepEPlus     with  ePlusFilter
G4WT3 >    0  eDep
G4WT3 >    1  nOfStepGamma     with  gammafilter
G4WT3 >    2  nOfStepEMinus     with  eMinusFilter
G4WT3 >    3  nOfStepEPlus     with  ePlusFilter

Now the scoring mesh variable sc1 holds the collected information

sum, sum2, entries = sc1.eDep;

Each of these variables (sum, sum2 and entries) is a 20×20×40 Array corresponding to the deposit energy. Let’s see a X-Y plane of it in the middle of the Z axis:

sum[:,:,20]
20×20 Matrix{Float64}:
 22.6907    8.23238   9.53181   14.7324  …  12.409     7.39246  17.7415
 11.2568   10.365    21.2517    24.7346     17.5209   15.3881    1.71277
 12.9987   15.2373   14.4912    48.1607     22.5194   19.1845   11.8564
  9.42243  19.6698   23.8529    37.7654     19.5384   21.3335   13.5281
 22.8952   24.6838   37.5823    52.9955     30.5014   33.8069   13.4116
 25.7023   25.9152   33.594     74.3156  …  26.7333   24.8169   28.8356
 32.9647   38.8203   49.2023    69.869      34.747    17.5358   23.1117
 26.5994   42.2314   62.3937    68.9426     74.4483   26.0788   33.6273
 11.4288   38.1839   59.5371   116.112      54.4134   35.2306   21.319
 16.6416   46.9006   65.8704   109.926      40.7341   46.4459   27.2181
 19.2279   44.3896   75.6179   104.706   …  73.4129   59.2247   32.4233
 20.4118   47.9795   59.2302   126.023      58.434    62.0383   41.5008
 24.6917   46.6389   60.4266    95.9413     80.301    29.0629   28.9642
 17.0803   32.8747   49.331     87.1838     37.8035   38.9716   39.1364
 12.9969   36.0215   43.2987    53.7823     57.9662   18.7645   20.4736
 13.24     24.9719   27.4121    42.8602  …  29.3471   21.7373   11.0561
  9.799    21.3981   30.4914    31.8881     35.2386   31.7529   11.3309
  6.4313   15.8679   37.8778    28.2031     33.2141    9.74859  10.3116
  5.79865  13.9472   13.9546    27.2462     14.7916    8.13246  11.2221
  6.29478  14.4728    7.10103   16.5264      7.39579  14.2824    9.63563

A better way to to plot a heatmap with Makie.

img = heatmap(sum[:,:,20], color=:thermal, title="Edep (XY)")
display("image/png", img)
Invalid attributes color and title for plot type Heatmap{Tuple{MakieCore.EndPoints{Float32}, MakieCore.EndPoints{Float32}, Matrix{Float32}}}.

The available plot attributes for Heatmap{Tuple{MakieCore.EndPoints{Float32}, MakieCore.EndPoints{Float32}, Matrix{Float32}}} are:

alpha        depth_shift      inspector_hover  nan_color       transparency
clip_planes  fxaa             inspector_label  overdraw        visible     
colormap     highclip         interpolate      space                       
colorrange   inspectable      lowclip          ssao                        
colorscale   inspector_clear  model            transformation              


Generic attributes are:

clip_planes  dim_conversions  model      transformation  yautolimits        
cycle        label            rasterize  xautolimits     zautolimits        



Stacktrace:
 [1] validate_attribute_keys(plot::Heatmap{Tuple{MakieCore.EndPoints{Float32}, MakieCore.EndPoints{Float32}, Matrix{Float32}}})
   @ MakieCore ~/.julia/packages/MakieCore/zO6H4/src/recipes.jl:758
 [2] push!(scene::Scene, plot::Plot)
   @ Makie ~/.julia/packages/Makie/pFPBw/src/scenes.jl:489
 [3] plot!
   @ ~/.julia/packages/Makie/pFPBw/src/interfaces.jl:413 [inlined]
 [4] plot!(ax::Axis, plot::Heatmap{Tuple{MakieCore.EndPoints{Float32}, MakieCore.EndPoints{Float32}, Matrix{Float32}}})
   @ Makie ~/.julia/packages/Makie/pFPBw/src/figureplotting.jl:412
 [5] plot!(fa::Makie.FigureAxis, plot::Heatmap{Tuple{MakieCore.EndPoints{Float32}, MakieCore.EndPoints{Float32}, Matrix{Float32}}})
   @ Makie ~/.julia/packages/Makie/pFPBw/src/figureplotting.jl:407
 [6] _create_plot(F::Function, attributes::Dict{Symbol, Any}, args::Matrix{Float64})
   @ Makie ~/.julia/packages/Makie/pFPBw/src/figureplotting.jl:318
 [7] #heatmap#37
   @ ~/.julia/packages/MakieCore/zO6H4/src/recipes.jl:501 [inlined]
 [8] top-level scope
   @ In[9]:1
img = heatmap(sum[:,10,:]', color=:thermal, title="Edep (XZ)")
display("image/png", img)