InterfaceHelpers.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <cstddef>
7 
8 #include "DirectionMap.hpp"
9 #include "Domain/Direction.hpp"
10 #include "Domain/Tags.hpp"
11 #include "Utilities/TMPL.hpp"
12 
13 namespace InterfaceHelpers_detail {
14 
15 template <typename T, typename = cpp17::void_t<>>
16 struct get_volume_tags_impl {
17  using type = tmpl::list<>;
18 };
19 template <typename T>
20 struct get_volume_tags_impl<T, cpp17::void_t<typename T::volume_tags>> {
21  using type = typename T::volume_tags;
22 };
23 
24 } // namespace InterfaceHelpers_detail
25 
26 /// Retrieve `T::volume_tags`, defaulting to an empty list
27 template <typename T>
28 using get_volume_tags =
29  tmpl::type_from<InterfaceHelpers_detail::get_volume_tags_impl<T>>;
30 
31 namespace InterfaceHelpers_detail {
32 
33 template <typename Tag, typename DirectionsTag, typename VolumeTags>
34 struct make_interface_tag_impl {
35  using type = tmpl::conditional_t<tmpl::list_contains_v<VolumeTags, Tag>, Tag,
37 };
38 
39 // Retrieve the `argument_tags` from the `InterfaceInvokable` and wrap them in
40 // `::Tags::Interface` if they are not listed in
41 // `InterfaceInvokable::volume_tags`.
42 template <typename InterfaceInvokable, typename DirectionsTag>
43 using get_interface_argument_tags = tmpl::transform<
44  typename InterfaceInvokable::argument_tags,
45  make_interface_tag_impl<tmpl::_1, tmpl::pin<DirectionsTag>,
46  tmpl::pin<get_volume_tags<InterfaceInvokable>>>>;
47 
48 /// Pull the direction's entry from interface arguments, passing volume
49 /// arguments through unchanged.
50 template <bool IsVolumeTag>
51 struct unmap_interface_args;
52 
53 template <>
54 struct unmap_interface_args<true> {
55  template <typename T>
56  using f = T;
57 
58  template <size_t VolumeDim, typename T>
59  static constexpr const T& apply(const ::Direction<VolumeDim>& /*direction*/,
60  const T& arg) noexcept {
61  return arg;
62  }
63 };
64 
65 template <>
66 struct unmap_interface_args<false> {
67  template <typename T>
68  using f = typename T::mapped_type;
69 
70  template <size_t VolumeDim, typename T>
71  static constexpr decltype(auto) apply(const ::Direction<VolumeDim>& direction,
72  const T& arg) noexcept {
73  return arg.at(direction);
74  }
75 };
76 
77 template <typename DirectionsTag, typename VolumeTags,
78  typename InterfaceInvokable, typename DbTagsList,
79  typename... ArgumentTags, typename... ExtraArgs>
80 SPECTRE_ALWAYS_INLINE constexpr auto interface_apply_impl(
81  InterfaceInvokable&& interface_invokable,
82  const db::DataBox<DbTagsList>& box, tmpl::list<ArgumentTags...> /*meta*/,
83  ExtraArgs&&... extra_args) noexcept {
84  using interface_return_type = std::decay_t<decltype(interface_invokable(
86  std::declval<ExtraArgs&&>()...))>;
87  constexpr size_t volume_dim = DirectionsTag::volume_dim;
89  for (const auto& direction : get<DirectionsTag>(box)) {
90  auto interface_value = interface_invokable(
91  unmap_interface_args<tmpl::list_contains_v<VolumeTags, ArgumentTags>>::
92  apply(direction,
93  get<tmpl::type_from<make_interface_tag_impl<
94  ArgumentTags, DirectionsTag, VolumeTags>>>(box))...,
95  extra_args...);
96  result.insert({direction, std::move(interface_value)});
97  }
98  return result;
99 }
100 
101 } // namespace InterfaceHelpers_detail
102 
103 /*!
104  * \brief Apply the `interface_invokable` to the `box` on all interfaces given
105  * by the `DirectionsTag`.
106  *
107  * \details The `interface_invokable` is expected to be invokable with the types
108  * held by the `ArgumentTags`, followed by the `extra_args`. The `ArgumentTags`
109  * will be prefixed as `::Tags::Interface<DirectionsTag, ArgumentTag>` and thus
110  * taken from the interface, except for those specified in the `VolumeTags`.
111  *
112  * This function returns a `DirectionMap` that holds the value returned by
113  * the `interface_invokable` in every direction of the `DirectionsTag`.
114  *
115  * Here is an example how to use this function:
116  *
117  * \snippet Test_InterfaceHelpers.cpp interface_apply_example
118  */
119 template <typename DirectionsTag, typename ArgumentTags, typename VolumeTags,
120  typename InterfaceInvokable, typename DbTagsList,
121  typename... ExtraArgs>
122 SPECTRE_ALWAYS_INLINE constexpr auto interface_apply(
123  InterfaceInvokable&& interface_invokable,
124  const db::DataBox<DbTagsList>& box, ExtraArgs&&... extra_args) noexcept {
125  return InterfaceHelpers_detail::interface_apply_impl<DirectionsTag,
126  VolumeTags>(
127  std::forward<InterfaceInvokable>(interface_invokable), box,
128  ArgumentTags{}, std::forward<ExtraArgs>(extra_args)...);
129 }
Defines class template Direction.
void void_t
Given a set of types, returns void
Definition: TypeTraits.hpp:214
An optimized map with Direction keys.
Definition: DirectionMap.hpp:15
Definition: InterfaceHelpers.hpp:13
A particular Side along a particular coordinate Axis.
Definition: Direction.hpp:23
#define SPECTRE_ALWAYS_INLINE
Always inline a function. Only use this if you benchmarked the code.
Definition: ForceInline.hpp:16
Definition: InterpolationTargetWedgeSectionTorus.hpp:24
constexpr auto apply(F &&f, const DataBox< BoxTags > &box, Args &&... args) noexcept
Apply the invokable f with argument Tags TagsList from DataBox box
Definition: DataBox.hpp:1623
Wraps the template metaprogramming library used (brigand)
Defines tags related to domain quantities.
tmpl::flatten< tmpl::list< Tags... > > ArgumentTags
List of Tags to get from the DataBox to be used as arguments.
Definition: DataBox.hpp:1236
C++ STL code present in C++17.
Definition: Array.hpp:16
Tag which is either a SimpleTag for quantities on an interface, base tag to a compute item which acts...
Definition: Tags.hpp:263