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 <memory>
8 : #include <optional>
9 : #include <string>
10 :
11 : #include "DataStructures/DataVector.hpp"
12 : #include "DataStructures/Tensor/TypeAliases.hpp"
13 : #include "Evolution/BoundaryConditions/Type.hpp"
14 : #include "Evolution/Systems/SecondOrderScalarWave/BoundaryConditions/BoundaryCondition.hpp"
15 : #include "Evolution/Systems/SecondOrderScalarWave/Tags.hpp"
16 : #include "Options/Auto.hpp"
17 : #include "Options/String.hpp"
18 : #include "PointwiseFunctions/InitialDataUtilities/InitialData.hpp"
19 : #include "Utilities/Gsl.hpp"
20 : #include "Utilities/Serialization/CharmPupable.hpp"
21 : #include "Utilities/TMPL.hpp" // IWYU pragma: keep
22 :
23 : /// \cond
24 : namespace PUP {
25 : class er;
26 : } // namespace PUP
27 : namespace Tags {
28 : struct Time;
29 : } // namespace Tags
30 : namespace domain::Tags {
31 : template <size_t Dim, typename Frame>
32 : struct Coordinates;
33 : } // namespace domain::Tags
34 : /// \endcond
35 :
36 : namespace SecondOrderScalarWave::BoundaryConditions {
37 : /*!
38 : * \brief Sets boundary conditions using the characteristic decomposition: the
39 : * incoming mode is set from analytic data, the outgoing and zero-speed modes
40 : * from the interior.
41 : *
42 : * If \f$n^i\f$ is the outward pointing unit normal at the external boundary,
43 : * the characteristic fields and their speeds are (see
44 : * `SecondOrderScalarWave::characteristic_fields`):
45 : * - \f$v^+ = \Pi + n^i\Phi_i\f$: speed \f$+1\f$ (outgoing, taken from the
46 : * interior)
47 : * - \f$v^- = \Pi - n^i\Phi_i\f$: speed \f$-1\f$ (incoming, taken from the
48 : * analytic data, or set to zero if `AnalyticPrescription` is
49 : * `ZeroIncomingMode`)
50 : * - \f$v^0_i\f$: speed \f$0\f$ (taken from the interior)
51 : *
52 : * The ghost \f$\Pi\f$ and \f$\Phi_i\f$ are reconstructed from these modes.
53 : * The ghost \f$\Psi\f$ by default is the boundary-evolved
54 : * `evolution::dg::Tags::BoundaryValue<Tags::Psi>`, integrated per face using
55 : * the interior evolution equation defined in `boundary_field_time_derivatives`.
56 : * If `CopyPsiFromInterior` is true the ghost \f$\Psi\f$ is instead the interior
57 : * evolved \f$\Psi\f$; the boundary value is still integrated but unused.
58 : *
59 : * Moving meshes are not supported: the characteristic speeds are defined
60 : * without a mesh velocity, so both member functions return an error if a face
61 : * mesh velocity is supplied.
62 : */
63 : template <size_t Dim>
64 1 : class DirichletCharacteristics final : public BoundaryCondition<Dim> {
65 : public:
66 : /// \brief Label for `AnalyticPrescription` setting the incoming
67 : /// characteristic mode \f$v^-\f$ to zero.
68 1 : struct ZeroIncomingMode {};
69 :
70 : /// \brief What analytic solution to prescribe.
71 1 : struct AnalyticPrescription {
72 0 : static constexpr Options::String help =
73 : "What analytic solution to prescribe, or ZeroIncomingMode to set the "
74 : "incoming characteristic mode to zero.";
75 0 : using type =
76 : Options::Auto<std::unique_ptr<evolution::initial_data::InitialData>,
77 : ZeroIncomingMode>;
78 : };
79 :
80 : /// \brief If true, the ghost Psi is copied from the interior
81 : /// instead of the boundary-evolved value.
82 1 : struct CopyPsiFromInterior {
83 0 : static constexpr Options::String help =
84 : "If true, ghost Psi is copied from the interior instead of the "
85 : "boundary-evolved value.";
86 0 : using type = bool;
87 : };
88 :
89 0 : using options = tmpl::list<AnalyticPrescription, CopyPsiFromInterior>;
90 :
91 0 : static constexpr Options::String help{
92 : "Analytic boundary condition using the characteristic decomposition. The "
93 : "incoming mode is set from analytic data, the outgoing and zero-speed "
94 : "modes copied from the interior. The evolved variable Pi and the "
95 : "auxiliary variable Phi are reconstructed from the characteristic modes. "
96 : "The ghost Psi is the boundary-evolved value if CopyPsiFromInterior is "
97 : "false. Otherwise, the ghost Psi is copied from the interior."};
98 :
99 0 : DirichletCharacteristics() = default;
100 0 : DirichletCharacteristics(DirichletCharacteristics&&) = default;
101 0 : DirichletCharacteristics& operator=(DirichletCharacteristics&&) = default;
102 0 : DirichletCharacteristics(const DirichletCharacteristics&);
103 0 : DirichletCharacteristics& operator=(const DirichletCharacteristics&);
104 0 : ~DirichletCharacteristics() override = default;
105 :
106 0 : DirichletCharacteristics(
107 : std::optional<std::unique_ptr<evolution::initial_data::InitialData>>
108 : analytic_prescription,
109 : bool copy_psi_from_interior);
110 :
111 0 : explicit DirichletCharacteristics(CkMigrateMessage* msg);
112 :
113 0 : WRAPPED_PUPable_decl_base_template( // NOLINT
114 : domain::BoundaryConditions::BoundaryCondition, DirichletCharacteristics);
115 :
116 0 : auto get_clone() const -> std::unique_ptr<
117 : domain::BoundaryConditions::BoundaryCondition> override;
118 :
119 0 : static constexpr evolution::BoundaryConditions::Type bc_type =
120 : evolution::BoundaryConditions::Type::Ghost;
121 :
122 0 : void pup(PUP::er& p) override;
123 :
124 0 : static constexpr bool evolves_boundary_variables = true;
125 :
126 0 : using dg_interior_evolved_variables_tags =
127 : tmpl::list<Tags::Psi, Tags::Pi, Tags::Phi<Dim>>;
128 0 : using dg_interior_temporary_tags =
129 : tmpl::list<domain::Tags::Coordinates<Dim, Frame::Inertial>>;
130 0 : using dg_gridless_tags = tmpl::list<::Tags::Time>;
131 :
132 0 : using boundary_field_time_derivatives_evolved_variables_tags =
133 : tmpl::list<Tags::Pi, Tags::Phi<Dim>>;
134 0 : using boundary_field_time_derivatives_temporary_tags =
135 : tmpl::list<domain::Tags::Coordinates<Dim, Frame::Inertial>>;
136 :
137 0 : std::optional<std::string> dg_ghost(
138 : gsl::not_null<Scalar<DataVector>*> psi,
139 : gsl::not_null<Scalar<DataVector>*> pi,
140 : gsl::not_null<tnsr::i<DataVector, Dim, Frame::Inertial>*> phi,
141 : const std::optional<tnsr::I<DataVector, Dim, Frame::Inertial>>&
142 : face_mesh_velocity,
143 : const tnsr::i<DataVector, Dim, Frame::Inertial>& normal_covector,
144 : const Scalar<DataVector>& boundary_psi,
145 : const Scalar<DataVector>& interior_psi,
146 : const Scalar<DataVector>& interior_pi,
147 : const tnsr::i<DataVector, Dim, Frame::Inertial>& interior_phi,
148 : const tnsr::I<DataVector, Dim, Frame::Inertial>& coords,
149 : double time) const;
150 :
151 0 : std::optional<std::string> boundary_field_time_derivatives(
152 : gsl::not_null<Scalar<DataVector>*> dt_boundary_psi,
153 : const std::optional<tnsr::I<DataVector, Dim, Frame::Inertial>>&
154 : face_mesh_velocity,
155 : const tnsr::i<DataVector, Dim, Frame::Inertial>& normal_covector,
156 : const Scalar<DataVector>& boundary_psi,
157 : const Scalar<DataVector>& interior_pi,
158 : const tnsr::i<DataVector, Dim, Frame::Inertial>& interior_phi,
159 : const tnsr::I<DataVector, Dim, Frame::Inertial>& coords,
160 : double time) const;
161 :
162 : private:
163 0 : std::unique_ptr<evolution::initial_data::InitialData> analytic_prescription_;
164 0 : bool copy_psi_from_interior_{false};
165 : };
166 : } // namespace SecondOrderScalarWave::BoundaryConditions
|