Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <cstddef>
7 :
8 : #include "DataStructures/DataBox/SubitemTag.hpp"
9 : #include "DataStructures/DataBox/Subitems.hpp"
10 : #include "DataStructures/DataBox/Tag.hpp"
11 : #include "DataStructures/DataBox/TagName.hpp"
12 : #include "DataStructures/DataBox/TagTraits.hpp"
13 : #include "DataStructures/SliceVariables.hpp"
14 : #include "DataStructures/Tensor/Slice.hpp"
15 : #include "Domain/CoordinateMaps/Tags.hpp"
16 : #include "Domain/ElementMap.hpp"
17 : #include "Domain/InterfaceHelpers.hpp"
18 : #include "Domain/Structure/Direction.hpp"
19 : #include "Domain/Structure/IndexToSliceAt.hpp"
20 : #include "Domain/Tags.hpp"
21 : #include "NumericalAlgorithms/Spectral/LogicalCoordinates.hpp"
22 : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
23 : #include "Utilities/Gsl.hpp"
24 : #include "Utilities/TMPL.hpp"
25 : #include "Utilities/TypeTraits/IsA.hpp"
26 :
27 : /// \cond
28 : namespace Tags {
29 : struct Time;
30 : } // namespace Tags
31 : /// \endcond
32 :
33 : namespace domain {
34 : namespace Tags {
35 : struct FunctionsOfTime;
36 : } // namespace Tags
37 :
38 : namespace Tags {
39 :
40 : namespace Interface_detail {
41 :
42 : template <typename ComputeTag, typename VolumeTags, typename... ArgumentTags,
43 : size_t Dim, typename... ArgTypes>
44 : constexpr void evaluate_compute_item(
45 : const gsl::not_null<typename ComputeTag::type*> result,
46 : const ::Direction<Dim>& direction, tmpl::list<ArgumentTags...> /*meta*/,
47 : const ArgTypes&... args) {
48 : ComputeTag::function(
49 : result,
50 : InterfaceHelpers_detail::unmap_interface_args<
51 : tmpl::list_contains_v<VolumeTags, ArgumentTags>>::apply(direction,
52 : args)...);
53 : }
54 : } // namespace Interface_detail
55 :
56 : /// \ingroup DataBoxTagsGroup
57 : /// \ingroup ComputationalDomainGroup
58 : /// \brief Compute tag for representing items computed on a set of interfaces.
59 : /// Can be retrieved using `Tags::Interface<DirectionsTag, Tag>`
60 : ///
61 : /// The computed object will be a map from a ::Direction to the item type of
62 : /// `Tag` (i.e. `Tag::type`), with the set of directions being those produced by
63 : /// `DirectionsTag`. `Tag::function` will be applied separately to the data on
64 : /// each interface. If some of the compute item's inputs (i.e.
65 : /// `Tag::argument_tags`) should be taken from the volume rather than the
66 : /// interface, they should be specified in the typelist `Tag::volume_tags`.
67 : ///
68 : /// \tparam DirectionsTag the simple tag labeling the set of Directions
69 : /// \tparam Tag the compute tag to apply on each interface
70 : template <typename DirectionsTag, typename Tag>
71 1 : struct InterfaceCompute : Interface<DirectionsTag, typename Tag::base>,
72 : db::ComputeTag {
73 : static_assert(db::is_simple_tag_v<DirectionsTag>);
74 : static_assert(db::is_compute_tag_v<Tag>,
75 : "Cannot use a non compute item as an interface compute item.");
76 0 : using base = Interface<DirectionsTag, typename Tag::base>;
77 0 : static constexpr size_t volume_dim = DirectionsTag::volume_dim;
78 0 : using return_type =
79 : std::unordered_map<::Direction<volume_dim>, typename Tag::type>;
80 :
81 0 : using forwarded_argument_tags =
82 : InterfaceHelpers_detail::get_interface_argument_tags<Tag, DirectionsTag>;
83 0 : using argument_tags =
84 : tmpl::push_front<forwarded_argument_tags, DirectionsTag>;
85 :
86 0 : using volume_tags = get_volume_tags<Tag>;
87 : static_assert(
88 : tmpl::size<tmpl::list_difference<volume_tags, argument_tags>>::value == 0,
89 : "volume_tags contains tags not in argument_tags");
90 :
91 : template <typename... ArgTypes>
92 0 : static constexpr void function(
93 : const gsl::not_null<return_type*> result,
94 : const std::unordered_set<::Direction<volume_dim>>& directions,
95 : const ArgTypes&... args) {
96 : for (const auto& direction : directions) {
97 : Interface_detail::evaluate_compute_item<Tag, volume_tags>(
98 : make_not_null(&(*result)[direction]), direction,
99 : forwarded_argument_tags{}, args...);
100 : }
101 : }
102 : };
103 :
104 : /// \ingroup DataBoxTagsGroup
105 : /// \ingroup ComputationalDomainGroup
106 : /// \brief Compute tag for representing a compute item that slices data from
107 : /// the volume to a set of interfaces.
108 : ///
109 : /// The computed object will be a map from a ::Direction to the item type of
110 : /// `Tag` (i.e. `Tag::type`), with the set of directions being those produced by
111 : /// `DirectionsTag`. `Tag::type` must be a `Tensor` or a `Variables`.
112 : /// Retrievable from the DataBox using `Tags::Interface<DirectionsTag, Tag>`
113 : ///
114 : /// \requires `Tag` correspond to a `Tensor` or a `Variables`
115 : ///
116 : /// \tparam DirectionsTag the simple tag labeling the set of Directions
117 : /// \tparam Tag the simple tag for the volume data to be sliced
118 : template <typename DirectionsTag, typename Tag>
119 1 : struct Slice : Interface<DirectionsTag, Tag>, db::ComputeTag {
120 : static_assert(db::is_simple_tag_v<DirectionsTag>);
121 : static_assert(db::is_simple_tag_v<Tag>);
122 0 : using base = Interface<DirectionsTag, Tag>;
123 0 : static constexpr size_t volume_dim = DirectionsTag::volume_dim;
124 :
125 0 : using return_type =
126 : std::unordered_map<::Direction<volume_dim>, typename Tag::type>;
127 :
128 0 : static constexpr void function(
129 : const gsl::not_null<return_type*> sliced_vars,
130 : const ::Mesh<volume_dim>& mesh,
131 : const std::unordered_set<::Direction<volume_dim>>& directions,
132 : const typename Tag::type& variables) {
133 : for (const auto& direction : directions) {
134 : data_on_slice(make_not_null(&((*sliced_vars)[direction])), variables,
135 : mesh.extents(), direction.dimension(),
136 : index_to_slice_at(mesh.extents(), direction));
137 : }
138 : }
139 :
140 0 : using argument_tags = tmpl::list<Mesh<volume_dim>, DirectionsTag, Tag>;
141 0 : using volume_tags = tmpl::list<Mesh<volume_dim>, Tag>;
142 : };
143 :
144 : /// \cond
145 : template <typename DirectionsTag, size_t VolumeDim>
146 : struct InterfaceCompute<DirectionsTag, Direction<VolumeDim>>
147 : : db::ComputeTag, Interface<DirectionsTag, Direction<VolumeDim>> {
148 : static_assert(db::is_simple_tag_v<DirectionsTag>);
149 : using base = Interface<DirectionsTag, Direction<VolumeDim>>;
150 : using return_type =
151 : std::unordered_map<::Direction<VolumeDim>, ::Direction<VolumeDim>>;
152 : using argument_tags = tmpl::list<DirectionsTag>;
153 : static constexpr auto function(
154 : const gsl::not_null<
155 : std::unordered_map<::Direction<VolumeDim>, ::Direction<VolumeDim>>*>
156 : result,
157 : const std::unordered_set<::Direction<VolumeDim>>& directions) {
158 : for (const auto& d : directions) {
159 : result->insert_or_assign(d, d);
160 : }
161 : }
162 : };
163 : /// \endcond
164 :
165 : /// \ingroup DataBoxTagsGroup
166 : /// \ingroup ComputationalDomainGroup
167 : /// Computes the `VolumeDim-1` dimensional mesh on an interface from the volume
168 : /// mesh. `Tags::InterfaceCompute<Dirs, InterfaceMesh<VolumeDim>>` is
169 : /// retrievable as `Tags::Interface<Dirs, Mesh<VolumeDim>>` from the DataBox.
170 : template <size_t VolumeDim>
171 1 : struct InterfaceMesh : db::ComputeTag, Tags::Mesh<VolumeDim - 1> {
172 0 : using base = Tags::Mesh<VolumeDim - 1>;
173 0 : using return_type = typename base::type;
174 0 : using argument_tags = tmpl::list<Direction<VolumeDim>, Mesh<VolumeDim>>;
175 0 : static constexpr auto function(const gsl::not_null<return_type*> mesh,
176 : const ::Direction<VolumeDim>& direction,
177 : const ::Mesh<VolumeDim>& volume_mesh) {
178 : *mesh = volume_mesh.slice_away(direction.dimension());
179 : }
180 0 : using volume_tags = tmpl::list<Mesh<VolumeDim>>;
181 : };
182 :
183 : /// \ingroup DataBoxTagsGroup
184 : /// \ingroup ComputationalDomainGroup
185 : /// Computes the coordinates in the frame `Frame` on the faces defined by
186 : /// `Direction`. Intended to be prefixed by a `Tags::InterfaceCompute` to
187 : /// define the directions on which to compute the coordinates.
188 : template <size_t VolumeDim, bool MovingMesh = false>
189 1 : struct BoundaryCoordinates : db::ComputeTag,
190 : Tags::Coordinates<VolumeDim, Frame::Inertial> {
191 0 : using base = Tags::Coordinates<VolumeDim, Frame::Inertial>;
192 0 : using return_type = typename base::type;
193 0 : static void function(const gsl::not_null<return_type*> boundary_coords,
194 : const ::Direction<VolumeDim>& direction,
195 : const ::Mesh<VolumeDim - 1>& interface_mesh,
196 : const ::ElementMap<VolumeDim, Frame::Inertial>& map) {
197 : *boundary_coords =
198 : map(interface_logical_coordinates(interface_mesh, direction));
199 : }
200 :
201 0 : static void function(
202 : const gsl::not_null<return_type*> boundary_coords,
203 : const ::Direction<VolumeDim>& direction,
204 : const ::Mesh<VolumeDim - 1>& interface_mesh,
205 : const ::ElementMap<VolumeDim, ::Frame::Grid>& logical_to_grid_map,
206 : const domain::CoordinateMapBase<Frame::Grid, Frame::Inertial, VolumeDim>&
207 : grid_to_inertial_map,
208 : const double time,
209 : const std::unordered_map<
210 : std::string,
211 : std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
212 : functions_of_time) {
213 : *boundary_coords =
214 : grid_to_inertial_map(logical_to_grid_map(interface_logical_coordinates(
215 : interface_mesh, direction)),
216 : time, functions_of_time);
217 : }
218 :
219 0 : using argument_tags = tmpl::conditional_t<
220 : MovingMesh,
221 : tmpl::list<Direction<VolumeDim>, Mesh<VolumeDim - 1>,
222 : Tags::ElementMap<VolumeDim, Frame::Grid>,
223 : CoordinateMaps::Tags::CoordinateMap<VolumeDim, Frame::Grid,
224 : Frame::Inertial>,
225 : ::Tags::Time, domain::Tags::FunctionsOfTime>,
226 : tmpl::list<Direction<VolumeDim>, Mesh<VolumeDim - 1>,
227 : ElementMap<VolumeDim, Frame::Inertial>>>;
228 0 : using volume_tags = tmpl::conditional_t<
229 : MovingMesh,
230 : tmpl::list<Tags::ElementMap<VolumeDim, Frame::Grid>,
231 : CoordinateMaps::Tags::CoordinateMap<VolumeDim, Frame::Grid,
232 : Frame::Inertial>,
233 : ::Tags::Time, domain::Tags::FunctionsOfTime>,
234 : tmpl::list<ElementMap<VolumeDim, Frame::Inertial>>>;
235 : };
236 :
237 : } // namespace Tags
238 : } // namespace domain
239 :
240 : namespace db {
241 : template <typename DirectionsTag, typename VariablesTag>
242 0 : struct Subitems<domain::Tags::InterfaceCompute<DirectionsTag, VariablesTag>,
243 : Requires<tt::is_a_v<Variables, typename VariablesTag::type>>>
244 : : detail::InterfaceSubitemsImpl<DirectionsTag,
245 : typename VariablesTag::base> {};
246 :
247 : template <typename DirectionsTag, typename VariablesTag>
248 0 : struct Subitems<domain::Tags::Slice<DirectionsTag, VariablesTag>,
249 : Requires<tt::is_a_v<Variables, typename VariablesTag::type>>>
250 : : detail::InterfaceSubitemsImpl<DirectionsTag, VariablesTag> {};
251 : } // namespace db
252 :
253 : namespace Tags {
254 : /// \brief specialization of a subitem tag for an interface compute tag of a
255 : /// Variables
256 : ///
257 : /// This is a compute tag for an unordered map from ::Direction (with the set of
258 : /// directions being those produced by `DirectionsTag`) to a Tensor (whose
259 : /// type comes from `TensorTag`) that is contained in a Variables (labeled by
260 : /// `VariablesTag`) for a ::domain::Tags::InterfaceCompute<DirectionsTag,
261 : /// VariablesTag>>.
262 : template <typename DirectionsTag, typename TensorTag, typename VariablesTag>
263 1 : struct Subitem<::domain::Tags::Interface<DirectionsTag, TensorTag>,
264 : ::domain::Tags::InterfaceCompute<DirectionsTag, VariablesTag>>
265 : : db::ComputeTag, ::domain::Tags::Interface<DirectionsTag, TensorTag> {
266 0 : using base = ::domain::Tags::Interface<DirectionsTag, TensorTag>;
267 0 : using return_type = typename base::type;
268 0 : using parent_tag =
269 : ::domain::Tags::InterfaceCompute<DirectionsTag, VariablesTag>;
270 0 : static void function(const gsl::not_null<return_type*> subitems,
271 : const typename parent_tag::type& parent_value) {
272 : ::db::Subitems<parent_tag>::template create_compute_item<base>(
273 : subitems, parent_value);
274 : }
275 0 : using argument_tags = tmpl::list<parent_tag>;
276 : };
277 :
278 : /// \brief specialization of a subitem tag for an interface compute tag of a
279 : /// sliced Variables
280 : ///
281 : /// This is a compute tag for an unordered map from ::Direction (with the set of
282 : /// directions being those produced by `DirectionsTag`) to a Tensor (whose
283 : /// type comes from `TensorTag`) that is contained in a Variables (labeled by
284 : /// `VariablesTag`) for a domain::Tags::Slice<DirectionsTag, VariablesTag>>.
285 : template <typename DirectionsTag, typename TensorTag, typename VariablesTag>
286 1 : struct Subitem<::domain::Tags::Interface<DirectionsTag, TensorTag>,
287 : ::domain::Tags::Slice<DirectionsTag, VariablesTag>>
288 : : db::ComputeTag, ::domain::Tags::Interface<DirectionsTag, TensorTag> {
289 0 : using base = ::domain::Tags::Interface<DirectionsTag, TensorTag>;
290 0 : using return_type = typename base::type;
291 0 : using parent_tag = ::domain::Tags::Slice<DirectionsTag, VariablesTag>;
292 0 : static void function(const gsl::not_null<return_type*> subitems,
293 : const typename parent_tag::type& parent_value) {
294 : ::db::Subitems<parent_tag>::template create_compute_item<base>(
295 : subitems, parent_value);
296 : }
297 0 : using argument_tags = tmpl::list<parent_tag>;
298 : };
299 : } // namespace Tags
|