Line data Source code
1 1 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : /// \file
5 : /// Defines tags related to domain quantities
6 :
7 : #pragma once
8 :
9 : #include <array>
10 : #include <cstddef>
11 : #include <memory>
12 : #include <string>
13 : #include <unordered_map>
14 : #include <unordered_set>
15 : #include <vector>
16 :
17 : #include "DataStructures/DataBox/Subitems.hpp"
18 : #include "DataStructures/DataBox/Tag.hpp"
19 : #include "DataStructures/DataBox/TagName.hpp"
20 : #include "DataStructures/Tensor/EagerMath/Determinant.hpp"
21 : #include "DataStructures/Tensor/EagerMath/DeterminantAndInverse.hpp"
22 : #include "DataStructures/Tensor/TypeAliases.hpp"
23 : #include "DataStructures/Variables.hpp"
24 : #include "Domain/Structure/Direction.hpp"
25 : #include "Domain/Structure/Element.hpp"
26 : #include "Utilities/GetOutput.hpp"
27 : #include "Utilities/Gsl.hpp"
28 : #include "Utilities/NoSuchType.hpp"
29 : #include "Utilities/Requires.hpp"
30 : #include "Utilities/TMPL.hpp"
31 : #include "Utilities/TypeTraits.hpp"
32 : #include "Utilities/TypeTraits/IsA.hpp"
33 :
34 : /// \cond
35 : class DataVector;
36 : template <size_t VolumeDim>
37 : class Domain;
38 : template <size_t VolumeDim, typename Frame>
39 : class ElementMap;
40 : template <size_t VolumeDim>
41 : class Mesh;
42 : /// \endcond
43 :
44 : namespace domain {
45 : /// \ingroup ComputationalDomainGroup
46 : /// \brief %Tags for the domain.
47 : namespace Tags {
48 : /// \ingroup DataBoxTagsGroup
49 : /// \ingroup ComputationalDomainGroup
50 : /// The ::Element associated with the DataBox
51 : template <size_t VolumeDim>
52 1 : struct Element : db::SimpleTag {
53 0 : using type = ::Element<VolumeDim>;
54 : };
55 :
56 : /// \ingroup DataBoxTagsGroup
57 : /// \ingroup ComputationalDomainGroup
58 : /// \brief The computational grid of the Element in the DataBox
59 : /// \details The corresponding interface tag uses Mesh::slice_through to compute
60 : /// the mesh on the face of the element.
61 : template <size_t VolumeDim>
62 1 : struct Mesh : db::SimpleTag {
63 0 : using type = ::Mesh<VolumeDim>;
64 : };
65 :
66 : /// \ingroup DataBoxTagsGroup
67 : /// \ingroup ComputationalDomainGroup
68 : /// The coordinate map from the ElementLogical frame to the TargetFrame
69 : template <size_t VolumeDim, typename TargetFrame = Frame::Inertial>
70 1 : struct ElementMap : db::SimpleTag {
71 0 : static constexpr size_t dim = VolumeDim;
72 0 : using target_frame = TargetFrame;
73 0 : using source_frame = Frame::ElementLogical;
74 :
75 0 : static std::string name() {
76 : return "ElementMap(" + get_output(TargetFrame{}) + ")";
77 : }
78 0 : using type = ::ElementMap<VolumeDim, TargetFrame>;
79 : };
80 :
81 : /// \ingroup DataBoxTagsGroup
82 : /// \ingroup ComputationalDomainGroup
83 : /// The coordinates in a given frame.
84 : template <size_t Dim, typename Frame>
85 1 : struct Coordinates : db::SimpleTag {
86 0 : static std::string name() { return get_output(Frame{}) + "Coordinates"; }
87 0 : using type = tnsr::I<DataVector, Dim, Frame>;
88 : };
89 :
90 : /// \ingroup DataBoxTagsGroup
91 : /// \ingroup ComputationalDomainGroup
92 : /// The coordinates in the target frame of `MapTag`. The `SourceCoordsTag`'s
93 : /// frame must be the source frame of `MapTag`
94 : template <class MapTag, class SourceCoordsTag,
95 : template <size_t, class> class CoordinatesTag = Coordinates>
96 1 : struct MappedCoordinates
97 : : CoordinatesTag<MapTag::dim, typename MapTag::target_frame>,
98 : db::ComputeTag {
99 0 : using base = CoordinatesTag<MapTag::dim, typename MapTag::target_frame>;
100 0 : using return_type = typename base::type;
101 0 : using argument_tags = tmpl::list<MapTag, SourceCoordsTag>;
102 0 : static constexpr auto function(
103 : const gsl::not_null<return_type*> target_coords,
104 : const typename MapTag::type& element_map,
105 : const tnsr::I<DataVector, MapTag::dim, typename MapTag::source_frame>&
106 : source_coords) {
107 : *target_coords = element_map(source_coords);
108 : }
109 : };
110 :
111 : /// \ingroup DataBoxTagsGroup
112 : /// \ingroup ComputationalDomainGroup
113 : /// \brief The inverse Jacobian from the source frame to the target frame.
114 : ///
115 : /// Specifically, \f$\partial x^{\bar{i}} / \partial x^i\f$, where \f$\bar{i}\f$
116 : /// denotes the source frame and \f$i\f$ denotes the target frame.
117 : template <size_t Dim, typename SourceFrame, typename TargetFrame>
118 1 : struct InverseJacobian : db::SimpleTag {
119 0 : static std::string name() {
120 : return "InverseJacobian(" + get_output(SourceFrame{}) + "," +
121 : get_output(TargetFrame{}) + ")";
122 : }
123 0 : using type = ::InverseJacobian<DataVector, Dim, SourceFrame, TargetFrame>;
124 : };
125 :
126 : /// \ingroup DataBoxTagsGroup
127 : /// \ingroup ComputationalDomainGroup
128 : /// Computes the inverse Jacobian of the map held by `MapTag` at the coordinates
129 : /// held by `SourceCoordsTag`. The coordinates must be in the source frame of
130 : /// the map.
131 : template <typename MapTag, typename SourceCoordsTag>
132 1 : struct InverseJacobianCompute
133 : : InverseJacobian<MapTag::dim, typename MapTag::source_frame,
134 : typename MapTag::target_frame>,
135 : db::ComputeTag {
136 0 : using base = InverseJacobian<MapTag::dim, typename MapTag::source_frame,
137 : typename MapTag::target_frame>;
138 0 : using return_type = typename base::type;
139 0 : using argument_tags = tmpl::list<MapTag, SourceCoordsTag>;
140 0 : static constexpr auto function(
141 : const gsl::not_null<return_type*> inv_jacobian,
142 : const typename MapTag::type& element_map,
143 : const tnsr::I<DataVector, MapTag::dim, typename MapTag::source_frame>&
144 : source_coords) {
145 : *inv_jacobian = element_map.inv_jacobian(source_coords);
146 : }
147 : };
148 :
149 : /// \ingroup DataBoxTagsGroup
150 : /// \ingroup ComputationalDomainGroup
151 : /// \brief The Jacobian from the source frame to the target frame.
152 : ///
153 : /// Specifically, \f$\partial x^{i} / \partial \xi^{\bar{i}}\f$, where
154 : /// \f$\xi^\bar{i}\f$ denotes the source frame and \f$x^i\f$ denotes the target
155 : /// frame.
156 : template <size_t Dim, typename SourceFrame, typename TargetFrame>
157 1 : struct Jacobian : db::SimpleTag {
158 0 : static std::string name() {
159 : return "Jacobian(" + get_output(SourceFrame{}) + "," +
160 : get_output(TargetFrame{}) + ")";
161 : }
162 0 : using type = ::Jacobian<DataVector, Dim, SourceFrame, TargetFrame>;
163 : };
164 :
165 : /// \ingroup DataBoxTagsGroup
166 : /// \ingroup ComputationalDomainGroup
167 : /// Computes the Jacobian of the map from the `InverseJacobian<Dim, SourceFrame,
168 : /// TargetFrame>` tag.
169 : template <size_t Dim, typename SourceFrame, typename TargetFrame>
170 1 : struct JacobianCompute : Jacobian<Dim, SourceFrame, TargetFrame>,
171 : db::ComputeTag {
172 0 : using base = Jacobian<Dim, SourceFrame, TargetFrame>;
173 0 : using return_type = typename base::type;
174 0 : using argument_tags =
175 : tmpl::list<InverseJacobian<Dim, SourceFrame, TargetFrame>>;
176 0 : static constexpr auto function(
177 : const gsl::not_null<return_type*> jacobian,
178 : const ::InverseJacobian<DataVector, Dim, SourceFrame, TargetFrame>&
179 : inv_jac) {
180 : *jacobian = determinant_and_inverse(inv_jac).second;
181 : }
182 : };
183 :
184 : /// \ingroup DataBoxTagsGroup
185 : /// \ingroup ComputationalDomainGroup
186 : /// \brief The determinant of the inverse Jacobian from the source frame to the
187 : /// target frame.
188 : template <typename SourceFrame, typename TargetFrame>
189 1 : struct DetInvJacobian : db::SimpleTag {
190 0 : using type = Scalar<DataVector>;
191 0 : static std::string name() {
192 : return "DetInvJacobian(" + get_output(SourceFrame{}) + "," +
193 : get_output(TargetFrame{}) + ")";
194 : }
195 : };
196 :
197 : /// \ingroup DataBoxTagsGroup
198 : /// \ingroup ComputationalDomainGroup
199 : /// Computes the determinant of the inverse Jacobian.
200 : template <size_t Dim, typename SourceFrame, typename TargetFrame>
201 1 : struct DetInvJacobianCompute : db::ComputeTag,
202 : DetInvJacobian<SourceFrame, TargetFrame> {
203 0 : using base = DetInvJacobian<SourceFrame, TargetFrame>;
204 0 : using return_type = typename base::type;
205 0 : using argument_tags =
206 : tmpl::list<InverseJacobian<Dim, SourceFrame, TargetFrame>>;
207 0 : static void function(const gsl::not_null<return_type*> det_inv_jac,
208 : const ::InverseJacobian<DataVector, Dim, SourceFrame,
209 : TargetFrame>& inv_jac) {
210 : determinant(det_inv_jac, inv_jac);
211 : }
212 : };
213 :
214 : /// \ingroup DataBoxTagsGroup
215 : /// \ingroup ComputationalDomainGroup
216 : /// Base tag for boundary data needed for updating the variables.
217 1 : struct VariablesBoundaryData : db::BaseTag {};
218 :
219 : /// @{
220 : /// \ingroup DataBoxTagsGroup
221 : /// \ingroup ComputationalDomainGroup
222 : /// The set of directions to neighboring Elements
223 : template <size_t VolumeDim>
224 1 : struct InternalDirections : db::SimpleTag {
225 0 : static constexpr size_t volume_dim = VolumeDim;
226 0 : using type = std::unordered_set<::Direction<VolumeDim>>;
227 : };
228 :
229 : template <size_t VolumeDim>
230 0 : struct InternalDirectionsCompute : InternalDirections<VolumeDim>,
231 : db::ComputeTag {
232 0 : static constexpr size_t volume_dim = VolumeDim;
233 0 : using base = InternalDirections<VolumeDim>;
234 0 : using return_type = std::unordered_set<::Direction<VolumeDim>>;
235 0 : using argument_tags = tmpl::list<Element<VolumeDim>>;
236 0 : static void function(const gsl::not_null<return_type*> directions,
237 : const ::Element<VolumeDim>& element) {
238 : for (const auto& direction_neighbors : element.neighbors()) {
239 : directions->insert(direction_neighbors.first);
240 : }
241 : }
242 : };
243 : /// @}
244 :
245 : /// @{
246 : /// \ingroup DataBoxTagsGroup
247 : /// \ingroup ComputationalDomainGroup
248 : /// The set of directions which correspond to external boundaries.
249 : /// Used for representing data on the interior side of the external boundary
250 : /// faces.
251 : template <size_t VolumeDim>
252 1 : struct BoundaryDirectionsInterior : db::SimpleTag {
253 0 : static constexpr size_t volume_dim = VolumeDim;
254 0 : using type = std::unordered_set<::Direction<VolumeDim>>;
255 : };
256 :
257 : template <size_t VolumeDim>
258 0 : struct BoundaryDirectionsInteriorCompute
259 : : BoundaryDirectionsInterior<VolumeDim>,
260 : db::ComputeTag {
261 0 : static constexpr size_t volume_dim = VolumeDim;
262 0 : using base = BoundaryDirectionsInterior<VolumeDim>;
263 0 : using return_type = std::unordered_set<::Direction<VolumeDim>>;
264 0 : using argument_tags = tmpl::list<Element<VolumeDim>>;
265 0 : static void function(const gsl::not_null<return_type*> directions,
266 : const ::Element<VolumeDim>& element) {
267 : *directions = element.external_boundaries();
268 : }
269 : };
270 : /// @}
271 :
272 : /// @{
273 : /// \ingroup DataBoxTagsGroup
274 : /// \ingroup ComputationalDomainGroup
275 : /// The set of directions which correspond to external boundaries. To be used
276 : /// to represent data which exists on the exterior side of the external boundary
277 : /// faces.
278 : template <size_t VolumeDim>
279 1 : struct BoundaryDirectionsExterior : db::SimpleTag {
280 0 : static constexpr size_t volume_dim = VolumeDim;
281 0 : using type = std::unordered_set<::Direction<VolumeDim>>;
282 : };
283 :
284 : template <size_t VolumeDim>
285 0 : struct BoundaryDirectionsExteriorCompute
286 : : BoundaryDirectionsExterior<VolumeDim>,
287 : db::ComputeTag {
288 0 : static constexpr size_t volume_dim = VolumeDim;
289 0 : using base = BoundaryDirectionsExterior<VolumeDim>;
290 0 : using return_type = std::unordered_set<::Direction<VolumeDim>>;
291 0 : using argument_tags = tmpl::list<Element<VolumeDim>>;
292 0 : static constexpr auto function(const gsl::not_null<return_type*> directions,
293 : const ::Element<VolumeDim>& element) {
294 : *directions = element.external_boundaries();
295 : }
296 : };
297 : /// @}
298 :
299 : /// \ingroup DataBoxTagsGroup
300 : /// \ingroup ComputationalDomainGroup
301 : /// \brief Tag which is either a SimpleTag for quantities on an
302 : /// interface, base tag to a compute item which acts on tags on an interface, or
303 : /// base tag to a compute item which slices a tag from the volume to an
304 : /// interface.
305 : ///
306 : /// The contained object will be a map from ::Direction to the item type of
307 : /// `Tag`, with the set of directions being those produced by `DirectionsTag`.
308 : ///
309 : /// If a SimpleTag is desired on the interface, then this tag can be added to
310 : /// the DataBox directly. If a ComputeTag which acts on Tags on the interface is
311 : /// desired, then the tag should be added using `InterfaceCompute`. If a
312 : /// ComputeTag which slices a TensorTag or a VariablesTag in the volume to an
313 : /// Interface is desired, then it should be added using `Slice`. In all cases,
314 : /// the tag can then be retrieved using `Tags::Interface<DirectionsTag, Tag>`.
315 : ///
316 : /// \tparam DirectionsTag the item of directions
317 : /// \tparam Tag the tag labeling the item
318 : ///
319 : /// \see InterfaceCompute, Slice
320 : template <typename DirectionsTag, typename Tag>
321 1 : struct Interface : db::SimpleTag {
322 : static_assert(db::is_simple_tag_v<DirectionsTag>);
323 : static_assert(db::is_simple_tag_v<Tag>);
324 0 : static std::string name() {
325 : return "Interface<" + db::tag_name<DirectionsTag>() + ", " +
326 : db::tag_name<Tag>() + ">";
327 : };
328 0 : using tag = Tag;
329 0 : using type = std::unordered_map<::Direction<DirectionsTag::volume_dim>,
330 : typename Tag::type>;
331 : };
332 :
333 : /// \ingroup DataBoxTagsGroup
334 : /// \ingroup ComputationalDomainGroup
335 : /// ::Direction to an interface
336 : template <size_t VolumeDim>
337 1 : struct Direction : db::SimpleTag {
338 0 : using type = ::Direction<VolumeDim>;
339 : };
340 :
341 : } // namespace Tags
342 : } // namespace domain
343 :
344 : namespace db {
345 : namespace detail {
346 : template <typename DirectionsTag, typename VariablesTag>
347 : struct InterfaceSubitemsImpl {
348 : using type = tmpl::transform<
349 : typename VariablesTag::type::tags_list,
350 : tmpl::bind<domain::Tags::Interface, tmpl::pin<DirectionsTag>, tmpl::_1>>;
351 :
352 : using tag = domain::Tags::Interface<DirectionsTag, VariablesTag>;
353 :
354 : template <typename Subtag>
355 : static void create_item(
356 : const gsl::not_null<typename tag::type*> parent_value,
357 : const gsl::not_null<typename Subtag::type*> sub_value) {
358 : sub_value->clear();
359 : for (auto& direction_vars : *parent_value) {
360 : const auto& direction = direction_vars.first;
361 : auto& parent_vars = get<typename Subtag::tag>(direction_vars.second);
362 : auto& sub_var = (*sub_value)[direction];
363 : for (auto vars_it = parent_vars.begin(), sub_var_it = sub_var.begin();
364 : vars_it != parent_vars.end(); ++vars_it, ++sub_var_it) {
365 : sub_var_it->set_data_ref(&*vars_it);
366 : }
367 : }
368 : }
369 :
370 : // The `return_type` can be anything for Subitems because the DataBox figures
371 : // out the correct return type, we just use the `return_type` type alias to
372 : // signal to the DataBox we want mutating behavior.
373 : using return_type = NoSuchType;
374 :
375 : template <typename Subtag>
376 : static void create_compute_item(
377 : const gsl::not_null<typename Subtag::type*> sub_value,
378 : const typename tag::type& parent_value) {
379 : for (const auto& direction_vars : parent_value) {
380 : const auto& direction = direction_vars.first;
381 : const auto& parent_vars =
382 : get<typename Subtag::tag>(direction_vars.second);
383 : auto& sub_var = (*sub_value)[direction];
384 : auto sub_var_it = sub_var.begin();
385 : for (auto vars_it = parent_vars.begin();
386 : vars_it != parent_vars.end(); ++vars_it, ++sub_var_it) {
387 : // clang-tidy: do not use const_cast
388 : // The DataBox will only give out a const reference to the
389 : // result of a compute item. Here, that is a reference to a
390 : // const map to Tensors of DataVectors. There is no (publicly
391 : // visible) indirection there, so having the map const will
392 : // allow only allow const access to the contained DataVectors,
393 : // so no modification through the pointer cast here is
394 : // possible.
395 : sub_var_it->set_data_ref(const_cast<DataVector*>(&*vars_it)); // NOLINT
396 : }
397 : }
398 : }
399 : };
400 : } // namespace detail
401 :
402 : template <typename DirectionsTag, typename VariablesTag>
403 0 : struct Subitems<domain::Tags::Interface<DirectionsTag, VariablesTag>,
404 : Requires<tt::is_a_v<Variables, typename VariablesTag::type>>>
405 : : detail::InterfaceSubitemsImpl<DirectionsTag, VariablesTag> {};
406 :
407 : } // namespace db
|