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 <optional> 8 : #include <type_traits> 9 : #include <utility> 10 : 11 : #include "DataStructures/DataBox/DataBox.hpp" 12 : #include "DataStructures/DataVector.hpp" 13 : #include "DataStructures/Index.hpp" 14 : #include "DataStructures/Tensor/Tensor.hpp" 15 : #include "DataStructures/Variables.hpp" 16 : #include "Domain/BoundaryConditions/BoundaryCondition.hpp" 17 : #include "Domain/BoundaryConditions/None.hpp" 18 : #include "Domain/BoundaryConditions/Periodic.hpp" 19 : #include "Domain/Creators/Tags/ExternalBoundaryConditions.hpp" 20 : #include "Domain/Domain.hpp" 21 : #include "Domain/Structure/Direction.hpp" 22 : #include "Domain/Structure/DirectionMap.hpp" 23 : #include "Domain/Structure/Element.hpp" 24 : #include "Domain/Structure/ElementId.hpp" 25 : #include "Domain/Tags.hpp" 26 : #include "Domain/TagsTimeDependent.hpp" 27 : #include "Evolution/BoundaryConditions/Type.hpp" 28 : #include "Evolution/DgSubcell/GhostData.hpp" 29 : #include "Evolution/DgSubcell/Tags/GhostDataForReconstruction.hpp" 30 : #include "Evolution/DgSubcell/Tags/Mesh.hpp" 31 : #include "Evolution/DiscontinuousGalerkin/NormalVectorTags.hpp" 32 : #include "Evolution/Systems/Burgers/BoundaryConditions/BoundaryCondition.hpp" 33 : #include "Evolution/Systems/Burgers/FiniteDifference/Reconstructor.hpp" 34 : #include "Evolution/Systems/Burgers/System.hpp" 35 : #include "Evolution/Systems/Burgers/Tags.hpp" 36 : #include "NumericalAlgorithms/Spectral/Mesh.hpp" 37 : #include "Parallel/Tags/Metavariables.hpp" 38 : #include "Utilities/CallWithDynamicType.hpp" 39 : #include "Utilities/ErrorHandling/Assert.hpp" 40 : #include "Utilities/Gsl.hpp" 41 : #include "Utilities/PrettyType.hpp" 42 : #include "Utilities/TMPL.hpp" 43 : 44 1 : namespace Burgers::fd { 45 : /*! 46 : * \brief Computes finite difference ghost data for external boundary 47 : * conditions. 48 : * 49 : * If the element is at the external boundary, computes FD ghost data with a 50 : * given boundary condition and stores it into neighbor data with {direction, 51 : * ElementId::external_boundary_id()} as the mortar_id key. 52 : * 53 : * \note Subcell needs to be enabled for boundary elements (see 54 : * Burgers::subcell::TimeDerivative). Otherwise this function would be never 55 : * called. 56 : * 57 : */ 58 1 : struct BoundaryConditionGhostData { 59 : template <typename DbTagsList> 60 0 : static void apply(const gsl::not_null<db::DataBox<DbTagsList>*> box, 61 : const Element<1>& element, 62 : const Burgers::fd::Reconstructor& reconstructor); 63 : 64 : private: 65 : template <typename FdBoundaryConditionHelper, typename DbTagsList, 66 : typename... FdBoundaryConditionArgsTags> 67 : // A helper function for calling fd_ghost() of BoundaryCondition subclasses 68 0 : static void apply_subcell_boundary_condition_impl( 69 : FdBoundaryConditionHelper& fd_boundary_condition_helper, 70 : const gsl::not_null<db::DataBox<DbTagsList>*>& box, 71 : tmpl::list<FdBoundaryConditionArgsTags...>) { 72 : return fd_boundary_condition_helper( 73 : db::get<FdBoundaryConditionArgsTags>(*box)...); 74 : } 75 : }; 76 : 77 : template <typename DbTagsList> 78 : void BoundaryConditionGhostData::apply( 79 : const gsl::not_null<db::DataBox<DbTagsList>*> box, 80 : const Element<1>& element, 81 : const Burgers::fd::Reconstructor& reconstructor) { 82 : const auto& external_boundary_condition = 83 : db::get<domain::Tags::ExternalBoundaryConditions<1>>(*box).at( 84 : element.id().block_id()); 85 : 86 : // Check if the element is on the external boundary. If not, the caller is 87 : // doing something wrong (e.g. trying to compute FD ghost data with boundary 88 : // conditions at an element which is not on the external boundary). 89 : ASSERT(not element.external_boundaries().empty(), 90 : "The element (ID : " << element.id() 91 : << ") is not on external boundaries"); 92 : 93 : const Mesh<1> subcell_mesh = 94 : db::get<evolution::dg::subcell::Tags::Mesh<1>>(*box); 95 : 96 : const size_t ghost_zone_size{reconstructor.ghost_zone_size()}; 97 : 98 : for (const auto& direction : element.external_boundaries()) { 99 : const auto& boundary_condition_at_direction = 100 : *external_boundary_condition.at(direction); 101 : 102 : const size_t num_face_pts{ 103 : subcell_mesh.extents().slice_away(direction.dimension()).product()}; 104 : 105 : // a Variables object to store the computed FD ghost data 106 : Variables<tmpl::list<Burgers::Tags::U>> ghost_data_vars{ghost_zone_size * 107 : num_face_pts}; 108 : 109 : // We don't need to care about boundary ghost data when using the periodic 110 : // condition, so exclude it from the type list 111 : using factory_classes = 112 : typename std::decay_t<decltype(db::get<Parallel::Tags::Metavariables>( 113 : *box))>::factory_creation::factory_classes; 114 : using derived_boundary_conditions_for_subcell = tmpl::remove_if< 115 : tmpl::at<factory_classes, 116 : typename Burgers::System::boundary_conditions_base>, 117 : tmpl::or_< 118 : std::is_base_of<domain::BoundaryConditions::MarkAsPeriodic, 119 : tmpl::_1>, 120 : std::is_base_of<domain::BoundaryConditions::MarkAsNone, tmpl::_1>>>; 121 : 122 : // Now apply subcell boundary conditions 123 : call_with_dynamic_type<void, derived_boundary_conditions_for_subcell>( 124 : &boundary_condition_at_direction, 125 : [&box, &direction, &ghost_data_vars](const auto* boundary_condition) { 126 : using BoundaryCondition = std::decay_t<decltype(*boundary_condition)>; 127 : using bcondition_interior_evolved_vars_tags = 128 : typename BoundaryCondition::fd_interior_evolved_variables_tags; 129 : using bcondition_interior_temporary_tags = 130 : typename BoundaryCondition::fd_interior_temporary_tags; 131 : using bcondition_gridless_tags = 132 : typename BoundaryCondition::fd_gridless_tags; 133 : 134 : using bcondition_interior_tags = 135 : tmpl::append<bcondition_interior_evolved_vars_tags, 136 : bcondition_interior_temporary_tags, 137 : bcondition_gridless_tags>; 138 : 139 : if constexpr (BoundaryCondition::bc_type == 140 : evolution::BoundaryConditions::Type::Ghost) { 141 : const auto apply_fd_ghost = 142 : [&boundary_condition, &direction, 143 : &ghost_data_vars](const auto&... boundary_ghost_data_args) { 144 : (*boundary_condition) 145 : .fd_ghost(make_not_null( 146 : &get<Burgers::Tags::U>(ghost_data_vars)), 147 : direction, boundary_ghost_data_args...); 148 : }; 149 : apply_subcell_boundary_condition_impl(apply_fd_ghost, box, 150 : bcondition_interior_tags{}); 151 : } else if constexpr (BoundaryCondition::bc_type == 152 : evolution::BoundaryConditions::Type:: 153 : DemandOutgoingCharSpeeds) { 154 : // This boundary condition only checks if all the characteristic 155 : // speeds are directed outward. 156 : const auto& volume_mesh_velocity = 157 : db::get<domain::Tags::MeshVelocity<1, Frame::Inertial>>(*box); 158 : if (volume_mesh_velocity.has_value()) { 159 : ERROR("Subcell currently does not support moving mesh"); 160 : } 161 : 162 : std::optional<tnsr::I<DataVector, 1>> face_mesh_velocity{}; 163 : 164 : const auto& normal_covector_and_magnitude = 165 : db::get<evolution::dg::Tags::NormalCovectorAndMagnitude<1>>( 166 : *box); 167 : const auto& outward_directed_normal_covector = 168 : get<evolution::dg::Tags::NormalCovector<1>>( 169 : normal_covector_and_magnitude.at(direction).value()); 170 : const auto apply_fd_demand_outgoing_char_speeds = 171 : [&boundary_condition, &direction, &face_mesh_velocity, 172 : &ghost_data_vars, &outward_directed_normal_covector]( 173 : const auto&... boundary_ghost_data_args) { 174 : return (*boundary_condition) 175 : .fd_demand_outgoing_char_speeds( 176 : make_not_null( 177 : &get<Burgers::Tags::U>(ghost_data_vars)), 178 : direction, face_mesh_velocity, 179 : outward_directed_normal_covector, 180 : boundary_ghost_data_args...); 181 : }; 182 : apply_subcell_boundary_condition_impl( 183 : apply_fd_demand_outgoing_char_speeds, box, 184 : bcondition_interior_tags{}); 185 : 186 : return; 187 : } else { 188 : ERROR("Unsupported boundary condition " 189 : << pretty_type::short_name<BoundaryCondition>() 190 : << " when using finite-difference"); 191 : } 192 : }); 193 : 194 : // Put the computed ghost data into neighbor data with {direction, 195 : // ElementId::external_boundary_id()} as the mortar_id key 196 : const DirectionalId<1> mortar_id{direction, 197 : ElementId<1>::external_boundary_id()}; 198 : 199 : db::mutate<evolution::dg::subcell::Tags::GhostDataForReconstruction<1>>( 200 : [&mortar_id, &ghost_data_vars](auto ghost_data_ptr) { 201 : (*ghost_data_ptr)[mortar_id] = evolution::dg::subcell::GhostData{1}; 202 : DataVector& neighbor_data = 203 : ghost_data_ptr->at(mortar_id) 204 : .neighbor_ghost_data_for_reconstruction(); 205 : neighbor_data.destructive_resize(ghost_data_vars.size()); 206 : std::copy(get(get<Burgers::Tags::U>(ghost_data_vars)).begin(), 207 : get(get<Burgers::Tags::U>(ghost_data_vars)).end(), 208 : neighbor_data.begin()); 209 : }, 210 : box); 211 : } 212 : } 213 : } // namespace Burgers::fd