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