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