Skip to content

Commit cacc71f

Browse files
committed
Update simulate_waveforms to allow for max_interaction_distance
1 parent df41f40 commit cacc71f

File tree

2 files changed

+38
-13
lines changed

2 files changed

+38
-13
lines changed

ext/SolidStateDetectorsLegendHDF5IOExt.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module SolidStateDetectorsLegendHDF5IOExt
55
import ..LegendHDF5IO
66

77
using SolidStateDetectors
8-
using SolidStateDetectors: RealQuantity, SSDFloat, to_internal_units, chunked_ranges
8+
using SolidStateDetectors: RealQuantity, SSDFloat, to_internal_units, chunked_ranges, LengthQuantity
99
using TypedTables, Unitful
1010
using Format
1111

@@ -34,6 +34,7 @@ function SolidStateDetectors.simulate_waveforms( mcevents::TypedTables.Table, si
3434
self_repulsion::Bool = false,
3535
number_of_carriers::Int = 1,
3636
number_of_shells::Int = 1,
37+
max_interaction_distance::Union{<:Real, <:LengthQuantity} = NaN,
3738
verbose = false) where {T <: SSDFloat}
3839
n_total_physics_events = length(mcevents)
3940
Δtime = T(to_internal_units(Δt))
@@ -48,7 +49,7 @@ function SolidStateDetectors.simulate_waveforms( mcevents::TypedTables.Table, si
4849
for evtrange in evt_ranges
4950
ofn = joinpath(output_dir, "$(output_base_name)_evts_$(nfmt(first(evtrange)))-$(nfmt(last(evtrange))).h5")
5051
@info "Now simulating $(evtrange) and storing it in\n\t \"$ofn\""
51-
mcevents_sub = simulate_waveforms(mcevents[evtrange], sim; Δt, max_nsteps, diffusion, self_repulsion, number_of_carriers, number_of_shells, verbose)
52+
mcevents_sub = simulate_waveforms(mcevents[evtrange], sim; Δt, max_nsteps, diffusion, self_repulsion, number_of_carriers, number_of_shells, max_interaction_distance, verbose)
5253

5354
LegendHDF5IO.lh5open(ofn, "w") do h5f
5455
LegendHDF5IO.writedata(h5f.data_store, "generated_waveforms", mcevents_sub)

src/MCEventsProcessing/MCEventsProcessing.jl

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ If [LegendHDF5IO.jl](https://github.com/legend-exp/LegendHDF5IO.jl) is loaded, t
2727
* `self_repulsion::Bool = false`: Activate or deactive self-repulsion of charge carriers of the same type.
2828
* `number_of_carriers::Int = 1`: Number of charge carriers to be used in the N-Body simulation of an energy deposition.
2929
* `number_of_shells::Int = 1`: Number of shells around the `center` point of the energy deposition.
30+
* `max_interaction_distance = NaN`: Maximum distance for which charge clouds will interact with each other (if `NaN`, then all charge clouds drift independently).
3031
* `verbose = false`: Activate or deactivate additional info output.
3132
* `chunk_n_physics_events::Int = 1000` (`LegendHDF5IO` only): Number of events that should be saved in a single HDF5 output file.
3233
@@ -53,6 +54,7 @@ function simulate_waveforms( mcevents::TypedTables.Table, sim::Simulation{T};
5354
self_repulsion::Bool = false,
5455
number_of_carriers::Int = 1,
5556
number_of_shells::Int = 1,
57+
max_interaction_distance::Union{<:Real, <:LengthQuantity} = NaN,
5658
verbose::Bool = false ) where {T <: SSDFloat}
5759
n_total_physics_events = length(mcevents)
5860
Δtime = T(to_internal_units(Δt))
@@ -71,7 +73,7 @@ function simulate_waveforms( mcevents::TypedTables.Table, sim::Simulation{T};
7173

7274
# First simulate drift paths
7375
drift_paths_and_edeps = _simulate_charge_drifts(mcevents, sim, Δt, max_nsteps, electric_field,
74-
diffusion, self_repulsion, number_of_carriers, number_of_shells, verbose)
76+
diffusion, self_repulsion, number_of_carriers, number_of_shells, max_interaction_distance, verbose)
7577
drift_paths = map(x -> vcat([vcat(ed...) for ed in x[1]]...), drift_paths_and_edeps)
7678
edeps = map(x -> vcat([vcat(ed...) for ed in x[2]]...), drift_paths_and_edeps)
7779
# now iterate over contacts and generate the waveform for each contact
@@ -94,19 +96,40 @@ function simulate_waveforms( mcevents::TypedTables.Table, sim::Simulation{T};
9496
return vcat(mcevents_chns...)
9597
end
9698

97-
_convertEnergyDepsToChargeDeps(pos::AbstractVector{<:SVector{3}}, edep::AbstractVector{<:Quantity}, det::SolidStateDetector; kwargs...) =
98-
_convertEnergyDepsToChargeDeps([[p] for p in pos], [[e] for e in edep], det; kwargs...)
99+
function _convertEnergyDepsToChargeDeps(
100+
pos::AbstractVector{<:SVector{3}}, edep::AbstractVector{<:Quantity}, det::SolidStateDetector{T};
101+
particle_type::Type{PT} = Gamma,
102+
radius::Vector{<:Union{<:Real, <:LengthQuantity}} = radius_guess.(T.(to_internal_units.(edep)), particle_type),
103+
max_interaction_distance::Union{<:Real, <:LengthQuantity} = NaN,
104+
kwargs...
105+
) where {T <: SSDFloat, PT <: ParticleType}
106+
107+
@assert eachindex(pos) == eachindex(edep) == eachindex(radius)
108+
109+
d::T = T(to_internal_units(max_interaction_distance))
110+
@assert isnan(d) || d >= 0 "Max. interaction distance must be positive or NaN (no grouping), but $(max_interaction_distance) was given."
111+
112+
loc, ene, rad = group_points_by_distance(CartesianPoint.(map(x -> to_internal_units.(x), pos)), T.(to_internal_units.(edep)), T.(to_internal_units.(radius)), d)
113+
_convertEnergyDepsToChargeDeps(loc, ene, det; radius = rad, kwargs...)
114+
end
115+
116+
function _convertEnergyDepsToChargeDeps(
117+
pos::AbstractVector{<:AbstractVector}, edep::AbstractVector{<:AbstractVector}, det::SolidStateDetector{T};
118+
particle_type::Type{PT} = Gamma,
119+
radius::AbstractVector{<:AbstractVector{<:Union{<:Real, <:LengthQuantity}}} = map(e -> radius_guess.(to_internal_units.(e), particle_type), edep),
120+
number_of_carriers::Int = 1, number_of_shells::Int = 1,
121+
max_interaction_distance::Union{<:Real, <:LengthQuantity} = NaN # is ignored here
122+
) where {T <: SSDFloat, PT <: ParticleType}
99123

100-
function _convertEnergyDepsToChargeDeps(pos::AbstractVector{<:AbstractVector}, edep::AbstractVector{<:AbstractVector}, det::SolidStateDetector;
101-
number_of_carriers::Int = 1, number_of_shells::Int = 1)
102124
charge_clouds = broadcast(
103125
iEdep_indep -> broadcast(
104126
i_together -> begin
105127
nbcc = NBodyChargeCloud(
106-
CartesianPoint(to_internal_units.((pos[iEdep_indep][i_together]))),
107-
edep[iEdep_indep][i_together],
128+
CartesianPoint(T.(to_internal_units.(pos[iEdep_indep][i_together]))),
129+
T.(to_internal_units(edep[iEdep_indep][i_together])),
108130
number_of_carriers,
109-
number_of_shells = number_of_shells
131+
number_of_shells = number_of_shells,
132+
radius = T(to_internal_units(edep[iEdep_indep][i_together]))
110133
)
111134
move_charges_inside_semiconductor!([nbcc.locations], [nbcc.energies], det)
112135
nbcc
@@ -115,8 +138,8 @@ function _convertEnergyDepsToChargeDeps(pos::AbstractVector{<:AbstractVector}, e
115138
),
116139
eachindex(edep)
117140
)
118-
locations = [map(cc -> cc.locations, ccs) for ccs in charge_clouds]
119-
edeps = [map(cc -> cc.energies, ccs) for ccs in charge_clouds]
141+
locations = map.(cc -> cc.locations, charge_clouds)
142+
edeps = map.(cc -> cc.energies, charge_clouds)
120143
locations, edeps
121144
end
122145

@@ -127,9 +150,10 @@ function _simulate_charge_drifts( mcevents::TypedTables.Table, sim::Simulation{T
127150
self_repulsion::Bool,
128151
number_of_carriers::Int,
129152
number_of_shells::Int,
153+
max_interaction_distance::Union{<:Real, <:LengthQuantity},
130154
verbose::Bool ) where {T <: SSDFloat}
131155
@showprogress map(mcevents) do phyevt
132-
locations, edeps = _convertEnergyDepsToChargeDeps(phyevt.pos, phyevt.edep, sim.detector; number_of_carriers, number_of_shells)
156+
locations, edeps = _convertEnergyDepsToChargeDeps(phyevt.pos, phyevt.edep, sim.detector; number_of_carriers, number_of_shells, max_interaction_distance)
133157
drift_paths = map( i -> _drift_charges(sim.detector, sim.electric_field.grid, sim.point_types,
134158
VectorOfArrays(locations[i]), VectorOfArrays(edeps[i]),
135159
electric_field, T(Δt.val) * unit(Δt), max_nsteps = max_nsteps,

0 commit comments

Comments
 (0)