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