Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <array> 7 : #include <cstddef> 8 : #include <string> 9 : 10 : #include "DataStructures/DataBox/Subitems.hpp" 11 : #include "DataStructures/DataBox/Tag.hpp" 12 : #include "DataStructures/DataVector.hpp" 13 : #include "DataStructures/Tensor/Tensor.hpp" 14 : #include "DataStructures/Variables.hpp" 15 : #include "Options/Auto.hpp" 16 : #include "Options/Options.hpp" 17 : #include "Parallel/Serialize.hpp" 18 : #include "ParallelAlgorithms/LinearSolver/Schwarz/OverlapHelpers.hpp" 19 : #include "Utilities/Gsl.hpp" 20 : #include "Utilities/TMPL.hpp" 21 : 22 : namespace LinearSolver::Schwarz { 23 : 24 : /// Option tags related to the Schwarz solver 25 1 : namespace OptionTags { 26 : 27 : template <typename OptionsGroup> 28 0 : struct MaxOverlap { 29 0 : using type = size_t; 30 0 : using group = OptionsGroup; 31 0 : static constexpr Options::String help = 32 : "Number of points that subdomains can extend into neighbors"; 33 : }; 34 : 35 : template <typename SolverType, typename OptionsGroup> 36 0 : struct SubdomainSolver { 37 0 : using type = SolverType; 38 0 : using group = OptionsGroup; 39 0 : static constexpr Options::String help = "The linear solver on subdomains"; 40 : }; 41 : 42 : template <typename OptionsGroup> 43 0 : struct SkipSubdomainSolverResets { 44 0 : static std::string name() noexcept { return "SkipResets"; } 45 0 : using type = bool; 46 0 : using group = OptionsGroup; 47 0 : static constexpr Options::String help = 48 : "Skip resets of the subdomain solver. This only has an effect in cases " 49 : "where the operator changes, e.g. between nonlinear-solver iterations. " 50 : "Skipping resets avoids expensive re-building of the operator, but comes " 51 : "at the cost of less accurate preconditioning and thus potentially more " 52 : "preconditioned iterations. Whether or not this helps convergence " 53 : "overall is highly problem-dependent."; 54 : }; 55 : 56 : } // namespace OptionTags 57 : 58 : /// Tags related to the Schwarz solver 59 : namespace Tags { 60 : 61 : /// Number of points a subdomain can overlap with its neighbor 62 : template <typename OptionsGroup> 63 1 : struct MaxOverlap : db::SimpleTag { 64 0 : static std::string name() noexcept { 65 : return "MaxOverlap(" + Options::name<OptionsGroup>() + ")"; 66 : } 67 0 : using type = size_t; 68 0 : static constexpr bool pass_metavariables = false; 69 0 : using option_tags = tmpl::list<OptionTags::MaxOverlap<OptionsGroup>>; 70 0 : static type create_from_options(const type& value) noexcept { return value; } 71 : }; 72 : 73 : /// The serial linear solver used to solve subdomain operators 74 : template <typename OptionsGroup> 75 1 : struct SubdomainSolverBase : db::BaseTag { 76 0 : static std::string name() noexcept { 77 : return "SubdomainSolver(" + Options::name<OptionsGroup>() + ")"; 78 : } 79 : }; 80 : 81 : /// The serial linear solver of type `SolverType` used to solve subdomain 82 : /// operators 83 : template <typename SolverType, typename OptionsGroup> 84 1 : struct SubdomainSolver : SubdomainSolverBase<OptionsGroup>, db::SimpleTag { 85 0 : using type = SolverType; 86 0 : static constexpr bool pass_metavariables = false; 87 0 : using option_tags = 88 : tmpl::list<OptionTags::SubdomainSolver<SolverType, OptionsGroup>>; 89 0 : static type create_from_options(const type& value) noexcept { 90 : return deserialize<type>(serialize<type>(value).data()); 91 : } 92 : }; 93 : 94 : /// Skip resets of the subdomain solver. 95 : /// 96 : /// \see LinearSolver::Schwarz::Actions::ResetSubdomainSolver 97 : template <typename OptionsGroup> 98 1 : struct SkipSubdomainSolverResets : db::SimpleTag { 99 0 : using type = bool; 100 0 : static constexpr bool pass_metavariables = false; 101 0 : using option_tags = 102 : tmpl::list<OptionTags::SkipSubdomainSolverResets<OptionsGroup>>; 103 0 : static bool create_from_options(const bool value) noexcept { return value; } 104 : }; 105 : 106 : /*! 107 : * \brief The `Tag` on the overlap region with each neighbor, i.e. on a region 108 : * extruding from the central element. 109 : * 110 : * Note that data on an overlap with a neighbor is typically oriented according 111 : * to the neighbor's orientation, so re-orientation needs to happen whenever 112 : * the data cross element boundaries. 113 : */ 114 : template <typename Tag, size_t Dim, typename OptionsGroup> 115 1 : struct Overlaps : db::SimpleTag { 116 0 : static std::string name() noexcept { 117 : return "Overlaps(" + db::tag_name<Tag>() + ", " + 118 : Options::name<OptionsGroup>() + ")"; 119 : } 120 0 : using tag = Tag; 121 0 : using type = OverlapMap<Dim, typename Tag::type>; 122 : }; 123 : 124 : /// The number of points a neighbor's subdomain extends into the element 125 : template <size_t Dim, typename OptionsGroup> 126 1 : struct IntrudingExtents : db::SimpleTag { 127 0 : static std::string name() noexcept { 128 : return "IntrudingExtents(" + Options::name<OptionsGroup>() + ")"; 129 : } 130 0 : using type = std::array<size_t, Dim>; 131 : }; 132 : 133 : /// The width in element-logical coordinates that a neighbor's subdomain extends 134 : /// into the element 135 : template <size_t Dim, typename OptionsGroup> 136 1 : struct IntrudingOverlapWidths : db::SimpleTag { 137 0 : static std::string name() noexcept { 138 : return "IntrudingOverlapWidths(" + Options::name<OptionsGroup>() + ")"; 139 : } 140 0 : using type = std::array<double, Dim>; 141 : }; 142 : 143 : /// Weighting field for combining data from multiple overlapping subdomains 144 : template <typename OptionsGroup> 145 1 : struct Weight : db::SimpleTag { 146 0 : static std::string name() noexcept { 147 : return "Weight(" + Options::name<OptionsGroup>() + ")"; 148 : } 149 0 : using type = Scalar<DataVector>; 150 : }; 151 : 152 : /*! 153 : * \brief A diagnostic quantity to check that weights are conserved 154 : * 155 : * This quantity and the `Tags::Weight` on the element should sum to one on all 156 : * grid points. Residual values indicate that overlap data from neighboring 157 : * subdomains and data on the element are combined in a non-conservative way. 158 : */ 159 : template <typename OptionsGroup> 160 1 : struct SummedIntrudingOverlapWeights : db::SimpleTag { 161 0 : static std::string name() noexcept { 162 : return "SummedIntrudingOverlapWeights(" + Options::name<OptionsGroup>() + 163 : ")"; 164 : } 165 0 : using type = Scalar<DataVector>; 166 : }; 167 : 168 : } // namespace Tags 169 : } // namespace LinearSolver::Schwarz 170 : 171 : namespace db { 172 : namespace detail { 173 : // This implementation mirrors the interface tag subitems in `Domain/Tags.hpp`. 174 : // Please see that implementation for details. 175 : template <typename VariablesTag, size_t Dim, typename OptionsGroup, 176 : typename Tags = typename VariablesTag::type::tags_list> 177 : struct OverlapSubitemsImpl; 178 : 179 : template <typename VariablesTag, size_t Dim, typename OptionsGroup, 180 : typename... Tags> 181 : struct OverlapSubitemsImpl<VariablesTag, Dim, OptionsGroup, 182 : tmpl::list<Tags...>> { 183 : using type = tmpl::list< 184 : LinearSolver::Schwarz::Tags::Overlaps<Tags, Dim, OptionsGroup>...>; 185 : using tag = 186 : LinearSolver::Schwarz::Tags::Overlaps<VariablesTag, Dim, OptionsGroup>; 187 : using return_type = NoSuchType; 188 : template <typename Subtag> 189 : static void create_item( 190 : const gsl::not_null<typename tag::type*> parent_value, 191 : const gsl::not_null<typename Subtag::type*> sub_value) noexcept { 192 : sub_value->clear(); 193 : for (auto& [overlap_id, parent_overlap_vars] : *parent_value) { 194 : auto& parent_overlap_field = 195 : get<typename Subtag::tag>(parent_overlap_vars); 196 : auto& sub_overlap_field = (*sub_value)[overlap_id]; 197 : for (size_t i = 0; i < parent_overlap_field.size(); ++i) { 198 : sub_overlap_field[i].set_data_ref(&parent_overlap_field[i]); 199 : } 200 : } 201 : } 202 : template <typename Subtag> 203 : static void create_compute_item( 204 : const gsl::not_null<typename Subtag::type*> sub_value, 205 : const typename tag::type& parent_value) noexcept { 206 : for (const auto& [overlap_id, parent_overlap_vars] : parent_value) { 207 : const auto& parent_overlap_field = 208 : get<typename Subtag::tag>(parent_overlap_vars); 209 : auto& sub_overlap_field = (*sub_value)[overlap_id]; 210 : for (size_t i = 0; i < parent_overlap_field.size(); ++i) { 211 : // clang-tidy: do not use const_cast 212 : // The DataBox will only give out a const reference to the result of a 213 : // compute item. Here, that is a reference to a const map to Tensors of 214 : // DataVectors. There is no (publicly visible) indirection there, so 215 : // having the map const will allow only const access to the contained 216 : // DataVectors, so no modification through the pointer cast here is 217 : // possible. See the implementation of subitems in `Domain/Tags.hpp` for 218 : // details. 219 : sub_overlap_field[i].set_data_ref( 220 : const_cast<DataVector*>(&parent_overlap_field[i])); // NOLINT 221 : } 222 : } 223 : } 224 : }; 225 : } // namespace detail 226 : 227 : template <typename VariablesTag, size_t Dim, typename OptionsGroup> 228 : struct Subitems< 229 : LinearSolver::Schwarz::Tags::Overlaps<VariablesTag, Dim, OptionsGroup>, 230 : Requires<tt::is_a_v<Variables, typename VariablesTag::type>>> 231 0 : : detail::OverlapSubitemsImpl<VariablesTag, Dim, OptionsGroup> {}; 232 : 233 : } // namespace db