Gyselalib++
derivative_field_common.hpp
1 // SPDX-License-Identifier: MIT
2 
3 #pragma once
4 #include <array>
5 
6 #include <ddc/ddc.hpp>
7 #include <ddc/kernels/splines.hpp> // Needed for ddc::Deriv
8 
9 #include <sll/math_tools.hpp>
10 
11 #include "ddc_aliases.hpp"
12 #include "deriv_details.hpp"
13 #include "idx_range_slice.hpp"
14 
15 template <class T>
16 inline constexpr bool enable_deriv_field = false;
17 
18 template <class T>
19 inline constexpr bool enable_borrowed_deriv_field = false;
20 
21 template <class T>
22 inline constexpr bool is_deriv_field_v
23  = enable_deriv_field<std::remove_const_t<std::remove_reference_t<T>>>;
24 
25 template <class T>
26 inline constexpr bool is_borrowed_deriv_field_v
27  = (std::is_lvalue_reference_v<T>)
28  || (enable_borrowed_deriv_field<std::remove_cv_t<std::remove_reference_t<T>>>);
29 
30 template <class FieldType, class SupportType>
32 
42 template <class FieldType, class... DDims>
43 class DerivFieldCommon<FieldType, IdxRange<DDims...>>
44 {
45 public:
53  using chunk_type = FieldType;
54 
56  using deriv_tags = detail::deriv_sub_set_t<ddc::detail::TypeSeq<DDims...>>;
57 
59  using physical_deriv_grids = typename detail::strip_deriv_t<deriv_tags>;
60 
62  using physical_grids = ddc::type_seq_remove_t<ddc::detail::TypeSeq<DDims...>, deriv_tags>;
63 
65  using element_type = typename chunk_type::element_type;
66 
73  using discrete_domain_type = IdxRange<DDims...>;
76 
83  using discrete_element_type = Idx<DDims...>;
86 
87 protected:
89  using internal_mdspan_type = std::experimental::mdspan<
91  std::experimental::dextents<std::size_t, sizeof...(DDims)>,
92  std::experimental::layout_stride>;
93 
95  using internal_mdview_type = std::experimental::mdspan<
96  const element_type,
97  std::experimental::dextents<std::size_t, sizeof...(DDims)>,
98  std::experimental::layout_stride>;
99 
101  using chunk_span = typename FieldType::span_type;
102 
104  using chunk_view = typename FieldType::view_type;
105 
108  typename ddc::detail::convert_type_seq_to_discrete_domain_t<physical_grids>;
109 
111  using physical_index_type = typename physical_idx_range_type::discrete_element_type;
112 
115  typename ddc::detail::convert_type_seq_to_discrete_domain_t<deriv_tags>;
116 
120  using discrete_deriv_index_type = typename discrete_deriv_idx_range_type::discrete_element_type;
121 
125  using discrete_deriv_vector_type = typename discrete_deriv_idx_range_type::mlength_type;
126 
128  static constexpr int n_fields = 1 << ddc::type_seq_size_v<deriv_tags>;
129 
130  template <class, class, int, class>
131  friend class DerivFieldMem;
132 
133  template <class, class, class, class>
134  friend class DerivField;
135 
136 protected:
149  std::array<internal_mdspan_type, n_fields> internal_fields;
150 
153 
156 
158  to_subidx_range_collection<physical_deriv_grids> m_cross_derivative_idx_range;
159 
160 protected:
171  template <class DElem>
172  KOKKOS_FUNCTION std::pair<int, index_type> get_index(DElem elem) const
173  {
174  discrete_deriv_index_type default_derivatives = detail::no_derivative_element<deriv_tags>();
175  discrete_deriv_index_type deriv_index(detail::select_default(elem, default_derivatives));
176  physical_index_type physical_index(elem);
177  index_type index(physical_index, deriv_index);
178  return std::pair<int, index_type>(get_array_index(deriv_index), index);
179  }
180 
196  template <class... Tag>
197  KOKKOS_FUNCTION int get_array_index(Idx<Tag...> idx) const
198  {
199  static_assert(std::is_same_v<Idx<Tag...>, discrete_deriv_index_type>);
200  return (0 + ...
201  + (int(ddc::select<Tag>(idx) != Idx<Tag>(0))
202  << ddc::type_seq_rank_v<Tag, deriv_tags>));
203  }
204 
215  template <class QueryDDim, class... ODDims>
216  KOKKOS_FUNCTION constexpr auto get_slicer_for(Idx<ODDims...> const& slice_idx, int array_idx)
217  const
218  {
219  if constexpr (!ddc::in_tags_v<QueryDDim, ddc::detail::TypeSeq<ODDims...>>) {
220  return std::experimental::full_extent;
221  } else {
222  if constexpr (ddc::in_tags_v<QueryDDim, physical_deriv_grids>) {
223  // Physical dimension along which derivatives are known
224  // If information is available about the physical index range
225  if (array_idx & (1 << ddc::type_seq_rank_v<ddc::Deriv<QueryDDim>, deriv_tags>)) {
226  // If the derivative is being requested
227  return m_cross_derivative_idx_range.get_index(
228  ddc::select<QueryDDim>(slice_idx));
229  }
230  }
231  if constexpr (ddc::in_tags_v<QueryDDim, physical_grids>) {
232  // Physical dimension along which derivatives are not known
233  return std::size_t(
234  (ddc::select<QueryDDim>(slice_idx)
235  - ddc::select<QueryDDim>(m_physical_idx_range).front()));
236  }
237  if constexpr (ddc::in_tags_v<QueryDDim, deriv_tags>) {
238  // Derivative dimension
239  if (array_idx & (1 << ddc::type_seq_rank_v<QueryDDim, deriv_tags>)) {
240  // If array contains derivatives
241  return std::size_t((ddc::select<QueryDDim>(slice_idx) - Idx<QueryDDim>(1)));
242  } else {
243  // If array doesn't contain derivatives
244  assert(ddc::select<QueryDDim>(slice_idx) == Idx<QueryDDim>(0));
245  return std::size_t(0);
246  }
247  }
248  }
249  }
250 
261  template <class QueryDDim, class... ODDims>
262  KOKKOS_FUNCTION constexpr auto get_slicer_for(
263  IdxRange<ODDims...> const& slice_idx_range,
264  int array_idx) const
265  {
266  if constexpr (!ddc::in_tags_v<QueryDDim, ddc::detail::TypeSeq<ODDims...>>) {
267  return std::experimental::full_extent;
268  } else {
269  if constexpr (ddc::in_tags_v<QueryDDim, physical_deriv_grids>) {
270  // Physical dimension along which derivatives are known
271  // If information is available about the physical index range
272  IdxRange<QueryDDim> idx_range_requested(slice_idx_range);
273  if (array_idx & (1 << ddc::type_seq_rank_v<ddc::Deriv<QueryDDim>, deriv_tags>)) {
274  // If the derivative is being requested
275  assert(m_cross_derivative_idx_range.contains(idx_range_requested));
276  return std::pair<std::size_t, std::size_t>(
277  m_cross_derivative_idx_range.get_index(idx_range_requested.front()),
278  m_cross_derivative_idx_range.get_index(idx_range_requested.back()) + 1);
279  }
280  }
281  if constexpr (ddc::in_tags_v<QueryDDim, physical_grids>) {
282  // Physical dimension along which derivatives are not known
283  return std::pair<std::size_t, std::size_t>(
284  ddc::select<QueryDDim>(slice_idx_range).front()
285  - ddc::select<QueryDDim>(m_physical_idx_range).front(),
286  ddc::select<QueryDDim>(slice_idx_range).back() + 1
287  - ddc::select<QueryDDim>(m_physical_idx_range).front());
288  }
289  if constexpr (ddc::in_tags_v<QueryDDim, deriv_tags>) {
290  // Derivative dimension
291  if (array_idx & (1 << ddc::type_seq_rank_v<QueryDDim, deriv_tags>)) {
292  // If array contains derivatives
293  return std::pair<std::size_t, std::size_t>(
294  ddc::select<QueryDDim>(slice_idx_range).front() - Idx<QueryDDim>(1),
295  ddc::select<QueryDDim>(slice_idx_range).back() + 1 - Idx<QueryDDim>(1));
296  } else {
297  // If array doesn't contain derivatives
298  assert(ddc::select<QueryDDim>(slice_idx_range).front() == Idx<QueryDDim>(0));
299  assert(ddc::select<QueryDDim>(slice_idx_range).back()
300  == ddc::select<QueryDDim>(slice_idx_range).front());
301  return std::pair<std::size_t, std::size_t>(0, 1);
302  }
303  }
304  }
305  }
306 
318  template <class... ODims>
319  KOKKOS_FUNCTION auto get_internal_field(IdxRange<ODims...> idx_range) const
320  {
321  // Get the types related to the provided information
322  using provided_tags = ddc::detail::TypeSeq<ODims...>;
323  using provided_deriv_tags = detail::deriv_sub_set_t<provided_tags>;
324 
325  // Get the types related to the implicit information
326  using remaining_deriv_tags = ddc::type_seq_remove_t<deriv_tags, provided_deriv_tags>;
327  using remaining_deriv_idx_range_type =
328  typename ddc::detail::convert_type_seq_to_discrete_domain_t<remaining_deriv_tags>;
329 
330  // Find the index range of the derivatives (either provided or an index range containing only the 0-th derivative)
331  remaining_deriv_idx_range_type no_deriv_idx_range = detail::get_idx_range_from_element(
332  detail::no_derivative_element<remaining_deriv_tags>());
333  discrete_deriv_idx_range_type deriv_idx_range(idx_range, no_deriv_idx_range);
334 
335  // Find the physical index range of the field
336  physical_idx_range_type local_physical_idx_range(
337  detail::select_default(idx_range, m_physical_idx_range));
338 
339  // Find the discrete index range of the field
340  index_range_type full_idx_range(local_physical_idx_range, deriv_idx_range);
341 
342  // Find the index of the internal field
343  int const array_idx = get_array_index(deriv_idx_range.front());
344 
345  // Get the relevant internal field
346  internal_mdspan_type internal_view = internal_fields[array_idx];
347  // Slice the relevant section of the internal field
348  auto subview = std::experimental::
349  submdspan(internal_view, get_slicer_for<DDims>(full_idx_range, array_idx)...);
350  // Create a Field with the expected index range
351  Field<element_type,
353  typename chunk_type::memory_space,
354  typename decltype(subview)::layout_type>
355  local_field(subview, full_idx_range);
356 
357  // If necessary, slice off the derivative dimensions deduced implicitly
358  if constexpr (ddc::type_seq_size_v<remaining_deriv_tags> == 0) {
359  return local_field;
360  } else {
361  return local_field[no_deriv_idx_range.front()];
362  }
363  }
364 
376  template <class... ODims>
377  KOKKOS_FUNCTION auto get_internal_field(Idx<ODims...> elem) const
378  {
379  // Get the types related to the provided information
380  using provided_tags = ddc::detail::TypeSeq<ODims...>;
381  using provided_deriv_tags = detail::deriv_sub_set_t<provided_tags>;
382  using provided_physical_tags = ddc::type_seq_remove_t<provided_tags, provided_deriv_tags>;
383  using provided_deriv_idx_range_type
384  = ddc::detail::convert_type_seq_to_discrete_domain_t<provided_deriv_tags>;
385  using provided_deriv_index_type =
386  typename provided_deriv_idx_range_type::discrete_element_type;
387 
388  // Get the types related to the implicit information
389  using remaining_deriv_tags = ddc::type_seq_remove_t<deriv_tags, provided_deriv_tags>;
390  using remaining_deriv_idx_range_type =
391  typename ddc::detail::convert_type_seq_to_discrete_domain_t<remaining_deriv_tags>;
392  using remaining_deriv_index_type =
393  typename remaining_deriv_idx_range_type::discrete_element_type;
394 
395  // Get the types related to the final field type
396  using sliced_tags = ddc::type_seq_merge_t<provided_physical_tags, deriv_tags>;
397  using sliced_idx_range_type =
398  typename ddc::detail::convert_type_seq_to_discrete_domain_t<sliced_tags>;
399  using sliced_index_type = typename sliced_idx_range_type::discrete_element_type;
400  using final_tags = ddc::type_seq_remove_t<ddc::detail::TypeSeq<DDims...>, sliced_tags>;
401  using final_idx_range_type =
402  typename ddc::detail::convert_type_seq_to_discrete_domain_t<final_tags>;
403 
404  // Get the index of the relevant derivatives
405  provided_deriv_index_type requested_derivs(elem);
406  remaining_deriv_index_type no_deriv_elements(
407  detail::no_derivative_element<remaining_deriv_tags>());
408  discrete_deriv_index_type deriv_index(requested_derivs, no_deriv_elements);
409 
410  // Get the element which will slice the mdspan
411  sliced_index_type slice_idx(elem, no_deriv_elements);
412 
413  // Find the index of the internal field
414  int const array_idx = get_array_index(deriv_index);
415 
416  // Get the final index range
417  final_idx_range_type final_idx_range(m_physical_idx_range);
418 
419  // Get the relevant internal field
420  internal_mdspan_type internal_view = internal_fields[array_idx];
421  // Slice the relevant section of the internal field
422  auto subview = std::experimental::
423  submdspan(internal_view, get_slicer_for<DDims>(slice_idx, array_idx)...);
424  // Create a Field with the expected index range
425  Field<element_type,
426  final_idx_range_type,
427  typename chunk_type::memory_space,
428  typename decltype(subview)::layout_type>
429  local_field(subview, final_idx_range);
430 
431  return local_field;
432  }
433 
442  KOKKOS_FUNCTION DerivFieldCommon(
443  physical_idx_range_type physical_idx_range,
444  discrete_deriv_idx_range_type deriv_idx_range,
445  to_subidx_range_collection<physical_deriv_grids> cross_derivative_idx_range)
446  : m_physical_idx_range(physical_idx_range)
447  , m_deriv_idx_range(deriv_idx_range)
448  , m_cross_derivative_idx_range(cross_derivative_idx_range)
449  {
450  }
451 
452 public:
453  KOKKOS_DEFAULTED_FUNCTION ~DerivFieldCommon() = default;
454 
464  template <class... QueryDDims>
465  constexpr auto operator[](Idx<QueryDDims...> const& slice_spec) const
466  {
467  return get_internal_field(slice_spec).span_cview();
468  }
469 
479  template <class... QueryDDims>
480  constexpr auto operator[](Idx<QueryDDims...> const& slice_spec)
481  {
482  return get_internal_field(slice_spec);
483  }
484 
496  template <class... QueryDDims>
497  KOKKOS_FUNCTION constexpr auto operator[](IdxRange<QueryDDims...> const& oidx_range)
498  {
499  return get_internal_field(oidx_range);
500  }
501 
513  template <class... QueryDDims>
514  KOKKOS_FUNCTION constexpr auto operator[](IdxRange<QueryDDims...> const& oidx_range) const
515  {
516  return get_internal_field(oidx_range).span_cview();
517  }
518 
530  template <class... ODims>
531  auto get_mdspan(IdxRange<ODims...> provided_deriv_idx_range)
532  {
533  static_assert(((ddc::in_tags_v<ODims, deriv_tags>)&&...));
534  using provided_deriv_tags = ddc::detail::TypeSeq<ODims...>;
535  using remaining_deriv_tags = ddc::type_seq_remove_t<deriv_tags, provided_deriv_tags>;
536  using remaining_deriv_idx_range_type =
537  typename ddc::detail::convert_type_seq_to_discrete_domain_t<remaining_deriv_tags>;
538  using remaining_deriv_index_type =
539  typename remaining_deriv_idx_range_type::discrete_element_type;
540 
541  discrete_deriv_index_type default_derivatives = detail::no_derivative_element<deriv_tags>();
542 
543  remaining_deriv_index_type deriv_elements(default_derivatives);
544  discrete_deriv_index_type deriv_index(
545  detail::select_default(provided_deriv_idx_range.front(), default_derivatives));
546 
547  int const array_idx = get_array_index(deriv_index);
548 
549  internal_mdspan_type internal_view = internal_fields[array_idx];
550  auto subview_all_dims = std::experimental::submdspan(
551  internal_view,
552  get_slicer_for<DDims>(provided_deriv_idx_range, array_idx)...);
553  auto subview = std::experimental::
554  submdspan(subview_all_dims, get_slicer_for<DDims>(deriv_elements, array_idx)...);
555  return subview;
556  }
557 
563  auto get_mdspan()
564  {
565  IdxRange<> no_specified_dims;
566  return get_mdspan(no_specified_dims);
567  }
568 
577  {
578  IdxRange<> no_specified_dims;
579  return get_internal_field(no_specified_dims);
580  }
581 
589  auto get_values_field() const
590  {
591  IdxRange<> no_specified_dims;
592  return get_internal_field(no_specified_dims).span_cview();
593  }
594 };
ddc::type_seq_remove_t< ddc::detail::TypeSeq< DDims... >, deriv_tags > physical_grids
A type sequence containing all the physical dimensions on which the fields are defined.
Definition: derivative_field_common.hpp:62
constexpr KOKKOS_FUNCTION auto operator[](IdxRange< QueryDDims... > const &oidx_range)
Get a Field describing a subset of the data.
Definition: derivative_field_common.hpp:497
std::array< internal_mdspan_type, n_fields > internal_fields
The internal fields describing the values and derivatives.
Definition: derivative_field_common.hpp:149
typename FieldType::view_type chunk_view
The type of a constant view of this field. This is a DDC keyword used to make this class interchangea...
Definition: derivative_field_common.hpp:104
auto get_mdspan()
Get the mdspan holding the values of the function from the internal array internal_fields.
Definition: derivative_field_common.hpp:563
IdxRange< DDims... > discrete_domain_type
The IdxRange on which the fields in this object are defined.
Definition: derivative_field_common.hpp:73
detail::deriv_sub_set_t< ddc::detail::TypeSeq< DDims... > > deriv_tags
A type sequence containing all derivatives present in this object.
Definition: derivative_field_common.hpp:56
typename ddc::detail::convert_type_seq_to_discrete_domain_t< deriv_tags > discrete_deriv_idx_range_type
The IdxRange which describes the derivatives present on each field.
Definition: derivative_field_common.hpp:115
to_subidx_range_collection< physical_deriv_grids > m_cross_derivative_idx_range
The physical index ranges on which the derivatives are defined.
Definition: derivative_field_common.hpp:158
std::experimental::mdspan< const element_type, std::experimental::dextents< std::size_t, sizeof...(DDims)>, std::experimental::layout_stride > internal_mdview_type
The type of a constant view on the memory block stored in the array internal_fields.
Definition: derivative_field_common.hpp:98
KOKKOS_FUNCTION int get_array_index(Idx< Tag... > idx) const
An internal function which provides the index of a field inside the internal_fields array.
Definition: derivative_field_common.hpp:197
discrete_element_type index_type
The Idx which can be used to index this object.
Definition: derivative_field_common.hpp:85
discrete_deriv_idx_range_type m_deriv_idx_range
The index range of available derivatives.
Definition: derivative_field_common.hpp:155
typename discrete_deriv_idx_range_type::mlength_type discrete_deriv_vector_type
The Idx which describes the order of the derivatives in each dimension.
Definition: derivative_field_common.hpp:125
typename detail::strip_deriv_t< deriv_tags > physical_deriv_grids
A type sequence containing all physical dimensions for which derivatives are present in this object.
Definition: derivative_field_common.hpp:59
physical_idx_range_type m_physical_idx_range
The physical index range on which the values are defined.
Definition: derivative_field_common.hpp:152
Idx< DDims... > discrete_element_type
The Idx which can be used to index this object.
Definition: derivative_field_common.hpp:83
std::experimental::mdspan< element_type, std::experimental::dextents< std::size_t, sizeof...(DDims)>, std::experimental::layout_stride > internal_mdspan_type
The type of the memory block stored in the array internal_fields.
Definition: derivative_field_common.hpp:92
FieldType chunk_type
The type of the field stored in the array.
Definition: derivative_field_common.hpp:53
typename chunk_type::element_type element_type
The type of the elements in the fields.
Definition: derivative_field_common.hpp:65
KOKKOS_FUNCTION std::pair< int, index_type > get_index(DElem elem) const
An internal function which provides the index of an element inside the internal_fields.
Definition: derivative_field_common.hpp:172
constexpr KOKKOS_FUNCTION auto get_slicer_for(Idx< ODDims... > const &slice_idx, int array_idx) const
Get an object which can be used to slice an mdspan.
Definition: derivative_field_common.hpp:216
typename FieldType::span_type chunk_span
The type of a modifiable span of this field. This is a DDC keyword used to make this class interchang...
Definition: derivative_field_common.hpp:101
typename physical_idx_range_type::discrete_element_type physical_index_type
The Idx which describes the physical position where values are defined.
Definition: derivative_field_common.hpp:111
constexpr KOKKOS_FUNCTION auto operator[](IdxRange< QueryDDims... > const &oidx_range) const
Get a ConstField describing a subset of the data.
Definition: derivative_field_common.hpp:514
discrete_domain_type index_range_type
The IdxRange on which the fields in this object are defined.
Definition: derivative_field_common.hpp:75
constexpr KOKKOS_FUNCTION auto get_slicer_for(IdxRange< ODDims... > const &slice_idx_range, int array_idx) const
Get an object which can be used to slice an mdspan.
Definition: derivative_field_common.hpp:262
typename discrete_deriv_idx_range_type::discrete_element_type discrete_deriv_index_type
The Idx which describes the order of the derivatives in each dimension.
Definition: derivative_field_common.hpp:120
KOKKOS_FUNCTION auto get_internal_field(IdxRange< ODims... > idx_range) const
Get a Field from a subset of one of the mdspans in internal_fields.
Definition: derivative_field_common.hpp:319
KOKKOS_FUNCTION auto get_internal_field(Idx< ODims... > elem) const
Get a Field from a subset of one of the mdspans in internal_fields.
Definition: derivative_field_common.hpp:377
typename ddc::detail::convert_type_seq_to_discrete_domain_t< physical_grids > physical_idx_range_type
The index range for the field excluding derivatives.
Definition: derivative_field_common.hpp:108
auto get_values_field() const
Get the Field which holds the values of the function.
Definition: derivative_field_common.hpp:589
KOKKOS_FUNCTION DerivFieldCommon(physical_idx_range_type physical_idx_range, discrete_deriv_idx_range_type deriv_idx_range, to_subidx_range_collection< physical_deriv_grids > cross_derivative_idx_range)
Protected constructor to be used by subclasses to initialise index ranges.
Definition: derivative_field_common.hpp:442
constexpr auto operator[](Idx< QueryDDims... > const &slice_spec) const
Get a ConstField describing a subset of the data.
Definition: derivative_field_common.hpp:465
auto get_values_field()
Get the Field which holds the values of the function.
Definition: derivative_field_common.hpp:576
constexpr auto operator[](Idx< QueryDDims... > const &slice_spec)
Get a Field describing a subset of the data.
Definition: derivative_field_common.hpp:480
auto get_mdspan(IdxRange< ODims... > provided_deriv_idx_range)
Get one of the mdspans from the internal array internal_fields.
Definition: derivative_field_common.hpp:531
Definition: derivative_field_common.hpp:31
See DerivFieldMemImplementation.
Definition: derivative_field.hpp:10
See DerivFieldImplementation.
Definition: derivative_field.hpp:20