Skip to content

Commit 9177e88

Browse files
LasNikasLasNikas
andauthored
Deactivate out of bounds particle (#1000)
* deactivate out of bounds particle * check if update is necessary * fix * apply formatter * fix tests * fix tests again * add unit tests * implement suggestions * fix tests * add exact cell check * add comments * fix * add comment * change "this" to "the" in comment * adapt comment --------- Co-authored-by: LasNikas <niklas.nehe@web.de>
1 parent 549104d commit 9177e88

5 files changed

Lines changed: 139 additions & 0 deletions

File tree

src/general/neighborhood_search.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,44 @@ function PointNeighbors.foreach_point_neighbor(f, system, neighbor_system,
1111
points, parallelization_backend)
1212
end
1313

14+
deactivate_out_of_bounds_particles!(system, buffer, nhs, v, u, semi) = system
15+
16+
function deactivate_out_of_bounds_particles!(system, buffer::SystemBuffer,
17+
nhs::GridNeighborhoodSearch, v, u, semi)
18+
deactivate_out_of_bounds_particles!(system, buffer, nhs, nhs.cell_list, v, u, semi)
19+
end
20+
21+
function deactivate_out_of_bounds_particles!(system, buffer, nhs, cell_list, v, u, semi)
22+
return system
23+
end
24+
25+
# `GridNeighborhoodSearch` with a `FullGridCellList` requires a bounding box.
26+
# This function deactivates particles that move outside the bounding box to prevent
27+
# simulation crashes.
28+
# Note that deactivating particles is only possible in combination with a 'SystemBuffer'.
29+
function deactivate_out_of_bounds_particles!(system, ::SystemBuffer, nhs,
30+
cell_list::FullGridCellList, v, u, semi)
31+
@trixi_timeit timer() "deactivate out of bounds particle" begin
32+
@threaded semi for particle in each_integrated_particle(system)
33+
particle_position = current_coords(u, system, particle)
34+
cell = PointNeighbors.cell_coords(particle_position, nhs)
35+
36+
# This is the same code as is used in PointNeighbors.jl in `check_cell_bounds`.
37+
# It tests that particles are inside the inner grid (without the padding layer for neighbor query).
38+
if !all(cell[i] in 2:(size(cell_list.linear_indices, i) - 1)
39+
for i in eachindex(cell))
40+
deactivate_particle!(system, particle, v, u)
41+
end
42+
end
43+
44+
if count(system.buffer.active_particle) != system.buffer.active_particle_count[]
45+
update_system_buffer!(system.buffer)
46+
end
47+
end
48+
49+
return system
50+
end
51+
1452
@propagate_inbounds function foreach_neighbor(f, system_coords, neighbor_coords,
1553
neighborhood_search, backend, particle)
1654
PointNeighbors.foreach_neighbor(f, system_coords, neighbor_coords,

src/schemes/boundary/open_boundary/system.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,16 @@ end
312312
return du
313313
end
314314

315+
function update_positions!(system::OpenBoundarySystem, v, u, v_ode, u_ode, semi, t)
316+
nhs = get_neighborhood_search(system.fluid_system, system, semi)
317+
318+
# `GridNeighborhoodSearch` with a `FullGridCellList` requires a bounding box.
319+
# This function deactivates particles that move outside the bounding box to prevent
320+
# simulation crashes.
321+
# Note that deactivating particles is only possible in combination with a 'SystemBuffer'.
322+
deactivate_out_of_bounds_particles!(system, buffer(system), nhs, v, u, semi)
323+
end
324+
315325
function update_boundary_interpolation!(system::OpenBoundarySystem, v, u, v_ode, u_ode,
316326
semi, t)
317327
update_boundary_model!(system, system.boundary_model, v, u, v_ode, u_ode, semi, t)

src/schemes/fluid/fluid.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,16 @@ end
115115

116116
@inline acceleration_source(system::AbstractFluidSystem) = system.acceleration
117117

118+
function update_positions!(system::AbstractFluidSystem, v, u, v_ode, u_ode, semi, t)
119+
nhs = get_neighborhood_search(system, semi)
120+
121+
# `GridNeighborhoodSearch` with a `FullGridCellList` requires a bounding box.
122+
# This function deactivates particles that move outside the bounding box to prevent
123+
# simulation crashes.
124+
# Note that deactivating particles is only possible in combination with a 'SystemBuffer'.
125+
deactivate_out_of_bounds_particles!(system, buffer(system), nhs, v, u, semi)
126+
end
127+
118128
function compute_density!(system, u, u_ode, semi, ::ContinuityDensity)
119129
# No density update with `ContinuityDensity`
120130
return system

test/general/general.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ include("interpolation.jl")
66
include("buffer.jl")
77
include("util.jl")
88
include("custom_quantities.jl")
9+
include("neighborhood_search.jl")
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
@testset verbose=true "Deactivate Out of Bounds Particles" begin
2+
struct MockSystemOutOfBounds <: TrixiParticles.AbstractSystem{2}
3+
buffer::TrixiParticles.SystemBuffer
4+
end
5+
6+
TrixiParticles.nparticles(system::MockSystemOutOfBounds) = length(system.buffer.active_particle)
7+
Base.eltype(system::MockSystemOutOfBounds) = Float64
8+
9+
@testset "Particles Inside Bounds" begin
10+
# Setup: 5 particles, all inside bounds
11+
buffer = TrixiParticles.SystemBuffer(5, 0)
12+
system = MockSystemOutOfBounds(buffer)
13+
14+
u = [-0.5 0.0 0.5 -0.8 0.8
15+
-0.5 -0.5 0.0 0.5 0.5]
16+
17+
cell_list = TrixiParticles.FullGridCellList(; min_corner=(-1.0, -1.0),
18+
max_corner=(1.0, 1.0),
19+
search_radius=0.1)
20+
dummy_nhs = (; cell_size=0.1, periodic_box=nothing, cell_list)
21+
semi = DummySemidiscretization()
22+
23+
# All particles should remain active
24+
initial_count = count(buffer.active_particle)
25+
TrixiParticles.deactivate_out_of_bounds_particles!(system, buffer, dummy_nhs,
26+
cell_list, u, u, semi)
27+
@test count(buffer.active_particle) == initial_count
28+
end
29+
30+
@testset "Particles Outside Bounds" begin
31+
# Setup: 5 particles, some outside bounds
32+
buffer = TrixiParticles.SystemBuffer(5, 0)
33+
system = MockSystemOutOfBounds(buffer)
34+
35+
# Particles 3 and 5 are outside the bounds
36+
u = [-0.5 0.0 2.0 -0.8 -2.0
37+
-0.5 -0.5 0.0 0.5 0.5]
38+
39+
cell_list = TrixiParticles.FullGridCellList(; min_corner=(-1.0, -1.0),
40+
max_corner=(1.0, 1.0),
41+
search_radius=0.1)
42+
dummy_nhs = (; cell_size=0.1, periodic_box=nothing, cell_list)
43+
semi = DummySemidiscretization()
44+
45+
TrixiParticles.deactivate_out_of_bounds_particles!(system, buffer, dummy_nhs,
46+
cell_list, u, u, semi)
47+
48+
# Particles 3 and 5 should be deactivated
49+
@test buffer.active_particle[3] == false
50+
@test buffer.active_particle[5] == false
51+
# Others should still be active
52+
@test buffer.active_particle[1] == true
53+
@test buffer.active_particle[2] == true
54+
@test buffer.active_particle[4] == true
55+
56+
@test TrixiParticles.each_active_particle(system, buffer) == [1, 2, 4]
57+
end
58+
59+
@testset "Edge Cases" begin
60+
# Test the 1001//1000 padding logic
61+
buffer = TrixiParticles.SystemBuffer(3, 0)
62+
system = MockSystemOutOfBounds(buffer)
63+
64+
# Particles directly at the boundaries (should remain active)
65+
u = [-1.0 1.0 0.0
66+
-1.0 1.0 0.0]
67+
68+
cell_list = TrixiParticles.FullGridCellList(; min_corner=(-1.0, -1.0),
69+
max_corner=(1.0, 1.0),
70+
search_radius=0.1)
71+
dummy_nhs = (; cell_size=0.1, periodic_box=nothing, cell_list)
72+
semi = DummySemidiscretization()
73+
74+
TrixiParticles.deactivate_out_of_bounds_particles!(system, buffer, dummy_nhs,
75+
cell_list, u, u, semi)
76+
77+
# All should still be active
78+
@test all(buffer.active_particle)
79+
end
80+
end

0 commit comments

Comments
 (0)