Skip to content

Commit 9ac6ace

Browse files
efaulhaberLasNikas
andauthored
Restructure tests (#13)
* Restructure tests * Also combine tests in `grid_nhs.jl` * Improve comments * Vary initalize and update functions * Reformat code * Remove ugly inline functions * Extract variables * Update test/nhs_grid.jl Co-authored-by: Niklas Neher <[email protected]> * Update test/nhs_grid.jl Co-authored-by: Niklas Neher <[email protected]> --------- Co-authored-by: Niklas Neher <[email protected]>
1 parent ded6167 commit 9ac6ace

File tree

3 files changed

+144
-139
lines changed

3 files changed

+144
-139
lines changed

test/neighborhood_search.jl

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# This file contains tests for the generic functions in `src/neighborhood_search.jl` and
2+
# tests comparing all NHS implementations against the `TrivialNeighborhoodSearch`.
3+
@testset verbose=true "Neighborhood Searches" begin
4+
@testset verbose=true "Periodicity" begin
5+
# These examples are constructed by hand and are therefore a good test for the
6+
# trivial neighborhood search as well.
7+
# (As opposed to the tests below that are just comparing against the trivial NHS.)
8+
9+
# Names, coordinates and corresponding periodic boxes for each test
10+
names = [
11+
"Simple Example 2D",
12+
"Box Not Multiple of Search Radius 2D",
13+
"Simple Example 3D",
14+
]
15+
16+
coordinates = [
17+
[-0.08 0.0 0.18 0.1 -0.08
18+
-0.12 -0.05 -0.09 0.15 0.39],
19+
[-0.08 0.0 0.18 0.1 -0.08
20+
-0.12 -0.05 -0.09 0.15 0.42],
21+
[-0.08 0.0 0.18 0.1 -0.08
22+
-0.12 -0.05 -0.09 0.15 0.39
23+
0.14 0.34 0.12 0.06 0.13],
24+
]
25+
26+
periodic_boxes = [
27+
([-0.1, -0.2], [0.2, 0.4]),
28+
# The `GridNeighborhoodSearch` is forced to round up the cell sizes in this test
29+
# to avoid split cells.
30+
([-0.1, -0.2], [0.205, 0.43]),
31+
([-0.1, -0.2, 0.05], [0.2, 0.4, 0.35]),
32+
]
33+
34+
@testset verbose=true "$(names[i])" for i in eachindex(names)
35+
coords = coordinates[i]
36+
37+
NDIMS = size(coords, 1)
38+
n_particles = size(coords, 2)
39+
search_radius = 0.1
40+
41+
neighborhood_searches = [
42+
TrivialNeighborhoodSearch{NDIMS}(search_radius, 1:n_particles,
43+
periodic_box_min_corner = periodic_boxes[i][1],
44+
periodic_box_max_corner = periodic_boxes[i][2]),
45+
GridNeighborhoodSearch{NDIMS}(search_radius, n_particles,
46+
periodic_box_min_corner = periodic_boxes[i][1],
47+
periodic_box_max_corner = periodic_boxes[i][2]),
48+
]
49+
neighborhood_searches_names = [
50+
"`TrivialNeighborhoodSearch`",
51+
"`GridNeighborhoodSearch`",
52+
]
53+
54+
# Run this for every neighborhood search
55+
@testset "$(neighborhood_searches_names[j])" for j in eachindex(neighborhood_searches_names)
56+
nhs = neighborhood_searches[j]
57+
58+
initialize!(nhs, coords, coords)
59+
60+
neighbors = [Int[] for _ in axes(coords, 2)]
61+
62+
for_particle_neighbor(coords, coords, nhs,
63+
particles = axes(coords, 2)) do particle, neighbor,
64+
pos_diff, distance
65+
append!(neighbors[particle], neighbor)
66+
end
67+
68+
# All of these tests are designed to yield the same neighbor lists.
69+
# Note that we have to sort the neighbor lists because neighborhood searches
70+
# might produce different orders.
71+
@test sort(neighbors[1]) == [1, 3, 5]
72+
@test sort(neighbors[2]) == [2]
73+
@test sort(neighbors[3]) == [1, 3]
74+
@test sort(neighbors[4]) == [4]
75+
@test sort(neighbors[5]) == [1, 5]
76+
end
77+
end
78+
end
79+
end;

test/nhs_grid.jl

Lines changed: 64 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@testset verbose=true "GridNeighborhoodSearch" begin
2-
@testset "Coordinate Limits" begin
3-
# Test the threshold for very large and very small coordinates.
2+
@testset "Cells at Coordinate Limits" begin
3+
# Test the threshold for very large and very small coordinates
44
coords1 = [Inf, -Inf]
55
coords2 = [NaN, 0]
66
coords3 = [typemax(Int) + 1.0, -typemax(Int) - 1.0]
@@ -15,8 +15,8 @@
1515

1616
@testset "Rectangular Point Cloud 2D" begin
1717
#### Setup
18-
# Rectangular filled with equidistant spaced particles
19-
# from (x, y) = (-0.25, -0.25) to (x, y) = (0.35, 0.35)
18+
# Rectangle of equidistantly spaced particles
19+
# from (x, y) = (-0.25, -0.25) to (x, y) = (0.35, 0.35).
2020
range = -0.25:0.1:0.35
2121
coordinates1 = hcat(collect.(Iterators.product(range, range))...)
2222
nparticles = size(coordinates1, 2)
@@ -28,8 +28,7 @@
2828
# Create neighborhood search
2929
nhs1 = GridNeighborhoodSearch{2}(radius, nparticles)
3030

31-
coords_fun(i) = coordinates1[:, i]
32-
initialize_grid!(nhs1, coords_fun)
31+
initialize_grid!(nhs1, coordinates1)
3332

3433
# Get each neighbor for `particle_position1`
3534
neighbors1 = sort(collect(PointNeighbors.eachneighbor(particle_position1, nhs1)))
@@ -38,57 +37,51 @@
3837
coordinates2 = coordinates1 .+ [1.4, -3.5]
3938

4039
# Update neighborhood search
41-
coords_fun2(i) = coordinates2[:, i]
42-
update_grid!(nhs1, coords_fun2)
40+
update_grid!(nhs1, coordinates2)
4341

4442
# Get each neighbor for updated NHS
45-
neighbors2 = sort(collect(PointNeighbors.eachneighbor(particle_position1,
46-
nhs1)))
43+
neighbors2 = sort(collect(PointNeighbors.eachneighbor(particle_position1, nhs1)))
4744

4845
# Change position
4946
particle_position2 = particle_position1 .+ [1.4, -3.5]
5047

5148
# Get each neighbor for `particle_position2`
52-
neighbors3 = sort(collect(PointNeighbors.eachneighbor(particle_position2,
53-
nhs1)))
49+
neighbors3 = sort(collect(PointNeighbors.eachneighbor(particle_position2, nhs1)))
5450

5551
# Double search radius
5652
nhs2 = GridNeighborhoodSearch{2}(2 * radius, size(coordinates1, 2))
57-
initialize_grid!(nhs2, coords_fun)
53+
initialize!(nhs2, coordinates1, coordinates1)
5854

5955
# Get each neighbor in double search radius
60-
neighbors4 = sort(collect(PointNeighbors.eachneighbor(particle_position1,
61-
nhs2)))
56+
neighbors4 = sort(collect(PointNeighbors.eachneighbor(particle_position1, nhs2)))
6257

6358
# Move particles
6459
coordinates2 = coordinates1 .+ [0.4, -0.4]
6560

6661
# Update neighborhood search
67-
update_grid!(nhs2, coords_fun2)
62+
update!(nhs2, coordinates2, coordinates2)
6863

6964
# Get each neighbor in double search radius
70-
neighbors5 = sort(collect(PointNeighbors.eachneighbor(particle_position1,
71-
nhs2)))
65+
neighbors5 = sort(collect(PointNeighbors.eachneighbor(particle_position1, nhs2)))
7266

73-
#### Verification
67+
#### Verification against lists of potential neighbors built by hand
7468
@test neighbors1 == [17, 18, 19, 24, 25, 26, 31, 32, 33]
7569

7670
@test neighbors2 == Int[]
7771

7872
@test neighbors3 == [17, 18, 19, 24, 25, 26, 31, 32, 33]
7973

8074
@test neighbors4 == [
81-
9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 23, 24, 25,
82-
26, 27, 28, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47,
83-
48, 49]
75+
9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 30, 31,
76+
32, 33, 34, 35, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49]
8477

8578
@test neighbors5 == [36, 37, 38, 43, 44, 45]
8679
end
8780

8881
@testset "Rectangular Point Cloud 3D" begin
8982
#### Setup
90-
# Rectangular filled with equidistant spaced particles
91-
# from (x, y, z) = (-0.25, -0.25, -0.25) to (x, y) = (0.35, 0.35, 0.35)
83+
# Rectangle of equidistantly spaced particles
84+
# from (x, y, z) = (-0.25, -0.25, -0.25) to (x, y, z) = (0.35, 0.35, 0.35).
9285
range = -0.25:0.1:0.35
9386
coordinates1 = hcat(collect.(Iterators.product(range, range, range))...)
9487
nparticles = size(coordinates1, 2)
@@ -104,8 +97,7 @@
10497
initialize_grid!(nhs1, coords_fun)
10598

10699
# Get each neighbor for `particle_position1`
107-
neighbors1 = sort(collect(PointNeighbors.eachneighbor(particle_position1,
108-
nhs1)))
100+
neighbors1 = sort(collect(PointNeighbors.eachneighbor(particle_position1, nhs1)))
109101

110102
# Move particles
111103
coordinates2 = coordinates1 .+ [1.4, -3.5, 0.8]
@@ -115,17 +107,15 @@
115107
update_grid!(nhs1, coords_fun2)
116108

117109
# Get each neighbor for updated NHS
118-
neighbors2 = sort(collect(PointNeighbors.eachneighbor(particle_position1,
119-
nhs1)))
110+
neighbors2 = sort(collect(PointNeighbors.eachneighbor(particle_position1, nhs1)))
120111

121112
# Change position
122113
particle_position2 = particle_position1 .+ [1.4, -3.5, 0.8]
123114

124115
# Get each neighbor for `particle_position2`
125-
neighbors3 = sort(collect(PointNeighbors.eachneighbor(particle_position2,
126-
nhs1)))
116+
neighbors3 = sort(collect(PointNeighbors.eachneighbor(particle_position2, nhs1)))
127117

128-
#### Verification
118+
#### Verification against lists of potential neighbors built by hand
129119
@test neighbors1 ==
130120
[115, 116, 117, 122, 123, 124, 129, 130, 131, 164, 165, 166, 171, 172,
131121
173, 178, 179, 180, 213, 214, 215, 220, 221, 222, 227, 228, 229]
@@ -137,59 +127,46 @@
137127
173, 178, 179, 180, 213, 214, 215, 220, 221, 222, 227, 228, 229]
138128
end
139129

140-
@testset verbose=true "Periodicity 2D" begin
141-
@testset "Simple Example" begin
142-
coords = [-0.08 0.0 0.18 0.1 -0.08
143-
-0.12 -0.05 -0.09 0.15 0.39]
144-
145-
# 3 x 6 cells
146-
nhs = GridNeighborhoodSearch{2}(0.1, size(coords, 2),
147-
periodic_box_min_corner = [-0.1, -0.2],
148-
periodic_box_max_corner = [0.2, 0.4])
149-
150-
initialize_grid!(nhs, coords)
151-
152-
neighbors = [sort(collect(PointNeighbors.eachneighbor(coords[:, i],
153-
nhs)))
154-
for i in 1:5]
155-
156-
# Note that (1, 2) and (2, 3) are not neighbors, but they are in neighboring cells
157-
@test neighbors[1] == [1, 2, 3, 5]
158-
@test neighbors[2] == [1, 2, 3]
159-
@test neighbors[3] == [1, 2, 3]
160-
@test neighbors[4] == [4]
161-
@test neighbors[5] == [1, 5]
162-
163-
neighbors_loop = [Int[] for _ in axes(coords, 2)]
164-
165-
for_particle_neighbor(coords, coords, nhs,
166-
particles = axes(coords, 2)) do particle,
167-
neighbor,
168-
pos_diff,
169-
distance
170-
append!(neighbors_loop[particle], neighbor)
171-
end
172-
173-
@test sort(neighbors_loop[1]) == [1, 3, 5]
174-
@test sort(neighbors_loop[2]) == [2]
175-
@test sort(neighbors_loop[3]) == [1, 3]
176-
@test sort(neighbors_loop[4]) == [4]
177-
@test sort(neighbors_loop[5]) == [1, 5]
178-
end
179-
180-
@testset "Rounding Up Cell Sizes" begin
181-
coords = [-0.08 0.0 0.18 0.1 -0.08
182-
-0.12 -0.05 -0.09 0.15 0.42]
183-
184-
# 3 x 6 cells
185-
nhs = GridNeighborhoodSearch{2}(0.1, size(coords, 2),
186-
periodic_box_min_corner = [-0.1, -0.2],
187-
periodic_box_max_corner = [0.205, 0.43])
130+
@testset verbose=true "Periodicity" begin
131+
# These setups are the same as in `test/neighborhood_search.jl`,
132+
# but instead of testing the actual neighbors with `for_particle_neighbor`,
133+
# we only test the potential neighbors (particles in neighboring cells) here.
134+
135+
# Names, coordinates and corresponding periodic boxes for each test
136+
names = [
137+
"Simple Example 2D",
138+
"Box Not Multiple of Search Radius 2D",
139+
"Simple Example 3D",
140+
]
141+
142+
coordinates = [
143+
[-0.08 0.0 0.18 0.1 -0.08
144+
-0.12 -0.05 -0.09 0.15 0.39],
145+
[-0.08 0.0 0.18 0.1 -0.08
146+
-0.12 -0.05 -0.09 0.15 0.42],
147+
[-0.08 0.0 0.18 0.1 -0.08
148+
-0.12 -0.05 -0.09 0.15 0.39
149+
0.14 0.34 0.12 0.06 0.13],
150+
]
151+
152+
periodic_boxes = [
153+
([-0.1, -0.2], [0.2, 0.4]),
154+
# The `GridNeighborhoodSearch` is forced to round up the cell sizes in this test
155+
# to avoid split cells.
156+
([-0.1, -0.2], [0.205, 0.43]),
157+
([-0.1, -0.2, 0.05], [0.2, 0.4, 0.35]),
158+
]
159+
160+
@testset verbose=true "$(names[i])" for i in eachindex(names)
161+
coords = coordinates[i]
162+
163+
nhs = GridNeighborhoodSearch{size(coords, 1)}(0.1, size(coords, 2),
164+
periodic_box_min_corner = periodic_boxes[i][1],
165+
periodic_box_max_corner = periodic_boxes[i][2])
188166

189167
initialize_grid!(nhs, coords)
190168

191-
neighbors = [sort(collect(PointNeighbors.eachneighbor(coords[:, i],
192-
nhs)))
169+
neighbors = [sort(collect(PointNeighbors.eachneighbor(coords[:, i], nhs)))
193170
for i in 1:5]
194171

195172
# Note that (1, 2) and (2, 3) are not neighbors, but they are in neighboring cells
@@ -198,32 +175,16 @@
198175
@test neighbors[3] == [1, 2, 3]
199176
@test neighbors[4] == [4]
200177
@test neighbors[5] == [1, 5]
201-
202-
neighbors_loop = [Int[] for _ in axes(coords, 2)]
203-
204-
for_particle_neighbor(coords, coords, nhs,
205-
particles = axes(coords, 2)) do particle,
206-
neighbor,
207-
pos_diff,
208-
distance
209-
append!(neighbors_loop[particle], neighbor)
210-
end
211-
212-
@test sort(neighbors_loop[1]) == [1, 3, 5]
213-
@test sort(neighbors_loop[2]) == [2]
214-
@test sort(neighbors_loop[3]) == [1, 3]
215-
@test sort(neighbors_loop[4]) == [4]
216-
@test sort(neighbors_loop[5]) == [1, 5]
217178
end
218179

219180
@testset "Offset Domain Triggering Split Cells" begin
220-
# This used to trigger a "split cell bug", where the left and right boundary
221-
# cells were only partially contained in the domain.
222-
# The left particle was placed inside a ghost cells, which causes it to not
223-
# see the right particle, even though it is within the search distance.
181+
# This test used to trigger a "split cell bug", where the left and right
182+
# boundary cells were only partially contained in the domain.
183+
# The left particle was placed inside a ghost cells, which caused it to not
184+
# see the right particle, even though it was within the search distance.
224185
# The domain size is an integer multiple of the cell size, but the NHS did not
225186
# offset the grid based on the domain position.
226-
# See https://github.com/trixi-framework/PointNeighbors.jl/pull/211
187+
# See https://github.com/trixi-framework/TrixiParticles.jl/pull/211
227188
# for a more detailed explanation.
228189
coords = [-1.4 1.9
229190
0.0 0.0]
@@ -244,40 +205,4 @@
244205
@test neighbors[2] == [1, 2]
245206
end
246207
end
247-
248-
@testset verbose=true "Periodicity 3D" begin
249-
coords = [-0.08 0.0 0.18 0.1 -0.08
250-
-0.12 -0.05 -0.09 0.15 0.39
251-
0.14 0.34 0.12 0.06 0.13]
252-
253-
# 3 x 6 x 3 cells
254-
nhs = GridNeighborhoodSearch{3}(0.1, size(coords, 2),
255-
periodic_box_min_corner = [-0.1, -0.2, 0.05],
256-
periodic_box_max_corner = [0.2, 0.4, 0.35])
257-
258-
initialize_grid!(nhs, coords)
259-
260-
neighbors = [sort(collect(PointNeighbors.eachneighbor(coords[:, i], nhs)))
261-
for i in 1:5]
262-
263-
# Note that (1, 2) and (2, 3) are not neighbors, but they are in neighboring cells
264-
@test neighbors[1] == [1, 2, 3, 5]
265-
@test neighbors[2] == [1, 2, 3]
266-
@test neighbors[3] == [1, 2, 3]
267-
@test neighbors[4] == [4]
268-
@test neighbors[5] == [1, 5]
269-
270-
neighbors_loop = [Int[] for _ in axes(coords, 2)]
271-
272-
for_particle_neighbor(coords, coords,
273-
nhs) do particle, neighbor, pos_diff, distance
274-
append!(neighbors_loop[particle], neighbor)
275-
end
276-
277-
@test sort(neighbors_loop[1]) == [1, 3, 5]
278-
@test sort(neighbors_loop[2]) == [2]
279-
@test sort(neighbors_loop[3]) == [1, 3]
280-
@test sort(neighbors_loop[4]) == [4]
281-
@test sort(neighbors_loop[5]) == [1, 5]
282-
end
283-
end
208+
end;

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ include("test_util.jl")
33
@testset verbose=true "PointNeighbors.jl Tests" begin
44
include("nhs_trivial.jl")
55
include("nhs_grid.jl")
6+
include("neighborhood_search.jl")
67
end

0 commit comments

Comments
 (0)