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