InterfaceComputeTags.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <cstddef>
7 
10 #include "Domain/Direction.hpp"
11 #include "Domain/ElementMap.hpp"
12 #include "Domain/IndexToSliceAt.hpp"
13 #include "Domain/InterfaceHelpers.hpp"
15 #include "Domain/Mesh.hpp"
16 #include "Domain/Tags.hpp"
17 #include "Utilities/Gsl.hpp"
18 #include "Utilities/TMPL.hpp"
19 
20 namespace Tags {
21 
22 namespace Interface_detail {
23 
24 template <typename DirectionsTag, typename BaseComputeItem,
25  typename ArgumentTags>
26 struct evaluate_compute_item;
27 
28 template <typename DirectionsTag, typename BaseComputeItem,
29  typename... ArgumentTags>
30 struct evaluate_compute_item<DirectionsTag, BaseComputeItem,
31  tmpl::list<ArgumentTags...>> {
32  using volume_tags = get_volume_tags<BaseComputeItem>;
33  static_assert(
34  tmpl::size<tmpl::list_difference<
35  volume_tags, typename BaseComputeItem::argument_tags>>::value ==
36  0,
37  "volume_tags contains tags not in argument_tags");
38 
39  private:
40  // Order matters so we mix public/private
41  template <class ComputeItem, bool = db::has_return_type_member_v<ComputeItem>>
42  struct ComputeItemType {
43  using type = std::decay_t<decltype(BaseComputeItem::function(
44  std::declval<typename InterfaceHelpers_detail::unmap_interface_args<
45  tmpl::list_contains_v<volume_tags, ArgumentTags>>::
46  template f<db::const_item_type<ArgumentTags>>>()...))>;
47  };
48 
49  template <class ComputeItem>
50  struct ComputeItemType<ComputeItem, true> {
51  using type = typename BaseComputeItem::return_type;
52  };
53 
54  public:
55  using return_type = std::unordered_map<
57  typename ComputeItemType<BaseComputeItem>::type>;
58 
59  static constexpr void apply(
60  const gsl::not_null<return_type*> result,
61  const db::const_item_type<DirectionsTag>& directions,
62  const db::const_item_type<ArgumentTags>&... args) noexcept {
63  apply_helper(
65  db::has_return_type_member_v<BaseComputeItem>>{},
66  result, directions, args...);
67  }
68 
69  private:
70  static constexpr void apply_helper(
71  std::false_type /*has_return_type_member*/,
72  const gsl::not_null<return_type*> result,
73  const db::const_item_type<DirectionsTag>& directions,
74  const db::const_item_type<ArgumentTags>&... args) noexcept {
75  for (const auto& direction : directions) {
76  (*result)[direction] = BaseComputeItem::function(
77  InterfaceHelpers_detail::unmap_interface_args<tmpl::list_contains_v<
78  volume_tags, ArgumentTags>>::apply(direction, args)...);
79  }
80  }
81 
82  static constexpr void apply_helper(
83  std::true_type /*has_return_type_member*/,
84  const gsl::not_null<return_type*> result,
85  const db::const_item_type<DirectionsTag>& directions,
86  const db::const_item_type<ArgumentTags>&... args) noexcept {
87  for (const auto& direction : directions) {
88  BaseComputeItem::function(
89  make_not_null(&(*result)[direction]),
90  InterfaceHelpers_detail::unmap_interface_args<tmpl::list_contains_v<
91  volume_tags, ArgumentTags>>::apply(direction, args)...);
92  }
93  }
94 };
95 
96 } // namespace Interface_detail
97 
98 /// \ingroup DataBoxTagsGroup
99 /// \ingroup ComputationalDomainGroup
100 /// \brief Derived tag for representing a compute item which acts on Tags on an
101 /// interface. Can be retrieved using Tags::Interface<DirectionsTag, Tag>
102 ///
103 /// The contained object will be a map from ::Direction to the item type of
104 /// `Tag`, with the set of directions being those produced by `DirectionsTag`.
105 /// `Tag::function` will be applied separately to the data on each interface. If
106 /// some of the compute item's inputs should be taken from the volume even when
107 /// applied on a slice, it may indicate them using `volume_tags`.
108 ///
109 /// If using the base tag mechanism for an interface tag is desired,
110 /// then `Tag` can have a `base` type alias pointing to its base
111 /// class. (This requirement is due to the lack of a way to determine
112 /// a type's base classes in C++.)
113 ///
114 /// \tparam DirectionsTag the item of Directions
115 /// \tparam Tag the tag labeling the item
116 template <typename DirectionsTag, typename Tag>
117 struct InterfaceCompute : Interface<DirectionsTag, Tag>,
119  virtual db::PrefixTag {
120  static_assert(db::is_compute_item_v<Tag>,
121  "Cannot use a non compute item as an interface compute item.");
122  // Defining name here prevents an ambiguous function call when using base
123  // tags; Both Interface<Dirs, Tag> and Interface<Dirs, Tag::base> will have a
124  // name function and so cannot be disambiguated.
125  static std::string name() noexcept {
126  return "Interface<" + DirectionsTag::name() + ", " + Tag::name() + ">";
127  };
128  using tag = Tag;
129  using forwarded_argument_tags =
130  InterfaceHelpers_detail::get_interface_argument_tags<Tag, DirectionsTag>;
131  using argument_tags =
132  tmpl::push_front<forwarded_argument_tags, DirectionsTag>;
133 
134  using return_type = typename Interface_detail::evaluate_compute_item<
135  DirectionsTag, Tag, forwarded_argument_tags>::return_type;
136  static constexpr auto function =
137  Interface_detail::evaluate_compute_item<DirectionsTag, Tag,
138  forwarded_argument_tags>::apply;
139 };
140 
141 /// \ingroup DataBoxTagsGroup
142 /// \ingroup ComputationalDomainGroup
143 /// \brief Derived tag for representing a compute item which slices a Tag
144 /// containing a `Tensor` or a `Variables` from the volume to an interface.
145 /// Retrievable from the DataBox using `Tags::Interface<DirectionsTag, Tag>`
146 ///
147 /// The contained object will be a map from ::Direction to the item
148 /// type of `Tag`, with the set of directions being those produced by
149 /// `DirectionsTag`.
150 ///
151 /// \requires `Tag` correspond to a `Tensor` or a `Variables`
152 ///
153 /// \tparam DirectionsTag the item of Directions
154 /// \tparam Tag the tag labeling the item
155 template <typename DirectionsTag, typename Tag>
156 struct Slice : Interface<DirectionsTag, Tag>, db::ComputeTag {
157  static constexpr size_t volume_dim =
159 
160  using return_type =
162 
163  static constexpr void function(
164  const gsl::not_null<return_type*> sliced_vars,
165  const ::Mesh<volume_dim>& mesh,
167  const db::const_item_type<Tag>& variables) noexcept {
168  for (const auto& direction : directions) {
169  data_on_slice(make_not_null(&((*sliced_vars)[direction])), variables,
170  mesh.extents(), direction.dimension(),
171  index_to_slice_at(mesh.extents(), direction));
172  }
173  }
174  static std::string name() { return "Interface<" + Tag::name() + ">"; };
175  using argument_tags = tmpl::list<Mesh<volume_dim>, DirectionsTag, Tag>;
176  using volume_tags = tmpl::list<Mesh<volume_dim>, Tag>;
177 };
178 
179 /// \cond
180 template <typename DirectionsTag, size_t VolumeDim>
181 struct InterfaceCompute<DirectionsTag, Direction<VolumeDim>>
182  : db::PrefixTag,
184  Tags::Interface<DirectionsTag, Direction<VolumeDim>> {
185  static std::string name() noexcept { return "Interface"; }
186  using tag = Direction<VolumeDim>;
187  static constexpr auto function(
188  const std::unordered_set<::Direction<VolumeDim>>& directions) noexcept {
190  for (const auto& d : directions) {
191  result.emplace(d, d);
192  }
193  return result;
194  }
195  using argument_tags = tmpl::list<DirectionsTag>;
196 };
197 /// \endcond
198 
199 /// \ingroup DataBoxTagsGroup
200 /// \ingroup ComputationalDomainGroup
201 /// Computes the `VolumeDim-1` dimensional mesh on an interface from the volume
202 /// mesh. `Tags::InterfaceCompute<Dirs, InterfaceMesh<VolumeDim>>` is
203 /// retrievable as Tags::Interface<Dirs, Mesh<VolumeDim>>` from the DataBox.
204 template <size_t VolumeDim>
205 struct InterfaceMesh : db::ComputeTag, Tags::Mesh<VolumeDim - 1> {
206  static constexpr auto function(
207  const ::Direction<VolumeDim>& direction,
208  const ::Mesh<VolumeDim>& volume_mesh) noexcept {
209  return volume_mesh.slice_away(direction.dimension());
210  }
211  using base = Tags::Mesh<VolumeDim - 1>;
212  using argument_tags = tmpl::list<Direction<VolumeDim>, Mesh<VolumeDim>>;
213  using volume_tags = tmpl::list<Mesh<VolumeDim>>;
214 };
215 
216 /// \ingroup DataBoxTagsGroup
217 /// \ingroup ComputationDomainGroup
218 /// Computes the coordinates in the frame `Frame` on the faces defined by
219 /// `Direction`. Intended to be prefixed by a `Tags::InterfaceCompute` to
220 /// define the directions on which to compute the coordinates.
221 template <size_t VolumeDim, typename Frame = ::Frame::Inertial>
223  Tags::Coordinates<VolumeDim, Frame> {
224  static constexpr auto function(
225  const ::Direction<VolumeDim>& direction,
226  const ::Mesh<VolumeDim - 1>& interface_mesh,
227  const ::ElementMap<VolumeDim, Frame>& map) noexcept {
228  return map(interface_logical_coordinates(interface_mesh, direction));
229  }
230  static std::string name() noexcept { return "BoundaryCoordinates"; }
232  using argument_tags = tmpl::list<Direction<VolumeDim>, Mesh<VolumeDim - 1>,
234  using volume_tags = tmpl::list<ElementMap<VolumeDim, Frame>>;
235 };
236 
237 } // namespace Tags
238 
239 namespace db {
240 template <typename TagList, typename DirectionsTag, typename VariablesTag>
241 struct Subitems<
242  TagList, Tags::InterfaceCompute<DirectionsTag, VariablesTag>,
243  Requires<tt::is_a_v<Variables, const_item_type<VariablesTag, TagList>>>>
244  : detail::InterfaceSubitemsImpl<TagList, DirectionsTag, VariablesTag> {};
245 
246 template <typename TagList, typename DirectionsTag, typename VariablesTag>
247 struct Subitems<
248  TagList, Tags::Slice<DirectionsTag, VariablesTag>,
249  Requires<tt::is_a_v<Variables, const_item_type<VariablesTag, TagList>>>>
250  : detail::InterfaceSubitemsImpl<TagList, DirectionsTag, VariablesTag> {};
251 } // namespace db
Defines class template Direction.
size_t index_to_slice_at(const Index< Dim > &extents, const Direction< Dim > &direction) noexcept
Finds the index in the perpendicular dimension of an element boundary.
Definition: IndexToSliceAt.hpp:15
Derived tag for representing a compute item which acts on Tags on an interface. Can be retrieved usin...
Definition: InterfaceComputeTags.hpp:117
Definition: Digraph.hpp:11
Direction to an interface
Definition: Tags.hpp:299
Marks a DataBoxTag as being a compute item that executes a function.
Definition: DataBoxTag.hpp:154
Computes the coordinates in the frame Frame on the faces defined by Direction. Intended to be prefixe...
Definition: InterfaceComputeTags.hpp:222
Computes the VolumeDim-1 dimensional mesh on an interface from the volume mesh. Tags::InterfaceComput...
Definition: InterfaceComputeTags.hpp:205
Defines functions logical_coordinates and interface_logical_coordinates.
Struct that can be specialized to allow DataBox items to have subitems. Specializations must define: ...
Definition: DataBoxTag.hpp:731
Derived tag for representing a compute item which slices a Tag containing a Tensor or a Variables fro...
Definition: InterfaceComputeTags.hpp:156
Definition: DataBoxTag.hpp:29
Defines the class template Mesh.
The coordinates in a given frame.
Definition: Tags.hpp:139
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
Namespace for DataBox related things.
Definition: DataBox.hpp:37
Variables< tmpl::list< TagsToSlice... > > data_on_slice(const db::DataBox< TagsList > &box, const Index< VolumeDim > &element_extents, const size_t sliced_dim, const size_t fixed_index, tmpl::list< TagsToSlice... >) noexcept
Slices volume Tensors from a DataBox into a Variables
Definition: DataOnSlice.hpp:33
tnsr::I< DataVector, VolumeDim, Frame::Logical > interface_logical_coordinates(const Mesh< VolumeDim - 1 > &mesh, const Direction< VolumeDim > &direction) noexcept
Compute the logical coordinates on a face of an Element.
Definition: LogicalCoordinates.cpp:36
Wraps the template metaprogramming library used (brigand)
The computational grid of the Element in the DataBox.
Definition: Tags.hpp:119
Defines functions and classes from the GSL.
gsl::not_null< T * > make_not_null(T *ptr) noexcept
Construct a not_null from a pointer. Often this will be done as an implicit conversion, but it may be necessary to perform the conversion explicitly when type deduction is desired.
Definition: Gsl.hpp:879
Defines tags related to domain quantities.
Marks an item as being a prefix to another tag.
Definition: DataBoxTag.hpp:111
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t ...
Definition: Requires.hpp:67
tmpl::flatten< tmpl::list< Tags... > > ArgumentTags
List of Tags to get from the DataBox to be used as arguments.
Definition: DataBox.hpp:1236
Defines helper functions for use with Variables class.
Defines classes SimpleTag, PrefixTag, ComputeTag and several functions for retrieving tag info...
Tag which is either a SimpleTag for quantities on an interface, base tag to a compute item which acts...
Definition: Tags.hpp:263
The coordinate map from logical to grid coordinate.
Definition: Tags.hpp:128
Require a pointer to not be a nullptr
Definition: ConservativeFromPrimitive.hpp:12