Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <cstddef> 7 : #include <type_traits> 8 : 9 : #include "DataStructures/DataBox/DataBox.hpp" 10 : #include "Domain/Structure/Direction.hpp" 11 : #include "Domain/Tags.hpp" 12 : #include "Domain/Tags/Faces.hpp" 13 : #include "Elliptic/BoundaryConditions/BoundaryCondition.hpp" 14 : #include "Elliptic/Utilities/ApplyAt.hpp" 15 : #include "Parallel/Tags/Metavariables.hpp" 16 : #include "Utilities/CallWithDynamicType.hpp" 17 : #include "Utilities/Gsl.hpp" 18 : #include "Utilities/TMPL.hpp" 19 : 20 : namespace elliptic { 21 : 22 : namespace detail { 23 : // Return the `BoundaryConditionClasses`, or get the list of derived classes 24 : // from `Metavariables::factory_creation` if `BoundaryConditionClasses` is 25 : // empty. 26 : template <typename Base, typename BoundaryConditionClasses, typename DbTagsList> 27 : struct GetBoundaryConditionClasses { 28 : using type = BoundaryConditionClasses; 29 : }; 30 : template <typename Base, typename DbTagsList> 31 : struct GetBoundaryConditionClasses<Base, tmpl::list<>, DbTagsList> { 32 : using type = tmpl::at< 33 : typename std::decay_t<decltype(db::get<Parallel::Tags::Metavariables>( 34 : std::declval<db::DataBox<DbTagsList>>()))>::factory_creation:: 35 : factory_classes, 36 : Base>; 37 : }; 38 : } // namespace detail 39 : 40 : /*! 41 : * \brief Apply the `boundary_condition` to the `fields_and_fluxes` with 42 : * arguments from interface tags in the DataBox. 43 : * 44 : * This functions assumes the arguments for the `boundary_condition` are stored 45 : * in the DataBox in tags `domain::Tags::Faces<Dim, Tag>`. 46 : * This may turn out not to be the most efficient setup, so code that 47 : * uses the boundary conditions doesn't have to use this function but can 48 : * procure the arguments differently. For example, future optimizations may 49 : * involve storing a subset of arguments that don't change during an elliptic 50 : * solve in direction-maps in the DataBox, and slicing other arguments to the 51 : * interface every time the boundary conditions are applied. 52 : * 53 : * The `ArgsTransform` template parameter can be used to transform the set of 54 : * argument tags for the boundary conditions further. It must be compatible with 55 : * `tmpl::transform`. For example, it may wrap the tags in another prefix. Set 56 : * it to `void` (default) to apply no transformation. 57 : * 58 : * The `BoundaryConditionClasses` can be used to list a set of classes derived 59 : * from `elliptic::BoundaryConditions::BoundaryCondition` that are iterated to 60 : * determine the concrete type of `boundary_condition`. It can be `tmpl::list<>` 61 : * (default) to use the classes listed in `Metavariables::factory_creation` 62 : * instead. 63 : */ 64 : template <bool Linearized, typename ArgsTransform = void, 65 : typename BoundaryConditionClasses = tmpl::list<>, size_t Dim, 66 : typename DbTagsList, typename MapKeys, typename... FieldsAndFluxes> 67 1 : void apply_boundary_condition( 68 : const elliptic::BoundaryConditions::BoundaryCondition<Dim>& 69 : boundary_condition, 70 : const db::DataBox<DbTagsList>& box, const MapKeys& map_keys_to_direction, 71 : FieldsAndFluxes&&... fields_and_fluxes) { 72 : using boundary_condition_classes = 73 : typename detail::GetBoundaryConditionClasses< 74 : elliptic::BoundaryConditions::BoundaryCondition<Dim>, 75 : BoundaryConditionClasses, DbTagsList>::type; 76 : call_with_dynamic_type<void, boundary_condition_classes>( 77 : &boundary_condition, [&map_keys_to_direction, &box, 78 : &fields_and_fluxes...](const auto* const derived) { 79 : using Derived = std::decay_t<std::remove_pointer_t<decltype(derived)>>; 80 : using volume_tags = 81 : tmpl::conditional_t<Linearized, 82 : typename Derived::volume_tags_linearized, 83 : typename Derived::volume_tags>; 84 : using argument_tags = domain::make_faces_tags< 85 : Dim, 86 : tmpl::conditional_t<Linearized, 87 : typename Derived::argument_tags_linearized, 88 : typename Derived::argument_tags>, 89 : volume_tags>; 90 : using argument_tags_transformed = 91 : tmpl::conditional_t<std::is_same_v<ArgsTransform, void>, 92 : argument_tags, 93 : tmpl::transform<argument_tags, ArgsTransform>>; 94 : using volume_tags_transformed = 95 : tmpl::conditional_t<std::is_same_v<ArgsTransform, void>, 96 : volume_tags, 97 : tmpl::transform<volume_tags, ArgsTransform>>; 98 : elliptic::util::apply_at<argument_tags_transformed, 99 : volume_tags_transformed>( 100 : [&derived, &fields_and_fluxes...](const auto&... args) { 101 : if constexpr (Linearized) { 102 : derived->apply_linearized( 103 : std::forward<FieldsAndFluxes>(fields_and_fluxes)..., 104 : args...); 105 : } else { 106 : derived->apply( 107 : std::forward<FieldsAndFluxes>(fields_and_fluxes)..., 108 : args...); 109 : } 110 : }, 111 : box, map_keys_to_direction); 112 : }); 113 : } 114 : } // namespace elliptic