@@ -22,71 +22,93 @@ initialization and update.
2222 [`PeriodicBox`](@ref).
2323- `update_strategy`: Strategy to parallelize `update!` of the internally used
2424 `GridNeighborhoodSearch`. See [`GridNeighborhoodSearch`](@ref)
25- for available options.
25+ for available options. This is only used for the default value
26+ of `update_neighborhood_search` below.
27+ - `update_neighborhood_search = GridNeighborhoodSearch{NDIMS}(; periodic_box, update_strategy)`:
28+ The neighborhood search used to compute the neighbor lists.
29+ By default, a [`GridNeighborhoodSearch`](@ref) is used.
30+ - `backend = DynamicVectorOfVectors{Int32}`: Type of the data structure to store
31+ the neighbor lists. Can be
32+ - `Vector{Vector{Int32}}`: Scattered memory, but very memory-efficient.
33+ - `DynamicVectorOfVectors{Int32}`: Contiguous memory, optimizing cache-hits
34+ and GPU-compatible.
35+ - `max_neighbors`: Maximum number of neighbors per particle. This will be used to
36+ allocate the `DynamicVectorOfVectors`. It is not used with
37+ other backends. The default is 64 in 2D and 324 in 3D.
2638"""
27- struct PrecomputedNeighborhoodSearch{NDIMS, NHS, NL , PB} <: AbstractNeighborhoodSearch
28- neighborhood_search :: NHS
39+ struct PrecomputedNeighborhoodSearch{NDIMS, NL, ELTYPE , PB, NHS } < :
40+ AbstractNeighborhoodSearch
2941 neighbor_lists :: NL
42+ search_radius :: ELTYPE
3043 periodic_box :: PB
44+ neighborhood_search :: NHS
3145
3246 function PrecomputedNeighborhoodSearch {NDIMS} (; search_radius = 0.0 , n_points = 0 ,
3347 periodic_box = nothing ,
34- update_strategy = nothing ) where {NDIMS}
35- nhs = GridNeighborhoodSearch {NDIMS} (; search_radius, n_points,
36- periodic_box, update_strategy)
37-
38- neighbor_lists = Vector {Vector{Int}} ()
39-
40- new{NDIMS, typeof (nhs),
41- typeof (neighbor_lists),
42- typeof (periodic_box)}(nhs, neighbor_lists, periodic_box)
48+ update_strategy = nothing ,
49+ update_neighborhood_search = GridNeighborhoodSearch {NDIMS} (;
50+ search_radius,
51+ n_points,
52+ periodic_box,
53+ update_strategy),
54+ backend = DynamicVectorOfVectors{Int32},
55+ max_neighbors = 4 * NDIMS^ 4 ) where {NDIMS}
56+ neighbor_lists = construct_backend (nothing , backend, n_points, max_neighbors)
57+
58+ new{NDIMS, typeof (neighbor_lists),
59+ typeof (search_radius), typeof (periodic_box),
60+ typeof (update_neighborhood_search)}(neighbor_lists, search_radius,
61+ periodic_box, update_neighborhood_search)
4362 end
4463end
4564
4665@inline Base. ndims (:: PrecomputedNeighborhoodSearch{NDIMS} ) where {NDIMS} = NDIMS
4766
4867@inline requires_update (:: PrecomputedNeighborhoodSearch ) = (true , true )
4968
50- @inline function search_radius (search:: PrecomputedNeighborhoodSearch )
51- return search_radius (search. neighborhood_search)
52- end
53-
5469function initialize! (search:: PrecomputedNeighborhoodSearch ,
5570 x:: AbstractMatrix , y:: AbstractMatrix ;
5671 parallelization_backend = default_backend (x),
5772 eachindex_y = axes (y, 2 ))
5873 (; neighborhood_search, neighbor_lists) = search
5974
75+ if eachindex_y != axes (y, 2 )
76+ error (" this neighborhood search does not support inactive points" )
77+ end
78+
6079 # Initialize grid NHS
61- initialize! (neighborhood_search, x, y; eachindex_y, parallelization_backend)
80+ initialize! (neighborhood_search, x, y; parallelization_backend)
6281
6382 initialize_neighbor_lists! (neighbor_lists, neighborhood_search, x, y,
64- parallelization_backend, eachindex_y)
83+ parallelization_backend)
84+
85+ return search
6586end
6687
67- # WARNING! Experimental feature:
68- # By default, determine the parallelization backend from the type of `x`.
69- # Optionally, pass a `KernelAbstractions.Backend` to run the KernelAbstractions.jl code
70- # on this backend. This can be useful to run GPU kernels on the CPU by passing
71- # `parallelization_backend = KernelAbstractions.CPU()`, even though `x isa Array`.
7288function update! (search:: PrecomputedNeighborhoodSearch ,
7389 x:: AbstractMatrix , y:: AbstractMatrix ;
7490 points_moving = (true , true ), parallelization_backend = default_backend (x),
7591 eachindex_y = axes (y, 2 ))
7692 (; neighborhood_search, neighbor_lists) = search
7793
78- # Update grid NHS
79- update! (neighborhood_search, x, y; eachindex_y, points_moving, parallelization_backend)
94+ if eachindex_y != axes (y, 2 )
95+ error (" this neighborhood search does not support inactive points" )
96+ end
97+
98+ # Update the internal neighborhood search
99+ update! (neighborhood_search, x, y; points_moving, parallelization_backend)
80100
81101 # Skip update if both point sets are static
82102 if any (points_moving)
83103 initialize_neighbor_lists! (neighbor_lists, neighborhood_search, x, y,
84- parallelization_backend, eachindex_y )
104+ parallelization_backend)
85105 end
106+
107+ return search
86108end
87109
88110function initialize_neighbor_lists! (neighbor_lists, neighborhood_search, x, y,
89- parallelization_backend, eachindex_y )
111+ parallelization_backend)
90112 # Initialize neighbor lists
91113 empty! (neighbor_lists)
92114 resize! (neighbor_lists, size (x, 2 ))
@@ -95,8 +117,19 @@ function initialize_neighbor_lists!(neighbor_lists, neighborhood_search, x, y,
95117 end
96118
97119 # Fill neighbor lists
98- foreach_point_neighbor (x, y, neighborhood_search; parallelization_backend,
99- points = eachindex_y) do point, neighbor, _, _
120+ foreach_point_neighbor (x, y, neighborhood_search;
121+ parallelization_backend) do point, neighbor, _, _
122+ push! (neighbor_lists[point], neighbor)
123+ end
124+ end
125+
126+ function initialize_neighbor_lists! (neighbor_lists:: DynamicVectorOfVectors ,
127+ neighborhood_search, x, y, parallelization_backend)
128+ resize! (neighbor_lists, size (x, 2 ))
129+
130+ # Fill neighbor lists
131+ foreach_point_neighbor (x, y, neighborhood_search;
132+ parallelization_backend) do point, neighbor, _, _
100133 push! (neighbor_lists[point], neighbor)
101134 end
102135end
132165
133166function copy_neighborhood_search (nhs:: PrecomputedNeighborhoodSearch ,
134167 search_radius, n_points; eachpoint = 1 : n_points)
135- update_strategy_ = nhs. neighborhood_search. update_strategy
168+ update_neighborhood_search = copy_neighborhood_search (nhs. neighborhood_search,
169+ search_radius, n_points;
170+ eachpoint)
171+ max_neighbors = max_inner_length (nhs. neighbor_lists, 4 * ndims (nhs)^ 4 )
136172 return PrecomputedNeighborhoodSearch {ndims(nhs)} (; search_radius, n_points,
137173 periodic_box = nhs. periodic_box,
138- update_strategy = update_strategy_)
174+ update_neighborhood_search,
175+ backend = typeof (nhs. neighbor_lists),
176+ max_neighbors)
177+ end
178+
179+ # TODO move to `vector_of_vectors.jl`
180+ function max_inner_length (cells:: DynamicVectorOfVectors , fallback)
181+ return size (cells. backend, 1 )
182+ end
183+
184+ # Fallback when backend is a `Vector{Vector{T}}`. Only used for copying the cell list.
185+ function max_inner_length (:: Any , fallback)
186+ return fallback
139187end
0 commit comments