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/DataBox/MetavariablesTag.hpp"
13 : #include "DataStructures/DataVector.hpp"
14 : #include "DataStructures/Index.hpp"
15 : #include "DataStructures/Tensor/Tensor.hpp"
16 : #include "DataStructures/Variables.hpp"
17 : #include "Domain/BoundaryConditions/BoundaryCondition.hpp"
18 : #include "Domain/BoundaryConditions/None.hpp"
19 : #include "Domain/BoundaryConditions/Periodic.hpp"
20 : #include "Domain/Creators/Tags/ExternalBoundaryConditions.hpp"
21 : #include "Domain/Domain.hpp"
22 : #include "Domain/Structure/Direction.hpp"
23 : #include "Domain/Structure/DirectionMap.hpp"
24 : #include "Domain/Structure/Element.hpp"
25 : #include "Domain/Structure/ElementId.hpp"
26 : #include "Domain/Tags.hpp"
27 : #include "Domain/TagsTimeDependent.hpp"
28 : #include "Evolution/BoundaryConditions/Type.hpp"
29 : #include "Evolution/DgSubcell/GhostData.hpp"
30 : #include "Evolution/DgSubcell/Tags/GhostDataForReconstruction.hpp"
31 : #include "Evolution/DgSubcell/Tags/Mesh.hpp"
32 : #include "Evolution/DiscontinuousGalerkin/NormalVectorTags.hpp"
33 : #include "Evolution/Systems/Burgers/BoundaryConditions/BoundaryCondition.hpp"
34 : #include "Evolution/Systems/Burgers/FiniteDifference/Reconstructor.hpp"
35 : #include "Evolution/Systems/Burgers/System.hpp"
36 : #include "Evolution/Systems/Burgers/Tags.hpp"
37 : #include "NumericalAlgorithms/Spectral/Mesh.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
|