MeshFields
GPU accelerated mesh-based fields
MeshField_Field.hpp
1 #ifndef MESHFIELD_FIELD_HPP
2 #define MESHFIELD_FIELD_HPP
3 
4 #include <Kokkos_Array.hpp>
5 #include <array>
6 #include <cstdio>
7 #include <stdexcept>
8 #include <type_traits> // std::same_v<t1,t2>
9 
10 #include "MeshField_Fail.hpp"
11 #include "MeshField_Utility.hpp"
12 #include <Kokkos_Core.hpp>
13 #include <Kokkos_StdAlgorithms.hpp>
14 
15 namespace {
16 template <class Field, class View>
17 void checkExtents(Field &field, View &view, std::string key) {
18  bool matches = true;
19  for (int i = 0; i < Field::Rank; i++) {
20  matches = matches && (view.extent(i) == field.size(i));
21  }
22  if (!matches) {
23  MeshField::fail("%s: the extents of the view does not match the field\n",
24  key.c_str());
25  }
26 }
27 } // namespace
28 
29 namespace MeshField {
30 
46 template <class Slice> class Field {
47 
48  Slice slice;
49  typedef typename Slice::Type Type;
50  typedef typename std::remove_pointer<Type>::type type_rank1;
51  typedef typename std::remove_pointer<type_rank1>::type type_rank2;
52  typedef typename std::remove_pointer<type_rank2>::type type_rank3;
53  typedef typename std::remove_pointer<type_rank3>::type type_rank4;
54  typedef typename std::remove_pointer<type_rank4>::type type_rank5;
55  typedef type_rank5 base_type;
56 
57  using ExecutionSpace = typename Slice::ExecutionSpace;
58 
59  const Kokkos::Array<size_t, Slice::RANK> divisors;
60 
67  auto computeDivisors() {
68  Kokkos::Array<size_t, Rank> div;
69  for (int r = 0; r < Rank; r++) {
70  div[r] = 1;
71  for (int i = r + 1; i < Rank; ++i) {
72  div[r] *= size(i);
73  }
74  }
75  return div;
76  }
77 
87  KOKKOS_INLINE_FUNCTION
88  auto linearIdxToTensorIdx(size_t index) const {
89  Kokkos::Array<size_t, Rank> multiIndex;
90  for (int i = 0; i < Rank; ++i) {
91  multiIndex[i] = index / divisors[i];
92  assert(multiIndex[i] < size(i));
93  index %= divisors[i];
94  }
95  return multiIndex;
96  }
97 
101  KOKKOS_INLINE_FUNCTION
102  auto totalSize() const { return size(0) * divisors[0]; }
103 
104 public:
105  static const int MAX_RANK = Slice::MAX_RANK;
106  static const int Rank = Slice::RANK;
107  using BaseType = base_type;
108 
109  Field(Slice s) : slice(s), divisors(computeDivisors()) {}
110 
117  KOKKOS_INLINE_FUNCTION
118  size_t size(int i) const { return slice.size(i); }
119 
123  KOKKOS_INLINE_FUNCTION
124  auto &operator()(int s) const { return slice(s); }
125 
126  KOKKOS_INLINE_FUNCTION
127  auto &operator()(int s, int a) const { return slice(s, a); }
128 
129  KOKKOS_INLINE_FUNCTION
130  auto &operator()(int s, int a, int i) const { return slice(s, a, i); }
131 
132  KOKKOS_INLINE_FUNCTION
133  auto &operator()(int s, int a, int i, int j) const {
134  return slice(s, a, i, j);
135  }
136  KOKKOS_INLINE_FUNCTION
137  auto &operator()(int s, int a, int i, int j, int k) const {
138  return slice(s, a, i, j, k);
139  }
140 
141  void serialize_impl(Kokkos::View<base_type *> &serial) const {
142  assert(serial.size() == totalSize());
143  Kokkos::parallel_for(
144  "field serializer", serial.size(),
145  KOKKOS_CLASS_LAMBDA(const int index) {
146  constexpr std::size_t rank = Rank;
147  auto serial_data = serial;
148  auto sIndex = linearIdxToTensorIdx(index);
149  if constexpr (rank == 1) {
150  serial_data(index) = slice(index);
151  } else if constexpr (rank == 2) {
152  serial_data(index) = slice(sIndex[0], sIndex[1]);
153  } else if constexpr (rank == 3) {
154  serial_data(index) = slice(sIndex[0], sIndex[1], sIndex[2]);
155  } else if constexpr (rank == 4) {
156  serial_data(index) =
157  slice(sIndex[0], sIndex[1], sIndex[2], sIndex[3]);
158  } else if constexpr (rank == 5) {
159  serial_data(index) =
160  slice(sIndex[0], sIndex[1], sIndex[2], sIndex[3], sIndex[4]);
161  }
162  });
163  }
164 
172  Kokkos::View<base_type *> serialize() const {
173  auto N = totalSize();
174  Kokkos::View<base_type *> serial("serialized field", N);
175  serialize_impl(serial);
176  return std::move(serial);
177  }
178 
187  void serialize(Kokkos::View<base_type *> &serial) const {
188  const size_t N = totalSize();
189  assert(N == serial.size());
190  serialize_impl(serial);
191  }
192 
200  void deserialize(const Kokkos::View<const base_type *> &serialized) {
201  const size_t N = totalSize();
202  assert(N == serialized.size());
203  Kokkos::parallel_for(
204  "field deserializer", N, KOKKOS_CLASS_LAMBDA(const int index) {
205  auto serialized_data = serialized;
206 
207  constexpr std::size_t rank = Rank;
208  auto sIndex = linearIdxToTensorIdx(index);
209  if constexpr (rank == 1) {
210  slice(index) = serialized_data(index);
211  } else if constexpr (rank == 2) {
212  slice(sIndex[0], sIndex[1]) = serialized_data(index);
213  } else if constexpr (rank == 3) {
214  slice(sIndex[0], sIndex[1], sIndex[2]) = serialized_data(index);
215  } else if constexpr (rank == 4) {
216  slice(sIndex[0], sIndex[1], sIndex[2], sIndex[3]) =
217  serialized_data(index);
218  } else if constexpr (rank == 5) {
219  slice(sIndex[0], sIndex[1], sIndex[2], sIndex[3], sIndex[4]) =
220  serialized_data(index);
221  }
222  });
223  }
224 
225  template <class View> void setRankOne(View &view) {
226  Kokkos::RangePolicy<ExecutionSpace> p(0, size(0));
227  Kokkos::parallel_for(
228  p, KOKKOS_CLASS_LAMBDA(const int &i) { operator()(i) = view(i); });
229  }
230  template <class View> void setRankTwo(View &view) {
231  Kokkos::Array a = MeshFieldUtil::to_kokkos_array<Field::Rank>({0, 0});
232  Kokkos::Array b =
233  MeshFieldUtil::to_kokkos_array<Field::Rank>({size(0), size(1)});
234  Kokkos::MDRangePolicy<Kokkos::Rank<Field::Rank>, ExecutionSpace> p(a, b);
235  Kokkos::parallel_for(
236  p, KOKKOS_CLASS_LAMBDA(const int &i, const int &j) {
237  operator()(i, j) = view(i, j);
238  });
239  }
240  template <class View> void setRankThree(View &view) {
241  Kokkos::Array a = MeshFieldUtil::to_kokkos_array<Field::Rank>({0, 0, 0});
242  Kokkos::Array b = MeshFieldUtil::to_kokkos_array<Field::Rank>(
243  {size(0), size(1), size(2)});
244  Kokkos::MDRangePolicy<Kokkos::Rank<Field::Rank>, ExecutionSpace> p(a, b);
245  Kokkos::parallel_for(
246  p, KOKKOS_CLASS_LAMBDA(const int &i, const int &j, const int &k) {
247  operator()(i, j, k) = view(i, j, k);
248  });
249  }
250  template <class View> void setRankFour(View &view) {
251  Kokkos::Array a = MeshFieldUtil::to_kokkos_array<Field::Rank>({0, 0, 0, 0});
252  Kokkos::Array b = MeshFieldUtil::to_kokkos_array<Field::Rank>(
253  {size(0), size(1), size(2), size(3)});
254  Kokkos::MDRangePolicy<Kokkos::Rank<Field::Rank>, ExecutionSpace> p(a, b);
255  Kokkos::parallel_for(
256  p, KOKKOS_CLASS_LAMBDA(const int &i, const int &j, const int &k,
257  const int &l) {
258  operator()(i, j, k, l) = view(i, j, k, l);
259  });
260  }
261  template <class View> void setRankFive(View &view) {
262  Kokkos::Array a =
263  MeshFieldUtil::to_kokkos_array<Field::Rank>({0, 0, 0, 0, 0});
264  Kokkos::Array b = MeshFieldUtil::to_kokkos_array<Field::Rank>(
265  {size(0), size(1), size(2), size(3), size(4)});
266  Kokkos::MDRangePolicy<Kokkos::Rank<Field::Rank>, ExecutionSpace> p(a, b);
267  Kokkos::parallel_for(
268  p, KOKKOS_CLASS_LAMBDA(const int &i, const int &j, const int &k,
269  const int &l, const int &m) {
270  operator()(i, j, k, l, m) = view(i, j, k, l, m);
271  });
272  }
278  template <class View> void set(View &view) {
279  constexpr std::size_t view_rank = View::rank;
280  constexpr std::size_t field_rank = Slice::RANK;
281  static_assert(field_rank <= Slice::MAX_RANK);
282  static_assert(view_rank == field_rank);
283  checkExtents(*this, view, __func__);
284  if constexpr (field_rank == 1) {
285  setRankOne(view);
286  } else if constexpr (field_rank == 2) {
287  setRankTwo(view);
288  } else if constexpr (field_rank == 3) {
289  setRankThree(view);
290  } else if constexpr (field_rank == 4) {
291  setRankFour(view);
292  } else if constexpr (field_rank == 5) {
293  setRankFive(view);
294  } else {
295  fail("Field::set error: field rank is %d, it must be [1:5]\n",
296  field_rank);
297  }
298  }
299 };
300 
310 template <class Controller, std::size_t index>
311 auto makeField(Controller controller) {
312  auto slice = controller.template makeSlice<index>();
313  return Field(std::move(slice));
314 }
315 
316 } // namespace MeshField
317 
318 #endif
Provides access to individual entries of a single Field provided by MeshField::makeField and helper f...
void set(View &view)
KOKKOS_INLINE_FUNCTION auto & operator()(int s) const
void deserialize(const Kokkos::View< const base_type * > &serialized)
copy the given Kokkos View into the Field
KOKKOS_INLINE_FUNCTION size_t size(int i) const
get the size/extent of the specified rank
void serialize(Kokkos::View< base_type * > &serial) const
copy the Field into a given Kokkos View
Kokkos::View< base_type * > serialize() const
copy the Field into a single rank Kokkos View