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 : #include <type_traits>
8 :
9 : #include "DataStructures/DataBox/PrefixHelpers.hpp"
10 : #include "DataStructures/DataBox/SubitemTag.hpp"
11 : #include "DataStructures/DataBox/Tag.hpp"
12 : #include "DataStructures/Variables.hpp"
13 : #include "Domain/Structure/DirectionMap.hpp"
14 : #include "Utilities/Gsl.hpp"
15 : #include "Utilities/Requires.hpp"
16 : #include "Utilities/TMPL.hpp"
17 :
18 : namespace domain {
19 : namespace Tags {
20 :
21 : /// The `Tag` on element faces
22 : template <size_t Dim, typename Tag>
23 1 : struct Faces : db::PrefixTag, db::SimpleTag {
24 0 : static constexpr size_t volume_dim = Dim;
25 0 : using tag = Tag;
26 0 : using type = DirectionMap<Dim, typename Tag::type>;
27 : };
28 :
29 : } // namespace Tags
30 :
31 : /// Wrap `Tag` in `domain::Tags::Faces`, unless `Tag` is in the `VolumeTags`
32 : /// list
33 : template <typename Dim, typename Tag, typename VolumeTags = tmpl::list<>>
34 1 : struct make_faces_tag {
35 0 : using type = tmpl::conditional_t<tmpl::list_contains_v<VolumeTags, Tag>, Tag,
36 : domain::Tags::Faces<Dim::value, Tag>>;
37 : };
38 :
39 : /// Wrap all tags in `TagsList` in `domain::Tags::Faces`, except those in the
40 : /// `VolumeTags` list
41 : template <size_t Dim, typename TagsList, typename VolumeTags = tmpl::list<>>
42 1 : using make_faces_tags =
43 : tmpl::transform<TagsList, make_faces_tag<tmpl::pin<tmpl::size_t<Dim>>,
44 : tmpl::_1, tmpl::pin<VolumeTags>>>;
45 :
46 : } // namespace domain
47 :
48 : namespace db {
49 : template <typename FacesTag>
50 : struct Subitems<
51 : FacesTag,
52 : Requires<std::is_base_of_v<domain::Tags::Faces<FacesTag::volume_dim,
53 : typename FacesTag::tag>,
54 : FacesTag> and
55 : tt::is_a_v<Variables, typename FacesTag::tag::type>>> {
56 : static constexpr size_t Dim = FacesTag::volume_dim;
57 : using VariablesTag = typename FacesTag::tag;
58 : using VectorType = typename VariablesTag::type::vector_type;
59 :
60 : template <typename LocalTag>
61 : using faces_tag = domain::Tags::Faces<Dim, LocalTag>;
62 :
63 : using tag = faces_tag<VariablesTag>;
64 : using type =
65 : db::wrap_tags_in<faces_tag, typename VariablesTag::type::tags_list>;
66 :
67 : template <typename Subtag>
68 : static void create_item(
69 : const gsl::not_null<typename tag::type*> parent_value,
70 : const gsl::not_null<typename Subtag::type*> sub_value) {
71 : sub_value->clear();
72 : for (auto& [direction, all_parent_vars] : *parent_value) {
73 : auto& parent_var = get<typename Subtag::tag>(all_parent_vars);
74 : auto& sub_var = (*sub_value)[direction];
75 : for (auto vars_it = parent_var.begin(), sub_var_it = sub_var.begin();
76 : vars_it != parent_var.end(); ++vars_it, ++sub_var_it) {
77 : sub_var_it->set_data_ref(&*vars_it);
78 : }
79 : }
80 : }
81 :
82 : // The `return_type` can be anything for Subitems because the DataBox figures
83 : // out the correct return type, we just use the `return_type` type alias to
84 : // signal to the DataBox we want mutating behavior.
85 : using return_type = NoSuchType;
86 :
87 : template <typename Subtag>
88 : static void create_compute_item(
89 : const gsl::not_null<typename Subtag::type*> sub_value,
90 : const typename tag::type& parent_value) {
91 : for (const auto& [direction, all_parent_vars] : parent_value) {
92 : const auto& parent_var = get<typename Subtag::tag>(all_parent_vars);
93 : auto& sub_var = (*sub_value)[direction];
94 : auto sub_var_it = sub_var.begin();
95 : for (auto vars_it = parent_var.begin(); vars_it != parent_var.end();
96 : ++vars_it, ++sub_var_it) {
97 : // clang-tidy: do not use const_cast
98 : // The DataBox will only give out a const reference to the
99 : // result of a compute item. Here, that is a reference to a
100 : // const map to Tensors of DataVectors. There is no (publicly
101 : // visible) indirection there, so having the map const will
102 : // allow only allow const access to the contained DataVectors,
103 : // so no modification through the pointer cast here is
104 : // possible.
105 : sub_var_it->set_data_ref(const_cast<VectorType*>(&*vars_it)); // NOLINT
106 : }
107 : }
108 : }
109 : };
110 : } // namespace db
111 :
112 : namespace Tags {
113 : /// \brief Specialization of a subitem tag for a compute tag that inherits off
114 : /// `domain::Tags::Faces`.
115 : ///
116 : /// This tag holds a map from faces to _one_ of the subitems, typically one
117 : /// tensor in a Variables. The `FacesSubitemTag` represents the particular
118 : /// tensor on faces, and the `FacesComputeTag` represents the full Variables on
119 : /// faces.
120 : template <typename FacesSubitemTag, typename FacesComputeTag>
121 : struct Subitem<FacesSubitemTag, FacesComputeTag,
122 : Requires<std::is_base_of_v<
123 : domain::Tags::Faces<FacesComputeTag::volume_dim,
124 : typename FacesComputeTag::tag>,
125 : FacesComputeTag>>> : db::ComputeTag,
126 : FacesSubitemTag {
127 : using base = FacesSubitemTag;
128 : using return_type = typename base::type;
129 : using parent_tag = FacesComputeTag;
130 : using argument_tags = tmpl::list<typename parent_tag::base>;
131 : static void function(const gsl::not_null<return_type*> subitems,
132 : const typename parent_tag::type& parent_value) {
133 : ::db::Subitems<parent_tag>::template create_compute_item<base>(
134 : subitems, parent_value);
135 : }
136 : };
137 : } // namespace Tags
|