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 <unordered_set> 10 : #include <utility> 11 : 12 : #include "DataStructures/DataBox/DataBox.hpp" 13 : #include "DataStructures/DataVector.hpp" 14 : #include "DataStructures/Variables.hpp" 15 : #include "Domain/BoundaryConditions/BoundaryCondition.hpp" 16 : #include "Domain/BoundaryConditions/None.hpp" 17 : #include "Domain/BoundaryConditions/Periodic.hpp" 18 : #include "Domain/Creators/Tags/ExternalBoundaryConditions.hpp" 19 : #include "Domain/Domain.hpp" 20 : #include "Domain/Structure/Direction.hpp" 21 : #include "Domain/Structure/Element.hpp" 22 : #include "Domain/Structure/ElementId.hpp" 23 : #include "Domain/Tags.hpp" 24 : #include "Domain/TagsTimeDependent.hpp" 25 : #include "Evolution/BoundaryConditions/Type.hpp" 26 : #include "Evolution/DgSubcell/Tags/GhostDataForReconstruction.hpp" 27 : #include "Evolution/DgSubcell/Tags/Mesh.hpp" 28 : #include "Evolution/DiscontinuousGalerkin/NormalVectorTags.hpp" 29 : #include "Evolution/Systems/GrMhd/GhValenciaDivClean/BoundaryConditions/BoundaryCondition.hpp" 30 : #include "Evolution/Systems/GrMhd/GhValenciaDivClean/BoundaryConditions/Factory.hpp" 31 : #include "Evolution/Systems/GrMhd/GhValenciaDivClean/FiniteDifference/Reconstructor.hpp" 32 : #include "Evolution/Systems/GrMhd/GhValenciaDivClean/System.hpp" 33 : #include "Evolution/Systems/GrMhd/GhValenciaDivClean/Tags.hpp" 34 : #include "NumericalAlgorithms/Spectral/Mesh.hpp" 35 : #include "Parallel/Tags/Metavariables.hpp" 36 : #include "PointwiseFunctions/GeneralRelativity/Tags.hpp" 37 : #include "PointwiseFunctions/Hydro/Tags.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 grmhd::GhValenciaDivClean::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. Otherwise this 54 : * function would be never called. 55 : * 56 : */ 57 1 : struct BoundaryConditionGhostData { 58 : template <typename DbTagsList> 59 0 : static void apply(gsl::not_null<db::DataBox<DbTagsList>*> box, 60 : const Element<3>& element, 61 : const Reconstructor& reconstructor); 62 : 63 : private: 64 : template <typename FdBoundaryConditionHelper, typename DbTagsList, 65 : typename... FdBoundaryConditionArgsTags> 66 : // A helper function for calling fd_ghost() of BoundaryCondition subclasses 67 0 : static void apply_subcell_boundary_condition_impl( 68 : FdBoundaryConditionHelper& fd_boundary_condition_helper, 69 : const gsl::not_null<db::DataBox<DbTagsList>*>& box, 70 : tmpl::list<FdBoundaryConditionArgsTags...>) { 71 : return fd_boundary_condition_helper( 72 : db::get<FdBoundaryConditionArgsTags>(*box)...); 73 : } 74 : }; 75 : 76 : template <typename DbTagsList> 77 0 : void BoundaryConditionGhostData::apply( 78 : const gsl::not_null<db::DataBox<DbTagsList>*> box, 79 : const Element<3>& element, const Reconstructor& reconstructor) { 80 : const auto& external_boundary_condition = 81 : db::get<domain::Tags::ExternalBoundaryConditions<3>>(*box).at( 82 : element.id().block_id()); 83 : 84 : // Check if the element is on the external boundary. If not, the caller is 85 : // doing something wrong (e.g. trying to compute FD ghost data with boundary 86 : // conditions at an element which is not on the external boundary). 87 : ASSERT(not element.external_boundaries().empty(), 88 : "The element (ID : " << element.id() 89 : << ") is not on external boundaries"); 90 : 91 : const Mesh<3> subcell_mesh = 92 : db::get<evolution::dg::subcell::Tags::Mesh<3>>(*box); 93 : 94 : const size_t ghost_zone_size{reconstructor.ghost_zone_size()}; 95 : 96 : // Tags and tags list for FD reconstruction 97 : using RestMassDensity = hydro::Tags::RestMassDensity<DataVector>; 98 : using ElectronFraction = hydro::Tags::ElectronFraction<DataVector>; 99 : using Temperature = hydro::Tags::Temperature<DataVector>; 100 : using LorentzFactorTimesSpatialVelocity = 101 : hydro::Tags::LorentzFactorTimesSpatialVelocity<DataVector, 3>; 102 : using MagneticField = hydro::Tags::MagneticField<DataVector, 3>; 103 : using DivergenceCleaningField = 104 : hydro::Tags::DivergenceCleaningField<DataVector>; 105 : using SpacetimeMetric = gr::Tags::SpacetimeMetric<DataVector, 3>; 106 : using Pi = gh::Tags::Pi<DataVector, 3>; 107 : using Phi = gh::Tags::Phi<DataVector, 3>; 108 : 109 : using reconstruction_tags = GhValenciaDivClean::Tags:: 110 : primitive_grmhd_and_spacetime_reconstruction_tags; 111 : using NeighborVariables = Variables<reconstruction_tags>; 112 : constexpr size_t number_of_tensor_components = 113 : NeighborVariables::number_of_independent_components; 114 : 115 : for (const auto& direction : element.external_boundaries()) { 116 : const auto& boundary_condition_at_direction = 117 : *external_boundary_condition.at(direction); 118 : 119 : const size_t num_face_pts{ 120 : subcell_mesh.extents().slice_away(direction.dimension()).product()}; 121 : 122 : // Allocate a vector to store the computed FD ghost data and assign a 123 : // non-owning Variables on it. 124 : auto& all_ghost_data = db::get_mutable_reference< 125 : evolution::dg::subcell::Tags::GhostDataForReconstruction<3>>(box); 126 : // Put the computed ghost data into neighbor data with {direction, 127 : // ElementId::external_boundary_id()} as the mortar_id key 128 : const DirectionalId<3> mortar_id{direction, 129 : ElementId<3>::external_boundary_id()}; 130 : all_ghost_data[mortar_id] = evolution::dg::subcell::GhostData{1}; 131 : DataVector& boundary_ghost_data = 132 : all_ghost_data.at(mortar_id).neighbor_ghost_data_for_reconstruction(); 133 : boundary_ghost_data.destructive_resize(number_of_tensor_components * 134 : ghost_zone_size * num_face_pts); 135 : Variables<reconstruction_tags> ghost_data_vars{boundary_ghost_data.data(), 136 : boundary_ghost_data.size()}; 137 : 138 : // We don't need to care about boundary ghost data when using the periodic 139 : // condition, so exclude it from the type list 140 : using factory_classes = 141 : typename std::decay_t<decltype(db::get<Parallel::Tags::Metavariables>( 142 : *box))>::factory_creation::factory_classes; 143 : using derived_boundary_conditions_for_subcell = tmpl::remove_if< 144 : tmpl::at<factory_classes, typename System::boundary_conditions_base>, 145 : tmpl::or_< 146 : std::is_base_of<domain::BoundaryConditions::MarkAsPeriodic, 147 : tmpl::_1>, 148 : std::is_base_of<domain::BoundaryConditions::MarkAsNone, tmpl::_1>>>; 149 : 150 : // Now apply subcell boundary conditions 151 : call_with_dynamic_type<void, derived_boundary_conditions_for_subcell>( 152 : &boundary_condition_at_direction, 153 : [&box, &direction, &ghost_data_vars](const auto* boundary_condition) { 154 : using BoundaryCondition = std::decay_t<decltype(*boundary_condition)>; 155 : using bcondition_interior_evolved_vars_tags = 156 : typename BoundaryCondition::fd_interior_evolved_variables_tags; 157 : using bcondition_interior_temporary_tags = 158 : typename BoundaryCondition::fd_interior_temporary_tags; 159 : using bcondition_interior_primitive_vars_tags = 160 : typename BoundaryCondition::fd_interior_primitive_variables_tags; 161 : using bcondition_gridless_tags = 162 : typename BoundaryCondition::fd_gridless_tags; 163 : 164 : using bcondition_interior_tags = 165 : tmpl::append<bcondition_interior_evolved_vars_tags, 166 : bcondition_interior_temporary_tags, 167 : bcondition_interior_primitive_vars_tags, 168 : bcondition_gridless_tags>; 169 : 170 : if constexpr (BoundaryCondition::bc_type == 171 : evolution::BoundaryConditions::Type::Ghost or 172 : BoundaryCondition::bc_type == 173 : evolution::BoundaryConditions::Type:: 174 : GhostAndTimeDerivative) { 175 : const auto apply_fd_ghost = 176 : [&boundary_condition, &direction, 177 : &ghost_data_vars](const auto&... boundary_ghost_data_args) { 178 : (*boundary_condition) 179 : .fd_ghost( 180 : make_not_null(&get<SpacetimeMetric>(ghost_data_vars)), 181 : make_not_null(&get<Pi>(ghost_data_vars)), 182 : make_not_null(&get<Phi>(ghost_data_vars)), 183 : make_not_null(&get<RestMassDensity>(ghost_data_vars)), 184 : make_not_null( 185 : &get<ElectronFraction>(ghost_data_vars)), 186 : make_not_null(&get<Temperature>(ghost_data_vars)), 187 : make_not_null(&get<LorentzFactorTimesSpatialVelocity>( 188 : ghost_data_vars)), 189 : make_not_null(&get<MagneticField>(ghost_data_vars)), 190 : make_not_null( 191 : &get<DivergenceCleaningField>(ghost_data_vars)), 192 : direction, boundary_ghost_data_args...); 193 : }; 194 : apply_subcell_boundary_condition_impl(apply_fd_ghost, box, 195 : bcondition_interior_tags{}); 196 : } else { 197 : ERROR("Unsupported boundary condition " 198 : << pretty_type::short_name<BoundaryCondition>() 199 : << " when using finite-difference"); 200 : } 201 : }); 202 : } 203 : } 204 : } // namespace grmhd::GhValenciaDivClean::fd