Compadre  1.2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Compadre_NeighborLists.hpp
Go to the documentation of this file.
1 #ifndef _COMPADRE_NEIGHBORLISTS_HPP_
2 #define _COMPADRE_NEIGHBORLISTS_HPP_
3 
4 #include "Compadre_Typedefs.hpp"
5 #include <Kokkos_Core.hpp>
6 
7 namespace Compadre {
8 
9 //! NeighborLists assists in accessing entries of compressed row neighborhood lists
10 template <typename view_type>
12 public:
13 
14  typedef view_type internal_view_type;
15  typedef Kokkos::View<global_index_type*, typename view_type::array_layout,
16  typename view_type::memory_space, typename view_type::memory_traits> internal_row_offsets_view_type;
17 
18 protected:
19 
20 
24 
26  view_type _cr_neighbor_lists;
28 
29  typename internal_row_offsets_view_type::HostMirror _host_row_offsets;
30  typename view_type::HostMirror _host_cr_neighbor_lists;
31  typename view_type::HostMirror _host_number_of_neighbors_list;
32 
33 
34 public:
35 
36 /** @name Constructors
37  * Ways to initialize a NeighborLists object
38  */
39 ///@{
40 
41  //! \brief Constructor for the purpose of classes who have NeighborLists as a member object
44  _needs_sync_to_host = true;
46  }
47 
48  /*! \brief Constructor for when compressed row `cr_neighbor_lists` is preallocated/populated,
49  * `number_of_neighbors_list` and `neighbor_lists_row_offsets` have already been populated.
50  */
51  NeighborLists(view_type cr_neighbor_lists, view_type number_of_neighbors_list,
52  internal_row_offsets_view_type neighbor_lists_row_offsets, bool compute_max = true) {
53  compadre_assert_release((view_type::rank==1) &&
54  "cr_neighbor_lists and number_neighbors_list and neighbor_lists_row_offsets must be a 1D Kokkos view.");
55 
56  _number_of_targets = number_of_neighbors_list.extent(0);
57  _number_of_neighbors_list = number_of_neighbors_list;
58  _cr_neighbor_lists = cr_neighbor_lists;
59  _row_offsets = neighbor_lists_row_offsets;
60 
61  _host_cr_neighbor_lists = Kokkos::create_mirror_view(_cr_neighbor_lists);
62  _host_number_of_neighbors_list = Kokkos::create_mirror_view(_number_of_neighbors_list);
63  _host_row_offsets = Kokkos::create_mirror_view(_row_offsets);
64 
65  Kokkos::deep_copy(_host_cr_neighbor_lists, _cr_neighbor_lists);
67  Kokkos::deep_copy(_host_row_offsets, _row_offsets);
68  Kokkos::fence();
69 
70  if (compute_max) {
72  } else {
74  }
75 
76  //check neighbor_lists is large enough
77  compadre_assert_release(((size_t)(this->getTotalNeighborsOverAllListsHost())<=cr_neighbor_lists.extent(0))
78  && "neighbor_lists is not large enough to store all neighbors.");
79 
80  _needs_sync_to_host = false;
81  }
82 
83  /*! \brief Constructor for when compressed row `cr_neighbor_lists` is preallocated/populated,
84  * and `number_of_neighbors_list` is already populated, and row offsets still need to be computed.
85  */
86  NeighborLists(view_type cr_neighbor_lists, view_type number_of_neighbors_list) {
87  compadre_assert_release((view_type::rank==1)
88  && "cr_neighbor_lists and number_neighbors_list must be a 1D Kokkos view.");
89 
90  _number_of_targets = number_of_neighbors_list.extent(0);
91 
92  _row_offsets = internal_row_offsets_view_type("row offsets", number_of_neighbors_list.extent(0));
93  _number_of_neighbors_list = number_of_neighbors_list;
94  _cr_neighbor_lists = cr_neighbor_lists;
95 
96  _host_cr_neighbor_lists = Kokkos::create_mirror_view(_cr_neighbor_lists);
97  _host_number_of_neighbors_list = Kokkos::create_mirror_view(_number_of_neighbors_list);
98  _host_row_offsets = Kokkos::create_mirror_view(_row_offsets);
99 
100  Kokkos::deep_copy(_host_cr_neighbor_lists, _cr_neighbor_lists);
101  Kokkos::deep_copy(_host_number_of_neighbors_list, _number_of_neighbors_list);
102  Kokkos::deep_copy(_host_row_offsets, _row_offsets);
103  Kokkos::fence();
104 
107 
108  //check neighbor_lists is large enough
109  compadre_assert_release(((size_t)(this->getTotalNeighborsOverAllListsHost())<=cr_neighbor_lists.extent(0))
110  && "neighbor_lists is not large enough to store all neighbors.");
111 
112  _needs_sync_to_host = false;
113  }
114 
115  /*! \brief Constructor for when `number_of_neighbors_list` is already populated.
116  * Will allocate space for compressed row neighbor lists data, and will allocate then
117  * populate information for row offsets.
118  */
119  NeighborLists(view_type number_of_neighbors_list) {
120  compadre_assert_release((view_type::rank==1)
121  && "cr_neighbor_lists and number_neighbors_list must be a 1D Kokkos view.");
122 
123  _number_of_targets = number_of_neighbors_list.extent(0);
124 
125  _row_offsets = internal_row_offsets_view_type("row offsets", number_of_neighbors_list.extent(0));
126  _number_of_neighbors_list = number_of_neighbors_list;
127 
128  _host_number_of_neighbors_list = Kokkos::create_mirror_view(_number_of_neighbors_list);
129  _host_row_offsets = Kokkos::create_mirror_view(_row_offsets);
130 
131  Kokkos::deep_copy(_host_number_of_neighbors_list, _number_of_neighbors_list);
132  Kokkos::deep_copy(_host_row_offsets, _row_offsets);
133  Kokkos::fence();
134 
137 
138  _cr_neighbor_lists = view_type("compressed row neighbor lists data", this->getTotalNeighborsOverAllListsHost());
139  _host_cr_neighbor_lists = Kokkos::create_mirror_view(_cr_neighbor_lists);
140  Kokkos::deep_copy(_host_cr_neighbor_lists, _cr_neighbor_lists);
141  Kokkos::fence();
142 
143  _needs_sync_to_host = false;
144  }
145 ///@}
146 
147 /** @name Public modifiers
148  */
149 ///@{
150 
151  //! Setter function for N(i,j) indexing where N(i,j) is the index of the jth neighbor of i
152  KOKKOS_INLINE_FUNCTION
153  void setNeighborDevice(int target_index, int neighbor_num, int new_value) {
154  _cr_neighbor_lists(_row_offsets(target_index)+neighbor_num) = new_value;
155  // indicate that host view is now out of sync with device
156  _needs_sync_to_host |= true;
157  }
158 
159  //! Calculate the maximum number of neighbors of all targets' neighborhoods (host)
162  auto number_of_neighbors_list = _number_of_neighbors_list;
163  Kokkos::parallel_reduce("max number of neighbors",
164  Kokkos::RangePolicy<typename view_type::execution_space>(0, _number_of_neighbors_list.extent(0)),
165  KOKKOS_LAMBDA(const int i, int& t_max_num_neighbors) {
166  t_max_num_neighbors = (number_of_neighbors_list(i) > t_max_num_neighbors) ? number_of_neighbors_list(i) : t_max_num_neighbors;
167  }, Kokkos::Max<int>(_max_neighbor_list_row_storage_size));
168  Kokkos::fence();
169  }
170 
171  //! Calculate the row offsets for each target's neighborhood (host)
173  auto number_of_neighbors_list = _number_of_neighbors_list;
174  auto row_offsets = _row_offsets;
175  Kokkos::parallel_scan("number of neighbors offsets",
176  Kokkos::RangePolicy<typename view_type::execution_space>(0, _number_of_neighbors_list.extent(0)),
177  KOKKOS_LAMBDA(const int i, global_index_type& lsum, bool final) {
178  row_offsets(i) = lsum;
179  lsum += number_of_neighbors_list(i);
180  });
181  Kokkos::deep_copy(_host_row_offsets, _row_offsets);
182  Kokkos::fence();
183  }
184 
185  //! Sync the host from the device (copy device data to host)
187  Kokkos::deep_copy(_host_cr_neighbor_lists, _cr_neighbor_lists);
188  Kokkos::fence();
189  _needs_sync_to_host = false;
190  }
191 
192  //! Device view into neighbor lists data (use with caution)
193  view_type getNeighborLists() {
194  return _cr_neighbor_lists;
195  }
196 
197 ///@}
198 /** @name Public accessors
199  */
200 ///@{
201  //! Get number of total targets having neighborhoods (host/device).
202  KOKKOS_INLINE_FUNCTION
203  int getNumberOfTargets() const {
204  return _number_of_targets;
205  }
206 
207  //! Get number of neighbors for a given target (host)
208  int getNumberOfNeighborsHost(int target_index) const {
209  return _host_number_of_neighbors_list(target_index);
210  }
211 
212  //! Get number of neighbors for a given target (device)
213  KOKKOS_INLINE_FUNCTION
214  int getNumberOfNeighborsDevice(int target_index) const {
215  return _number_of_neighbors_list(target_index);
216  }
217 
218  //! Get offset into compressed row neighbor lists (host)
219  global_index_type getRowOffsetHost(int target_index) const {
220  return _host_row_offsets(target_index);
221  }
222 
223  //! Get offset into compressed row neighbor lists (device)
224  KOKKOS_INLINE_FUNCTION
225  global_index_type getRowOffsetDevice(int target_index) const {
226  return _row_offsets(target_index);
227  }
228 
229  //! Offers N(i,j) indexing where N(i,j) is the index of the jth neighbor of i (host)
230  int getNeighborHost(int target_index, int neighbor_num) const {
231  if (_needs_sync_to_host) {
233  && "Stale information in host_cr_neighbor_lists. Call CopyDeviceDataToHost() to refresh.");
234  }
235  return _host_cr_neighbor_lists(_row_offsets(target_index)+neighbor_num);
236  }
237 
238  //! Offers N(i,j) indexing where N(i,j) is the index of the jth neighbor of i (device)
239  KOKKOS_INLINE_FUNCTION
240  int getNeighborDevice(int target_index, int neighbor_num) const {
241  return _cr_neighbor_lists(_row_offsets(target_index)+neighbor_num);
242  }
243 
244  //! Get the maximum number of neighbors of all targets' neighborhoods (host/device)
245  KOKKOS_INLINE_FUNCTION
246  int getMaxNumNeighbors() const {
247  compadre_kernel_assert_debug((_max_neighbor_list_row_storage_size > -1) && "getMaxNumNeighbors() called but maximum never calculated.");
249  }
250 
251  //! Get the sum of the number of neighbors of all targets' neighborhoods (host)
254  }
255 
256  //! Get the sum of the number of neighbors of all targets' neighborhoods (device)
257  KOKKOS_INLINE_FUNCTION
260  }
261 ///@}
262 
263 }; // NeighborLists
264 
265 //! CreateNeighborLists allows for the construction of an object of type NeighborLists with template deduction
266 template <typename view_type>
267 NeighborLists<view_type> CreateNeighborLists(view_type neighbor_lists, view_type number_of_neighbors_list) {
268  return NeighborLists<view_type>(neighbor_lists, number_of_neighbors_list);
269 }
270 
271 //! CreateNeighborLists allows for the construction of an object of type NeighborLists with template deduction
272 template <typename view_type>
273 NeighborLists<view_type> CreateNeighborLists(view_type neighbor_lists, view_type number_of_neighbors_list, view_type neighbor_lists_row_offsets) {
274  return NeighborLists<view_type>(neighbor_lists, number_of_neighbors_list, neighbor_lists_row_offsets);
275 }
276 
277 //! Converts 2D neighbor lists to compressed row neighbor lists
278 template <typename view_type_2d, typename view_type_1d = Kokkos::View<int*, typename view_type_2d::memory_space, typename view_type_2d::memory_traits> >
280 
281  // gets total number of neighbors over all lists
282  // computes calculation where the data resides (device/host)
283  int total_storage_size = 0;
284  Kokkos::parallel_reduce("total number of neighbors over all lists", Kokkos::RangePolicy<typename view_type_2d::execution_space>(0, neighbor_lists.extent(0)),
285  KOKKOS_LAMBDA(const int i, int& t_total_num_neighbors) {
286  t_total_num_neighbors += neighbor_lists(i,0);
287  }, Kokkos::Sum<int>(total_storage_size));
288  Kokkos::fence();
289 
290  // view_type_1d may be on host or device, and view_type_2d may be either as well (could even be opposite)
291  view_type_1d new_cr_neighbor_lists("compressed row neighbor lists", total_storage_size);
292  view_type_1d new_number_of_neighbors_list("number of neighbors list", neighbor_lists.extent(0));
293 
294  // copy number of neighbors list over to view_type_1d
295  // d_neighbor_lists will be accessible from view_type_1d's execution space
296  auto d_neighbor_lists = create_mirror_view(typename view_type_1d::execution_space(), neighbor_lists);
297  Kokkos::deep_copy(d_neighbor_lists, neighbor_lists);
298  Kokkos::fence();
299  Kokkos::parallel_for("copy number of neighbors to compressed row",
300  Kokkos::RangePolicy<typename view_type_1d::execution_space>(0, neighbor_lists.extent(0)),
301  KOKKOS_LAMBDA(const int i) {
302  new_number_of_neighbors_list(i) = d_neighbor_lists(i,0);
303  });
304  Kokkos::fence();
305 
306 
307  // this will calculate row offsets
308  auto nla(CreateNeighborLists(new_cr_neighbor_lists, new_number_of_neighbors_list));
309  auto cr_data = nla.getNeighborLists();
310 
311  // if device_execution_space can access this view, then write directly into the view
312  if (Kokkos::SpaceAccessibility<device_execution_space, typename view_type_1d::memory_space>::accessible==1) {
313  Kokkos::parallel_for("copy neighbor lists to compressed row", Kokkos::RangePolicy<typename view_type_1d::execution_space>(0, neighbor_lists.extent(0)),
314  KOKKOS_LAMBDA(const int i) {
315  for (int j=0; j<d_neighbor_lists(i,0); ++j) {
316  cr_data(nla.getRowOffsetDevice(i)+j) = d_neighbor_lists(i,j+1);
317  }
318  });
319  nla.copyDeviceDataToHost(); // has a fence at the end
320  }
321  // otherwise we are writing to a view that can't be seen from device (must be host space),
322  // and d_neighbor_lists was already made to be a view_type that is accessible from view_type_1d's execution_space
323  // (which we know is host) so we can do a parallel_for over the host_execution_space
324  else {
325  Kokkos::parallel_for("copy neighbor lists to compressed row", Kokkos::RangePolicy<host_execution_space>(0, neighbor_lists.extent(0)),
326  KOKKOS_LAMBDA(const int i) {
327  for (int j=0; j<neighbor_lists(i,0); ++j) {
328  cr_data(nla.getRowOffsetHost(i)+j) = d_neighbor_lists(i,j+1);
329  }
330  });
331  Kokkos::fence();
332  }
333 
334  return nla;
335 }
336 
337 } // Compadre namespace
338 
339 #endif
340 
view_type::HostMirror _host_number_of_neighbors_list
std::size_t global_index_type
KOKKOS_INLINE_FUNCTION int getMaxNumNeighbors() const
Get the maximum number of neighbors of all targets&#39; neighborhoods (host/device)
internal_row_offsets_view_type::HostMirror _host_row_offsets
int getNumberOfNeighborsHost(int target_index) const
Get number of neighbors for a given target (host)
view_type getNeighborLists()
Device view into neighbor lists data (use with caution)
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
void computeMaxNumNeighbors()
Calculate the maximum number of neighbors of all targets&#39; neighborhoods (host)
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) ...
NeighborLists< view_type > CreateNeighborLists(view_type neighbor_lists, view_type number_of_neighbors_list)
CreateNeighborLists allows for the construction of an object of type NeighborLists with template dedu...
#define TO_GLOBAL(variable)
KOKKOS_INLINE_FUNCTION int getNumberOfTargets() const
Get number of total targets having neighborhoods (host/device).
KOKKOS_INLINE_FUNCTION int getNumberOfNeighborsDevice(int target_index) const
Get number of neighbors for a given target (device)
NeighborLists()
Constructor for the purpose of classes who have NeighborLists as a member object. ...
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(view_type number_of_neighbors_list)
Constructor for when number_of_neighbors_list is already populated. Will allocate space for compresse...
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&#39; neighborhoods (device)
global_index_type getRowOffsetHost(int target_index) const
Get offset into compressed row neighbor lists (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 global_index_type getRowOffsetDevice(int target_index) const
Get offset into compressed row neighbor lists (device)
void computeRowOffsets()
Calculate the row offsets for each target&#39;s neighborhood (host)
void copyDeviceDataToHost()
Sync the host from the device (copy device data to host)
global_index_type getTotalNeighborsOverAllListsHost() const
Get the sum of the number of neighbors of all targets&#39; neighborhoods (host)
#define compadre_assert_debug(condition)
compadre_assert_debug is used for assertions that are checked in loops, as these significantly impact...
view_type::HostMirror _host_cr_neighbor_lists
NeighborLists< view_type_1d > Convert2DToCompressedRowNeighborLists(view_type_2d neighbor_lists)
Converts 2D neighbor lists to compressed row neighbor lists.
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_...
#define compadre_assert_release(condition)
compadre_assert_release is used for assertions that should always be checked, but generally are not e...
internal_row_offsets_view_type _row_offsets
#define compadre_kernel_assert_debug(condition)