Skip to content

Commit 6591930

Browse files
authored
Merge pull request JuliaPhysics#526 from JuliaPhysics/IsotopeSource
Fix bug in source emission in `Geant4` extension
2 parents 6f7a3ad + 067e6ca commit 6591930

File tree

1 file changed

+59
-37
lines changed

1 file changed

+59
-37
lines changed

ext/Geant4/g4jl_application.jl

Lines changed: 59 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,17 @@ struct SSDPhysics <: G4VUserPhysicsList
1313
end
1414

1515
struct SDData{T} <: G4JLSDData
16-
detectorHits::DetectorHits
17-
SDData{T}() where {T} = new(DetectorHits((evtno = Int32[], detno = Int32[], thit = typeof(zero(T)*u"s")[], edep = typeof(zero(T)*u"keV")[], pos = SVector{3,typeof(zero(T)*u"mm")}[])))
16+
detectorHits::DetectorHits
17+
SDData{T}() where {T} = new(DetectorHits((evtno = Int32[], detno = Int32[], thit = typeof(zero(T)*u"s")[], edep = typeof(zero(T)*u"keV")[], pos = SVector{3,typeof(zero(T)*u"mm")}[])))
1818
end
1919

2020
function _initialize(::G4HCofThisEvent, data::SDData)::Nothing
21-
empty!(data.detectorHits)
22-
return
21+
empty!(data.detectorHits)
22+
return
2323
end
2424

2525
function _endOfEvent(::G4HCofThisEvent, data::SDData)::Nothing
26-
return
26+
return
2727
end
2828

2929
function _processHits(step::G4Step, ::G4TouchableHistory, data::SDData{T})::Bool where {T}
@@ -48,12 +48,19 @@ function _processHits(step::G4Step, ::G4TouchableHistory, data::SDData{T})::Bool
4848
end
4949

5050
function endeventaction(evt::G4Event, app::G4JLApplication)
51+
# direction = evt |> (evt -> GetPrimaryVertex(evt, 0)) |> (vertex -> GetPrimary(vertex, 0)) |> GetMomentumDirection
52+
# pos = evt |> (evt -> GetPrimaryVertex(evt, 0)) |> GetPosition
53+
# d = [x(direction), y(direction), z(direction)]
54+
# @info [x(pos), y(pos), z(pos)], normalize(d)
5155
return
5256
end
5357

5458

59+
# We are using G4SingleParticleSource instead of G4ParticleGun for uniformity
60+
# across MonoenergeticSource and IsotopeSource, see discussion
61+
# https://github.com/JuliaPhysics/SolidStateDetectors.jl/pull/526
5562
@with_kw mutable struct GeneratorData <: G4JLGeneratorData
56-
gun::Union{Nothing, CxxPtr{G4ParticleGun}, CxxPtr{G4SingleParticleSource}} = nothing
63+
gun::Union{Nothing, CxxPtr{G4SingleParticleSource}} = nothing
5764
particle::Union{Nothing, CxxPtr{G4ParticleDefinition}} = nothing
5865
position::G4ThreeVector = G4ThreeVector(0, 0, 0)
5966
direction::G4ThreeVector = G4ThreeVector(0, 0, 0)
@@ -66,31 +73,39 @@ function SSDGenerator(source::SolidStateDetectors.MonoenergeticSource; kwargs..
6673
data = GeneratorData(;kwargs...)
6774

6875
function _init(data::GeneratorData, ::Any)
69-
gun = data.gun = move!(G4ParticleGun())
76+
data.gun = move!(G4SingleParticleSource())
7077
particle = data.particle = FindParticle(source.particle_type)
78+
SetParticleDefinition(data.gun, particle)
79+
80+
# Place the SingleParticleSource as point source
7181
data.position = G4ThreeVector(
7282
source.position.x * Geant4.SystemOfUnits.meter,
7383
source.position.y * Geant4.SystemOfUnits.meter,
7484
source.position.z * Geant4.SystemOfUnits.meter
7585
)
76-
SetParticlePosition(gun, data.position)
77-
data.direction = G4ThreeVector(source.direction.x, source.direction.y, source.direction.z)
78-
SetParticleMomentumDirection(gun, data.direction)
79-
SetParticleEnergy(gun, ustrip(u"MeV", source.energy))
80-
SetParticleDefinition(gun, particle)
86+
posdist = GetPosDist(data.gun)
87+
SetPosDisType(posdist, "Point")
88+
SetCentreCoords(posdist, data.position)
89+
90+
# Define the source emission
91+
d::CartesianVector = normalize(source.direction)
92+
a::CartesianVector = normalize(d × (abs(d.x) == 1 ? CartesianVector(0,1,0) : CartesianVector(1,0,0)))
93+
b::CartesianVector = normalize(a × d)
94+
data.direction = G4ThreeVector(d.x, d.y, d.z)
95+
96+
angdist = GetAngDist(data.gun)
97+
SetAngDistType(angdist, "iso")
98+
DefineAngRefAxes(angdist, "angref1", G4ThreeVector(a...))
99+
DefineAngRefAxes(angdist, "angref2", G4ThreeVector(b...))
100+
SetMinTheta(angdist, 0.0)
101+
SetMaxTheta(angdist, ustrip(NoUnits, source.opening_angle)) # convert to radians
102+
# SetParticleMomentumDirection(angdist, data.direction)
103+
104+
# set energy
105+
SetMonoEnergy(GetEneDist(data.gun), ustrip(u"MeV", source.energy))
81106
end
82107

83108
function _gen(evt::G4Event, data::GeneratorData)::Nothing
84-
if !iszero(source.opening_angle)
85-
d::CartesianVector = normalize(source.direction)
86-
a::CartesianVector = normalize(d × (abs(d.x) == 1 ? CartesianVector(0,1,0) : CartesianVector(1,0,0)))
87-
b::CartesianVector = normalize(a × d)
88-
ϕ = rand()*2π
89-
θ = acos(1 - (1 - cos(source.opening_angle))*rand())
90-
v = (cos(θ) * d + sin(θ) * (cos(ϕ) * a + sin(ϕ) * b))
91-
direction = G4ThreeVector(v.x, v.y, v.z)
92-
SetParticleMomentumDirection(data.gun, direction)
93-
end
94109
GeneratePrimaryVertex(data.gun, CxxPtr(evt))
95110
end
96111

@@ -103,16 +118,33 @@ function SSDGenerator(source::SolidStateDetectors.IsotopeSource; kwargs...)
103118

104119
data = GeneratorData(;kwargs...)
105120
function _init(data::GeneratorData, ::Any)
106-
gun = data.gun = move!(G4SingleParticleSource())
121+
data.gun = move!(G4SingleParticleSource())
122+
123+
# Place the SingleParticleSource as point source
107124
data.position = G4ThreeVector(
108125
source.position.x * Geant4.SystemOfUnits.meter,
109126
source.position.y * Geant4.SystemOfUnits.meter,
110127
source.position.z * Geant4.SystemOfUnits.meter
111128
)
112-
SetParticlePosition(gun, data.position)
113-
data.direction = G4ThreeVector(source.direction.x, source.direction.y, source.direction.z)
114-
SetParticleMomentumDirection(GetAngDist(gun), data.direction)
115-
SetMonoEnergy(gun |> GetEneDist, 0.0 * Geant4.SystemOfUnits.MeV)
129+
posdist = GetPosDist(data.gun)
130+
SetPosDisType(posdist, "Point")
131+
SetCentreCoords(posdist, data.position)
132+
133+
# Define the source emission
134+
d::CartesianVector = normalize(source.direction)
135+
a::CartesianVector = normalize(d × (abs(d.x) == 1 ? CartesianVector(0,1,0) : CartesianVector(1,0,0)))
136+
b::CartesianVector = normalize(a × d)
137+
data.direction = G4ThreeVector(d.x, d.y, d.z)
138+
139+
angdist = GetAngDist(data.gun)
140+
SetAngDistType(angdist, "iso")
141+
DefineAngRefAxes(angdist, "angref1", G4ThreeVector(a...))
142+
DefineAngRefAxes(angdist, "angref2", G4ThreeVector(b...))
143+
SetMinTheta(angdist, 0.0)
144+
SetMaxTheta(angdist, ustrip(NoUnits, source.opening_angle)) # convert to radians
145+
146+
# Set kinetic energy of the decaying isotope to zero ("decay at rest")
147+
SetMonoEnergy(GetEneDist(data.gun), 0.0 * Geant4.SystemOfUnits.MeV)
116148
end
117149

118150
function _gen(evt::G4Event, data::GeneratorData)::Nothing
@@ -121,16 +153,6 @@ function SSDGenerator(source::SolidStateDetectors.IsotopeSource; kwargs...)
121153
SetParticleDefinition(data.gun, data.particle)
122154
SetParticleCharge(data.gun, source.ionCharge)
123155
end
124-
if !iszero(source.opening_angle)
125-
d::CartesianVector = normalize(source.direction)
126-
a::CartesianVector = normalize(d × (abs(d.x) == 1 ? CartesianVector(0,1,0) : CartesianVector(1,0,0)))
127-
b::CartesianVector = normalize(a × d)
128-
ϕ = rand()*2π
129-
θ = acos(1 - (1 - cos(source.opening_angle))*rand())
130-
v = (cos(θ) * d + sin(θ) * (cos(ϕ) * a + sin(ϕ) * b))
131-
direction = G4ThreeVector(v.x, v.y, v.z)
132-
SetParticleMomentumDirection(GetAngDist(data.gun), direction)
133-
end
134156
GeneratePrimaryVertex(data.gun, CxxPtr(evt))
135157
end
136158

0 commit comments

Comments
 (0)