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