@@ -15,7 +15,7 @@ See also [`update!`](@ref).
1515@inline initialize! (search:: AbstractNeighborhoodSearch , x, y) = search
1616
1717"""
18- update!(search::AbstractNeighborhoodSearch, x, y; particles_moving = (true, true))
18+ update!(search::AbstractNeighborhoodSearch, x, y; points_moving = (true, true))
1919
2020Update an already initialized neighborhood search with the two coordinate arrays `x` and `y`.
2121
@@ -29,70 +29,112 @@ If incremental updates are not possible for an implementation, `update!` will fa
2929to a regular `initialize!`.
3030
3131Some neighborhood searches might not need to update when only `x` changed since the last
32- `update!` or `initialize!` and `y` did not change. Pass `particles_moving = (true, false)`
32+ `update!` or `initialize!` and `y` did not change. Pass `points_moving = (true, false)`
3333in this case to avoid unnecessary updates.
34- The first flag in `particles_moving ` indicates if points in `x` are moving.
34+ The first flag in `points_moving ` indicates if points in `x` are moving.
3535The second flag indicates if points in `y` are moving.
3636
3737See also [`initialize!`](@ref).
3838"""
3939@inline function update! (search:: AbstractNeighborhoodSearch , x, y;
40- particles_moving = (true , true ))
40+ points_moving = (true , true ))
4141 return search
4242end
4343
44+ """
45+ copy_neighborhood_search(search::AbstractNeighborhoodSearch, search_radius, n_points;
46+ eachpoint = 1:n_points)
47+
48+ Create a new **uninitialized** neighborhood search of the same type and with the same
49+ configuration options as `search`, but with a different search radius and number of points.
50+
51+ The [`TrivialNeighborhoodSearch`](@ref) also requires an iterator `eachpoint`, which most
52+ of the time will be `1:n_points`. If the `TrivialNeighborhoodSearch` is never going to be
53+ used, the keyword argument `eachpoint` can be ignored.
54+
55+ This is useful when a simulation code requires multiple neighborhood searches of the same
56+ kind. One can then just pass an empty neighborhood search as a template and use
57+ this function inside the simulation code to generate similar neighborhood searches with
58+ different search radii and different numbers of points.
59+ ```jldoctest; filter = r"GridNeighborhoodSearch{2,.*"
60+ # Template
61+ nhs = GridNeighborhoodSearch{2}()
62+
63+ # Inside the simulation code, generate similar neighborhood searches
64+ nhs1 = copy_neighborhood_search(nhs, 1.0, 100)
65+
66+ # output
67+ GridNeighborhoodSearch{2, Float64, ...}(...)
68+ ```
69+ """
70+ @inline function copy_neighborhood_search (search:: AbstractNeighborhoodSearch ,
71+ search_radius, n_points; eachpoint = 1 : n_points)
72+ return nothing
73+ end
74+
75+ """
76+ PeriodicBox(; min_corner, max_corner)
77+
78+ Define a rectangular periodic domain.
79+
80+ # Keywords
81+ - `min_corner`: Coordinates of the domain corner in negative coordinate directions.
82+ - `max_corner`: Coordinates of the domain corner in positive coordinate directions.
83+ """
4484struct PeriodicBox{NDIMS, ELTYPE}
4585 min_corner :: SVector{NDIMS, ELTYPE}
4686 max_corner :: SVector{NDIMS, ELTYPE}
4787 size :: SVector{NDIMS, ELTYPE}
4888
49- function PeriodicBox (min_corner, max_corner)
50- new {length(min_corner), eltype(min_corner)} (min_corner, max_corner,
51- max_corner - min_corner)
89+ function PeriodicBox (; min_corner, max_corner)
90+ min_corner_ = SVector (Tuple (min_corner))
91+ max_corner_ = SVector (Tuple (max_corner))
92+
93+ new {length(min_corner), eltype(min_corner)} (min_corner_, max_corner_,
94+ max_corner_ - min_corner_)
5295 end
5396end
5497
5598# The type annotation is to make Julia specialize on the type of the function.
5699# Otherwise, unspecialized code will cause a lot of allocations
57100# and heavily impact performance.
58101# See https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing
59- function for_particle_neighbor (f:: T , system_coords, neighbor_coords, neighborhood_search;
60- particles = axes (system_coords, 2 ),
61- parallel = true ) where {T}
62- for_particle_neighbor (f, system_coords, neighbor_coords, neighborhood_search, particles ,
63- Val (parallel))
102+ function foreach_point_neighbor (f:: T , system_coords, neighbor_coords, neighborhood_search;
103+ points = axes (system_coords, 2 ),
104+ parallel = true ) where {T}
105+ foreach_point_neighbor (f, system_coords, neighbor_coords, neighborhood_search, points ,
106+ Val (parallel))
64107end
65108
66- @inline function for_particle_neighbor (f, system_coords, neighbor_coords,
67- neighborhood_search, particles , parallel:: Val{true} )
68- @threaded for particle in particles
69- foreach_neighbor (f, system_coords, neighbor_coords, neighborhood_search, particle )
109+ @inline function foreach_point_neighbor (f, system_coords, neighbor_coords,
110+ neighborhood_search, points , parallel:: Val{true} )
111+ @threaded for point in points
112+ foreach_neighbor (f, system_coords, neighbor_coords, neighborhood_search, point )
70113 end
71114
72115 return nothing
73116end
74117
75- @inline function for_particle_neighbor (f, system_coords, neighbor_coords,
76- neighborhood_search, particles , parallel:: Val{false} )
77- for particle in particles
78- foreach_neighbor (f, system_coords, neighbor_coords, neighborhood_search, particle )
118+ @inline function foreach_point_neighbor (f, system_coords, neighbor_coords,
119+ neighborhood_search, points , parallel:: Val{false} )
120+ for point in points
121+ foreach_neighbor (f, system_coords, neighbor_coords, neighborhood_search, point )
79122 end
80123
81124 return nothing
82125end
83126
84127@inline function foreach_neighbor (f, system_coords, neighbor_system_coords,
85- neighborhood_search, particle ;
128+ neighborhood_search, point ;
86129 search_radius = neighborhood_search. search_radius)
87130 (; periodic_box) = neighborhood_search
88131
89- particle_coords = extract_svector (system_coords, Val (ndims (neighborhood_search)),
90- particle)
91- for neighbor in eachneighbor (particle_coords, neighborhood_search)
132+ point_coords = extract_svector (system_coords, Val (ndims (neighborhood_search)), point)
133+ for neighbor in eachneighbor (point_coords, neighborhood_search)
92134 neighbor_coords = extract_svector (neighbor_system_coords,
93135 Val (ndims (neighborhood_search)), neighbor)
94136
95- pos_diff = particle_coords - neighbor_coords
137+ pos_diff = point_coords - neighbor_coords
96138 distance2 = dot (pos_diff, pos_diff)
97139
98140 pos_diff, distance2 = compute_periodic_distance (pos_diff, distance2, search_radius,
102144 distance = sqrt (distance2)
103145
104146 # Inline to avoid loss of performance
105- # compared to not using `for_particle_neighbor `.
106- @inline f (particle , neighbor, pos_diff, distance)
147+ # compared to not using `foreach_point_neighbor `.
148+ @inline f (point , neighbor, pos_diff, distance)
107149 end
108150 end
109151end
113155 return pos_diff, distance2
114156end
115157
116- @inline function compute_periodic_distance (pos_diff, distance2, search_radius,
117- periodic_box)
158+ @inline function compute_periodic_distance (pos_diff, distance2, search_radius, periodic_box)
118159 if distance2 > search_radius^ 2
119160 # Use periodic `pos_diff`
120161 pos_diff -= periodic_box. size .* round .(pos_diff ./ periodic_box. size)
0 commit comments