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