Compadre 1.6.4
Loading...
Searching...
No Matches
Compadre_NeighborLists.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Compadre: COMpatible PArticle Discretization and REmap Toolkit
4//
5// Copyright 2018 NTESS and the Compadre contributors.
6// SPDX-License-Identifier: BSD-2-Clause
7// *****************************************************************************
8// @HEADER
9#ifndef _COMPADRE_NEIGHBORLISTS_HPP_
10#define _COMPADRE_NEIGHBORLISTS_HPP_
11
12#include "Compadre_Typedefs.hpp"
13#include <Kokkos_Core.hpp>
14
15namespace Compadre {
16
17//! NeighborLists assists in accessing entries of compressed row neighborhood lists
18template <typename view_type>
20
21 typedef view_type internal_view_type;
22 typedef Kokkos::View<global_index_type*, typename view_type::array_layout,
23 typename view_type::memory_space, typename view_type::memory_traits> internal_row_offsets_view_type;
24
29
33
34 typename internal_row_offsets_view_type::host_mirror_type _host_row_offsets;
35 typename view_type::host_mirror_type _host_cr_neighbor_lists;
36 typename view_type::host_mirror_type _host_number_of_neighbors_list;
37
38/** @name Constructors
39 * Ways to initialize a NeighborLists object
40 */
41///@{
42
43 //! \brief Constructor for the purpose of classes who have NeighborLists as a member object
50
51 /*! \brief Constructor for when compressed row `cr_neighbor_lists` is preallocated/populated,
52 * `number_of_neighbors_list` and `neighbor_lists_row_offsets` have already been populated.
53 */
54 NeighborLists(view_type cr_neighbor_lists, view_type number_of_neighbors_list,
55 internal_row_offsets_view_type neighbor_lists_row_offsets, bool compute_max = true) {
56 compadre_assert_release((view_type::rank==1) &&
57 "cr_neighbor_lists and number_neighbors_list and neighbor_lists_row_offsets must be a 1D Kokkos view.");
58
59 _number_of_targets = number_of_neighbors_list.extent(0);
60 _number_of_neighbors_list = number_of_neighbors_list;
61 _cr_neighbor_lists = cr_neighbor_lists;
62 _row_offsets = neighbor_lists_row_offsets;
63
64 _host_cr_neighbor_lists = Kokkos::create_mirror_view(_cr_neighbor_lists);
66 _host_row_offsets = Kokkos::create_mirror_view(_row_offsets);
67
70 Kokkos::deep_copy(_host_row_offsets, _row_offsets);
71 Kokkos::fence();
72
73 if (compute_max) {
75 } else {
77 }
79
80 //check neighbor_lists is large enough
81 compadre_assert_release(((size_t)(this->getTotalNeighborsOverAllListsHost())<=cr_neighbor_lists.extent(0))
82 && "neighbor_lists is not large enough to store all neighbors.");
83
84 _needs_sync_to_host = false;
85 }
86
87 /*! \brief Constructor for when compressed row `cr_neighbor_lists` is preallocated/populated,
88 * and `number_of_neighbors_list` is already populated, and row offsets still need to be computed.
89 */
90 NeighborLists(view_type cr_neighbor_lists, view_type number_of_neighbors_list) {
91 compadre_assert_release((view_type::rank==1)
92 && "cr_neighbor_lists and number_neighbors_list must be a 1D Kokkos view.");
93
94 _number_of_targets = number_of_neighbors_list.extent(0);
95
96 _row_offsets = internal_row_offsets_view_type("row offsets", number_of_neighbors_list.extent(0));
97 _number_of_neighbors_list = number_of_neighbors_list;
98 _cr_neighbor_lists = cr_neighbor_lists;
99
100 _host_cr_neighbor_lists = Kokkos::create_mirror_view(_cr_neighbor_lists);
101 _host_number_of_neighbors_list = Kokkos::create_mirror_view(_number_of_neighbors_list);
102 _host_row_offsets = Kokkos::create_mirror_view(_row_offsets);
103
106 Kokkos::deep_copy(_host_row_offsets, _row_offsets);
107 Kokkos::fence();
108
111
112 //check neighbor_lists is large enough
113 compadre_assert_release(((size_t)(this->getTotalNeighborsOverAllListsHost())<=cr_neighbor_lists.extent(0))
114 && "neighbor_lists is not large enough to store all neighbors.");
115
116 _needs_sync_to_host = false;
117 }
118
119 /*! \brief Constructor for when `number_of_neighbors_list` is already populated.
120 * Will allocate space for compressed row neighbor lists data, and will allocate then
121 * populate information for row offsets.
122 */
123 NeighborLists(view_type number_of_neighbors_list) {
124 compadre_assert_release((view_type::rank==1)
125 && "cr_neighbor_lists and number_neighbors_list must be a 1D Kokkos view.");
126
127 _number_of_targets = number_of_neighbors_list.extent(0);
128
129 _row_offsets = internal_row_offsets_view_type("row offsets", number_of_neighbors_list.extent(0));
130 _number_of_neighbors_list = number_of_neighbors_list;
131
132 _host_number_of_neighbors_list = Kokkos::create_mirror_view(_number_of_neighbors_list);
133 _host_row_offsets = Kokkos::create_mirror_view(_row_offsets);
134
136 Kokkos::deep_copy(_host_row_offsets, _row_offsets);
137 Kokkos::fence();
138
141
142 _cr_neighbor_lists = view_type("compressed row neighbor lists data", this->getTotalNeighborsOverAllListsHost());
143 _host_cr_neighbor_lists = Kokkos::create_mirror_view(_cr_neighbor_lists);
145 Kokkos::fence();
146
147 _needs_sync_to_host = false;
148 }
149///@}
150
151/** @name Public modifiers
152 */
153///@{
154
155 //! Setter function for N(i,j) indexing where N(i,j) is the index of the jth neighbor of i
156 KOKKOS_INLINE_FUNCTION
157 void setNeighborDevice(int target_index, int neighbor_num, int new_value) {
158 _cr_neighbor_lists(_row_offsets(target_index)+neighbor_num) = new_value;
159 // indicate that host view is now out of sync with device
160 // but only in debug mode (notice the next line is both setting the variable and checking it was set)
162 }
163
164 //! Calculate the maximum number of neighbors of all targets' neighborhoods (host)
166 if (_number_of_neighbors_list.extent(0)==0) {
168 } else {
169 auto number_of_neighbors_list = _number_of_neighbors_list;
170 Kokkos::parallel_reduce("max number of neighbors",
171 Kokkos::RangePolicy<typename view_type::execution_space>(0, _number_of_neighbors_list.extent(0)),
172 KOKKOS_LAMBDA(const int i, int& t_max_num_neighbors) {
173 t_max_num_neighbors = (number_of_neighbors_list(i) > t_max_num_neighbors) ? number_of_neighbors_list(i) : t_max_num_neighbors;
174 }, Kokkos::Max<int>(_max_neighbor_list_row_storage_size));
175 Kokkos::fence();
176 }
177 }
178
179 //! Calculate the minimum number of neighbors of all targets' neighborhoods (host)
181 if (_number_of_neighbors_list.extent(0)==0) {
183 } else {
184 auto number_of_neighbors_list = _number_of_neighbors_list;
185 Kokkos::parallel_reduce("min number of neighbors",
186 Kokkos::RangePolicy<typename view_type::execution_space>(0, _number_of_neighbors_list.extent(0)),
187 KOKKOS_LAMBDA(const int i, int& t_min_num_neighbors) {
188 t_min_num_neighbors = (number_of_neighbors_list(i) < t_min_num_neighbors) ? number_of_neighbors_list(i) : t_min_num_neighbors;
189 }, Kokkos::Min<int>(_min_neighbor_list_row_storage_size));
190 Kokkos::fence();
191 }
192 }
193
194 //! Calculate the row offsets for each target's neighborhood (host)
196 auto number_of_neighbors_list = _number_of_neighbors_list;
197 auto row_offsets = _row_offsets;
198 Kokkos::parallel_scan("number of neighbors offsets",
199 Kokkos::RangePolicy<typename view_type::execution_space>(0, _number_of_neighbors_list.extent(0)),
200 KOKKOS_LAMBDA(const int i, global_index_type& lsum, bool final) {
201 row_offsets(i) = lsum;
202 lsum += number_of_neighbors_list(i);
203 });
204 Kokkos::deep_copy(_host_row_offsets, _row_offsets);
205 Kokkos::fence();
206 }
207
208 //! Sync the host from the device (copy device data to host)
211 Kokkos::fence();
212 _needs_sync_to_host = false;
213 }
214
215 //! Device view into neighbor lists data (use with caution)
216 view_type getNeighborLists() const {
217 return _cr_neighbor_lists;
218 }
219
220 //! Device view into number of neighbors list (use with caution)
221 view_type getNumberOfNeighborsList() const {
223 }
224
225///@}
226/** @name Public accessors
227 */
228///@{
229 //! Get number of total targets having neighborhoods (host/device).
230 KOKKOS_INLINE_FUNCTION
231 int getNumberOfTargets() const {
232 return _number_of_targets;
233 }
234
235 //! Get number of neighbors for a given target (host)
236 int getNumberOfNeighborsHost(int target_index) const {
238 return _host_number_of_neighbors_list(target_index);
239 }
240
241 //! Get number of neighbors for a given target (device)
242 KOKKOS_INLINE_FUNCTION
243 int getNumberOfNeighborsDevice(int target_index) const {
245 return _number_of_neighbors_list(target_index);
246 }
247
248 //! Get offset into compressed row neighbor lists (host)
249 global_index_type getRowOffsetHost(int target_index) const {
251 return _host_row_offsets(target_index);
252 }
253
254 //! Get offset into compressed row neighbor lists (device)
255 KOKKOS_INLINE_FUNCTION
256 global_index_type getRowOffsetDevice(int target_index) const {
258 return _row_offsets(target_index);
259 }
260
261 //! Offers N(i,j) indexing where N(i,j) is the index of the jth neighbor of i (host)
262 int getNeighborHost(int target_index, int neighbor_num) const {
265 && "Stale information in host_cr_neighbor_lists. Call CopyDeviceDataToHost() to refresh.");
266 compadre_assert_debug((neighbor_num<_host_number_of_neighbors_list(target_index))
267 && "neighor_num exceeds number of neighbors for this target_index.");
268 return _host_cr_neighbor_lists(_host_row_offsets(target_index)+neighbor_num);
269 }
270
271 //! Offers N(i,j) indexing where N(i,j) is the index of the jth neighbor of i (device)
272 KOKKOS_INLINE_FUNCTION
273 int getNeighborDevice(int target_index, int neighbor_num) const {
275 && "neighor_num exceeds number of neighbors for this target_index.");
277 return _cr_neighbor_lists(_row_offsets(target_index)+neighbor_num);
278 }
279
280 //! Get the maximum number of neighbors of all targets' neighborhoods (host/device)
281 KOKKOS_INLINE_FUNCTION
282 int getMaxNumNeighbors() const {
283 compadre_kernel_assert_debug((_max_neighbor_list_row_storage_size > -1) && "getMaxNumNeighbors() called but maximum never calculated.");
285 }
286
287 //! Get the minimum number of neighbors of all targets' neighborhoods (host/device)
288 KOKKOS_INLINE_FUNCTION
289 int getMinNumNeighbors() const {
290 compadre_kernel_assert_debug((_min_neighbor_list_row_storage_size > -1) && "getMinNumNeighbors() called but minimum never calculated.");
292 }
293
294 //! Get the sum of the number of neighbors of all targets' neighborhoods (host)
296 if (this->getNumberOfTargets()==0) {
297 return 0;
298 } else {
300 }
301 }
302
303 //! Get the sum of the number of neighbors of all targets' neighborhoods (device)
304 KOKKOS_INLINE_FUNCTION
308///@}
309
310}; // NeighborLists
311
312//! CreateNeighborLists allows for the construction of an object of type NeighborLists with template deduction
313template <typename view_type>
314NeighborLists<view_type> CreateNeighborLists(view_type number_of_neighbors_list) {
315 return NeighborLists<view_type>(number_of_neighbors_list);
316}
317
318//! CreateNeighborLists allows for the construction of an object of type NeighborLists with template deduction
319template <typename view_type>
320NeighborLists<view_type> CreateNeighborLists(view_type neighbor_lists, view_type number_of_neighbors_list) {
321 return NeighborLists<view_type>(neighbor_lists, number_of_neighbors_list);
322}
323
324//! CreateNeighborLists allows for the construction of an object of type NeighborLists with template deduction
325template <typename view_type>
326NeighborLists<view_type> CreateNeighborLists(view_type neighbor_lists, view_type number_of_neighbors_list, view_type neighbor_lists_row_offsets) {
327 return NeighborLists<view_type>(neighbor_lists, number_of_neighbors_list, neighbor_lists_row_offsets);
328}
329
330//! Converts 2D neighbor lists to compressed row neighbor lists
331template <typename view_type_2d, typename view_type_1d = Kokkos::View<int*, typename view_type_2d::memory_space, typename view_type_2d::memory_traits> >
333
334 // gets total number of neighbors over all lists
335 // computes calculation where the data resides (device/host)
336 global_index_type total_storage_size = 0;
337 Kokkos::parallel_reduce("total number of neighbors over all lists", Kokkos::RangePolicy<typename view_type_2d::execution_space>(0, neighbor_lists.extent(0)),
338 KOKKOS_LAMBDA(const int i, global_index_type& t_total_num_neighbors) {
339 t_total_num_neighbors += neighbor_lists(i,0);
340 }, Kokkos::Sum<global_index_type>(total_storage_size));
341 Kokkos::fence();
342
343 // view_type_1d may be on host or device, and view_type_2d may be either as well (could even be opposite)
344 view_type_1d new_cr_neighbor_lists("compressed row neighbor lists", total_storage_size);
345 view_type_1d new_number_of_neighbors_list("number of neighbors list", neighbor_lists.extent(0));
346
347 // copy number of neighbors list over to view_type_1d
348 // d_neighbor_lists will be accessible from view_type_1d's execution space
349 auto d_neighbor_lists = create_mirror_view(typename view_type_1d::execution_space(), neighbor_lists);
350 Kokkos::deep_copy(d_neighbor_lists, neighbor_lists);
351 Kokkos::fence();
352 Kokkos::parallel_for("copy number of neighbors to compressed row",
353 Kokkos::RangePolicy<typename view_type_1d::execution_space>(0, neighbor_lists.extent(0)),
354 KOKKOS_LAMBDA(const int i) {
355 new_number_of_neighbors_list(i) = d_neighbor_lists(i,0);
356 });
357 Kokkos::fence();
358
359
360 // this will calculate row offsets
361 auto nla = CreateNeighborLists(new_cr_neighbor_lists, new_number_of_neighbors_list);
362 auto cr_data = nla.getNeighborLists();
363
364 // if device_execution_space can access this view, then write directly into the view
365 if (Kokkos::SpaceAccessibility<device_execution_space, typename view_type_1d::memory_space>::accessible==1) {
366 Kokkos::parallel_for("copy neighbor lists to compressed row", Kokkos::RangePolicy<typename view_type_1d::execution_space>(0, neighbor_lists.extent(0)),
367 KOKKOS_LAMBDA(const int i) {
368 for (int j=0; j<d_neighbor_lists(i,0); ++j) {
369 cr_data(nla.getRowOffsetDevice(i)+j) = d_neighbor_lists(i,j+1);
370 }
371 });
372 Kokkos::fence();
373 nla.copyDeviceDataToHost(); // has a fence at the end
374 }
375 // otherwise we are writing to a view that can't be seen from device (must be host space),
376 // and d_neighbor_lists was already made to be a view_type that is accessible from view_type_1d's execution_space
377 // (which we know is host) so we can do a parallel_for over the host_execution_space
378 else {
379 Kokkos::parallel_for("copy neighbor lists to compressed row", Kokkos::RangePolicy<host_execution_space>(0, neighbor_lists.extent(0)),
380 KOKKOS_LAMBDA(const int i) {
381 for (int j=0; j<neighbor_lists(i,0); ++j) {
382 cr_data(nla.getRowOffsetHost(i)+j) = d_neighbor_lists(i,j+1);
383 }
384 });
385 Kokkos::fence();
386 }
387
388 return nla;
389}
390
391} // Compadre namespace
392
393#endif
394
#define compadre_kernel_assert_debug(condition)
#define compadre_assert_extreme_debug(condition)
compadre_kernel_assert_debug is similar to compadre_assert_debug, but is a call on the device,...
#define compadre_assert_debug(condition)
compadre_assert_debug is used for assertions that are checked in loops, as these significantly impact...
#define TO_GLOBAL(variable)
#define compadre_kernel_assert_extreme_debug(condition)
#define compadre_assert_release(condition)
compadre_assert_release is used for assertions that should always be checked, but generally are not e...
NeighborLists< view_type > CreateNeighborLists(view_type number_of_neighbors_list)
CreateNeighborLists allows for the construction of an object of type NeighborLists with template dedu...
NeighborLists< view_type_1d > Convert2DToCompressedRowNeighborLists(view_type_2d neighbor_lists)
Converts 2D neighbor lists to compressed row neighbor lists.
std::size_t global_index_type
NeighborLists assists in accessing entries of compressed row neighborhood lists.
KOKKOS_INLINE_FUNCTION global_index_type getTotalNeighborsOverAllListsDevice() const
Get the sum of the number of neighbors of all targets' neighborhoods (device)
void computeMinNumNeighbors()
Calculate the minimum number of neighbors of all targets' neighborhoods (host)
KOKKOS_INLINE_FUNCTION int getMinNumNeighbors() const
Get the minimum number of neighbors of all targets' neighborhoods (host/device)
view_type getNeighborLists() const
Device view into neighbor lists data (use with caution)
global_index_type getRowOffsetHost(int target_index) const
Get offset into compressed row neighbor lists (host)
KOKKOS_INLINE_FUNCTION global_index_type getRowOffsetDevice(int target_index) const
Get offset into compressed row neighbor lists (device)
NeighborLists(view_type number_of_neighbors_list)
Constructor for when number_of_neighbors_list is already populated. Will allocate space for compresse...
view_type::host_mirror_type _host_cr_neighbor_lists
int getNeighborHost(int target_index, int neighbor_num) const
Offers N(i,j) indexing where N(i,j) is the index of the jth neighbor of i (host)
Kokkos::View< global_index_type *, typename view_type::array_layout, typename view_type::memory_space, typename view_type::memory_traits > internal_row_offsets_view_type
view_type getNumberOfNeighborsList() const
Device view into number of neighbors list (use with caution)
internal_row_offsets_view_type::host_mirror_type _host_row_offsets
KOKKOS_INLINE_FUNCTION int getNumberOfNeighborsDevice(int target_index) const
Get number of neighbors for a given target (device)
KOKKOS_INLINE_FUNCTION int getNeighborDevice(int target_index, int neighbor_num) const
Offers N(i,j) indexing where N(i,j) is the index of the jth neighbor of i (device)
global_index_type getTotalNeighborsOverAllListsHost() const
Get the sum of the number of neighbors of all targets' neighborhoods (host)
NeighborLists(view_type cr_neighbor_lists, view_type number_of_neighbors_list, internal_row_offsets_view_type neighbor_lists_row_offsets, bool compute_max=true)
Constructor for when compressed row cr_neighbor_lists is preallocated/populated, number_of_neighbors_...
void computeRowOffsets()
Calculate the row offsets for each target's neighborhood (host)
NeighborLists(view_type cr_neighbor_lists, view_type number_of_neighbors_list)
Constructor for when compressed row cr_neighbor_lists is preallocated/populated, and number_of_neighb...
KOKKOS_INLINE_FUNCTION int getMaxNumNeighbors() const
Get the maximum number of neighbors of all targets' neighborhoods (host/device)
view_type::host_mirror_type _host_number_of_neighbors_list
internal_row_offsets_view_type _row_offsets
KOKKOS_INLINE_FUNCTION int getNumberOfTargets() const
Get number of total targets having neighborhoods (host/device).
KOKKOS_INLINE_FUNCTION void setNeighborDevice(int target_index, int neighbor_num, int new_value)
Setter function for N(i,j) indexing where N(i,j) is the index of the jth neighbor of i.
NeighborLists()
Constructor for the purpose of classes who have NeighborLists as a member object.
void copyDeviceDataToHost()
Sync the host from the device (copy device data to host)
int getNumberOfNeighborsHost(int target_index) const
Get number of neighbors for a given target (host)
void computeMaxNumNeighbors()
Calculate the maximum number of neighbors of all targets' neighborhoods (host)