Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <type_traits> 7 : 8 : #include "Utilities/ProtocolHelpers.hpp" 9 : #include "Utilities/TMPL.hpp" 10 : #include "Utilities/TypeTraits/IsA.hpp" 11 : 12 : /// \cond 13 : class DataVector; 14 : template <typename X, typename Symm, typename IndexList> 15 : class Tensor; 16 : namespace Tags { 17 : template <typename Tag> 18 : struct Source; 19 : } // namespace Tags 20 : /// \endcond 21 : 22 : namespace imex::protocols { 23 : /// Protocol for an implicit sector of an IMEX system. 24 : /// 25 : /// An implicit sector describes the sources for one implicit solve 26 : /// performed during IMEX evolution. A system may have multiple 27 : /// implicit sectors, but they must be independent, i.e., their 28 : /// sources must not depend on any tensors in other sectors. 29 : /// 30 : /// Classes implementing this protocol must define: 31 : /// 32 : /// * a `tensors` type alias of tags for the variables to be solved for 33 : /// 34 : /// * an `initial_guess` type to be passed to `db::mutate_apply`, 35 : /// taking additional arguments for the inhomogeneous terms \f$X\f$ 36 : /// and implicit weight \f$w\f$ in the equation to be solved: 37 : /// \f$u = X + w S(u)\f$. (See example below.) It must return a 38 : /// `std::vector<GuessResult>` indicating, for each point, whether 39 : /// the implicit equation has been solved analytically or whether 40 : /// the numerical solve should continue. An empty return is 41 : /// equivalent to `imex::GuessResult::InitialGuess` for every point, 42 : /// so numerical solves will be performed for each. When this is 43 : /// called, the sector variables will have the value from the 44 : /// explicit part of the time step. This mutator will not be called 45 : /// if the implicit weight is zero, as the solution is trivial in 46 : /// that case. If using the value of the explicit step as an 47 : /// initial guess is acceptable, this can be the type 48 : /// `imex::GuessExplicitResult`. 49 : /// 50 : /// * a `solve_attempts` list of sources that will be attempted to be 51 : /// solved, in order. The first one that succeeds at each point 52 : /// will be used. Pieces of code that need "the" source for the 53 : /// sector will use the source from the first entry. Each attempt 54 : /// must be a struct with the following types: 55 : /// 56 : /// * lists used to construct a DataBox during the pointwise 57 : /// implicit solve: 58 : /// 59 : /// * `tags_from_evolution` for tags in addition to the sector 60 : /// tensors to be made available from the evolution DataBox. 61 : /// Volume quantities will be reduced to have one grid point, 62 : /// with the appropriate value for the point being solved for. 63 : /// 64 : /// * `simple_tags` for temporaries (e.g., primitives) 65 : /// 66 : /// * `compute_tags` 67 : /// 68 : /// * a `source` type to be passed to `db::mutate_apply` to compute 69 : /// the sources. 70 : /// 71 : /// * a `jacobian` type to be passed to `db::mutate_apply` to 72 : /// compute the source jacobian. If the implicit equation can 73 : /// always be solved analytically for the sector, the jacobian is 74 : /// not required and this may be the type 75 : /// `imex::NoJacobianBecauseSolutionIsAnalytic`. 76 : /// 77 : /// * lists `source_prep` and `jacobian_prep` that will be called 78 : /// before the corresponding main mutator, e.g., for computing 79 : /// primitives. Mutators appearing in multiple lists, as well as 80 : /// the `source` and `jacobian` mutators, will be skipped if they 81 : /// have already been applied for the current point. Note that 82 : /// the `source_prep` mutators are only used during the implicit 83 : /// solve, and any preparation needed before the `source` call in 84 : /// the main action loop to record the history is the 85 : /// responsibility of the user. 86 : /// 87 : /// All `Variables` in the DataBox, including the sources and source 88 : /// jacobian, will be initialized to zero with a single grid point. 89 : /// 90 : /// \snippet DoImplicitStepSector.hpp simple_sector 91 : /// 92 : /// Examples of definitions of a complicated implicit source and 93 : /// jacobian: 94 : /// 95 : /// \snippet Test_SolveImplicitSector.cpp source 96 : /// \snippet Test_SolveImplicitSector.cpp jacobian 97 1 : struct ImplicitSector { 98 : template <typename ConformingType> 99 0 : struct test { 100 0 : using tensors = typename ConformingType::tensors; 101 0 : using initial_guess = typename ConformingType::initial_guess; 102 0 : using solve_attempts = typename ConformingType::solve_attempts; 103 : 104 : static_assert(tt::is_a_v<tmpl::list, tensors>); 105 : static_assert(tt::is_a_v<tmpl::list, solve_attempts>); 106 : static_assert(tmpl::size<solve_attempts>::value >= 1); 107 : 108 : static_assert( 109 : tmpl::all< 110 : tensors, 111 : tt::is_a<Tensor, tmpl::bind<tmpl::type_from, tmpl::_1>>>::value); 112 : 113 0 : using source_tensors = 114 : tmpl::transform<tensors, tmpl::bind<::Tags::Source, tmpl::_1>>; 115 : 116 : static_assert( 117 : tmpl::size<tmpl::list_difference<typename initial_guess::return_tags, 118 : tensors>>::value == 0, 119 : "initial_guess can only modify sector variables."); 120 : 121 : template <typename SolveAttempt> 122 0 : struct test_solve_attempt { 123 0 : using source = typename SolveAttempt::source; 124 0 : using jacobian = typename SolveAttempt::jacobian; 125 : 126 0 : using tags_from_evolution = typename SolveAttempt::tags_from_evolution; 127 0 : using simple_tags = typename SolveAttempt::simple_tags; 128 0 : using compute_tags = typename SolveAttempt::compute_tags; 129 : 130 0 : using source_prep = typename SolveAttempt::source_prep; 131 0 : using jacobian_prep = typename SolveAttempt::jacobian_prep; 132 : 133 : static_assert(tt::is_a_v<tmpl::list, tags_from_evolution>); 134 : static_assert(tt::is_a_v<tmpl::list, simple_tags>); 135 : static_assert(tt::is_a_v<tmpl::list, compute_tags>); 136 : static_assert(tt::is_a_v<tmpl::list, source_prep>); 137 : static_assert(tt::is_a_v<tmpl::list, jacobian_prep>); 138 : 139 : static_assert( 140 : std::is_same_v<tmpl::list_difference<tags_from_evolution, tensors>, 141 : tags_from_evolution>, 142 : "tags_from_evolution cannot include the sector tensors."); 143 : 144 : static_assert( 145 : std::is_same_v<tmpl::list_difference<source_tensors, 146 : typename source::return_tags>, 147 : tmpl::list<>> and 148 : std::is_same_v<tmpl::list_difference<typename source::return_tags, 149 : source_tensors>, 150 : tmpl::list<>>, 151 : "Implicit source must provide sources for the entire sector."); 152 : 153 : template <typename T> 154 0 : struct is_a_tensor_of_data_vector : std::false_type {}; 155 : 156 : template <typename Symm, typename IndexList> 157 0 : struct is_a_tensor_of_data_vector<Tensor<DataVector, Symm, IndexList>> 158 : : std::true_type {}; 159 : 160 : static_assert( 161 : tmpl::none<simple_tags, is_a_tensor_of_data_vector<tmpl::bind< 162 : tmpl::type_from, tmpl::_1>>>::value, 163 : "Do not include tags for Tensor<DataVector> in simple_tags, because " 164 : "they trigger many memory allocations. Add the tensors as part of " 165 : "a Variables instead."); 166 : 167 0 : using type = std::true_type; 168 : }; 169 : 170 : static_assert( 171 : tmpl::all<solve_attempts, test_solve_attempt<tmpl::_1>>::value); 172 : }; 173 : }; 174 : } // namespace imex::protocols