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 <string>
8 :
9 : #include "DataStructures/Index.hpp"
10 : #include "NumericalAlgorithms/Spectral/Basis.hpp"
11 : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
12 : #include "NumericalAlgorithms/Spectral/Quadrature.hpp"
13 : #include "Utilities/ErrorHandling/Assert.hpp"
14 :
15 : /// \cond
16 : template <size_t Dim>
17 : class Mesh;
18 : template <size_t Dim>
19 : class Index;
20 : /// \endcond
21 :
22 : namespace evolution::dg::subcell::fd {
23 : /*!
24 : * \brief Returns `true` if the DG mesh has a topology compatible with
25 : * switching to subcell (finite-difference).
26 : *
27 : * Only meshes using Legendre, Chebyshev, or Cartoon bases are compatible.
28 : * Non-hypercube topologies (e.g., ZernikeB3 for filled balls) return `false`.
29 : */
30 : template <size_t Dim>
31 1 : bool dg_mesh_supports_subcell(const Mesh<Dim>& dg_mesh);
32 :
33 : /*!
34 : * \brief Computes the cell-centered finite-difference mesh from the DG mesh,
35 : * using \f$2N-1\f$ grid points per dimension, where \f$N\f$ is the degree of
36 : * the DG basis.
37 : *
38 : * If the DG mesh uses a basis that is not compatible with subcell (i.e.,
39 : * `dg_mesh_supports_subcell()` returns `false`), the returned mesh is
40 : * uninitialized (`{0_st, Basis::Uninitialized, Quadrature::Uninitialized}`).
41 : * The uninitialized mesh should never be used for actual subcell computations.
42 : */
43 : template <size_t Dim>
44 1 : Mesh<Dim> mesh(const Mesh<Dim>& dg_mesh);
45 :
46 : /*!
47 : * \brief Computes the DG mesh from the cell-centered finite-difference mesh.
48 : */
49 : template <size_t Dim>
50 1 : Mesh<Dim> dg_mesh(const Mesh<Dim>& subcell_mesh, Spectral::Basis basis,
51 : Spectral::Quadrature quadrature);
52 :
53 : /*!
54 : * \brief Computes the computational dimension from the subcell mesh, which
55 : * can be less than `Dim` when Cartoon bases are used.
56 : */
57 : template <size_t Dim>
58 1 : size_t get_computational_dim(const Mesh<Dim>& subcell_mesh) {
59 : if constexpr (Dim == 3) {
60 : if (subcell_mesh.quadrature(2) == Spectral::Quadrature::SphericalSymmetry) {
61 : return 1;
62 : } else if (subcell_mesh.quadrature(2) ==
63 : Spectral::Quadrature::AxialSymmetry) {
64 : return 2;
65 : } else {
66 : return 3;
67 : }
68 : } else {
69 : return Dim;
70 : }
71 : }
72 :
73 : /*!
74 : * \brief Computes the computational dimension from the subcell extents, which
75 : * can be less than `Dim` when Cartoon bases are used.
76 : */
77 : template <size_t Dim>
78 1 : size_t get_computational_dim(const Index<Dim>& subcell_extents) {
79 : if constexpr (Dim == 3) {
80 : if (subcell_extents[1] == 1) {
81 : return 1;
82 : } else if (subcell_extents[2] == 1) {
83 : return 2;
84 : } else {
85 : return 3;
86 : }
87 : } else {
88 : return Dim;
89 : }
90 : }
91 :
92 : /*!
93 : * \brief Verifies the passed subcell mesh is valid, i.e. properly using
94 : * Cartoon bases and isotropic in non-Cartoon extents.
95 : *
96 : * The \p neighbor argument should be set to `true` when checking a neighbor's
97 : * mesh (only the output of the assert is modified).
98 : */
99 : template <size_t Dim>
100 1 : void verify_subcell_mesh(const Mesh<Dim>& subcell_mesh, bool neighbor = false);
101 :
102 : /*!
103 : * \brief Verifies the passed subcell extents are valid, i.e. fully isotropic
104 : * or deviating in a Cartoon-specific manner.
105 : *
106 : * The \p neighbor argument should be set to `true` when checking a neighbor's
107 : * mesh (only the output of the assert is modified).
108 : */
109 : template <size_t Dim>
110 1 : void verify_subcell_extents(const Index<Dim>& subcell_extents,
111 : bool neighbor = false) {
112 : const std::string neighbor_str = neighbor ? " neighbor" : "";
113 : if constexpr (Dim == 3) {
114 : if (subcell_extents[1] == 1) {
115 : // Checking for spherical symmetry
116 : ASSERT(
117 : subcell_extents[0] != 1 and subcell_extents[2] == 1,
118 : "The" << neighbor_str
119 : << " subcell extents are neither isotropic nor a valid cartoon "
120 : "pattern, got "
121 : << subcell_extents);
122 : } else if (subcell_extents[2] == 1) {
123 : // Checking for axial symmetry
124 : ASSERT(
125 : subcell_extents.slice_away(2) == Index<2>(subcell_extents[0]),
126 : "The" << neighbor_str
127 : << " subcell extents are neither isotropic nor a valid cartoon "
128 : "pattern, got "
129 : << subcell_extents);
130 : } else {
131 : // No cartoon, normal extents
132 : ASSERT(subcell_extents == Index<Dim>(subcell_extents[0]),
133 : "The" << neighbor_str << " subcell mesh must be uniform but is "
134 : << subcell_extents);
135 : }
136 : } else {
137 : ASSERT(subcell_extents == Index<Dim>(subcell_extents[0]),
138 : "The" << neighbor_str << " subcell mesh must be uniform but is "
139 : << subcell_extents);
140 : }
141 : }
142 : } // namespace evolution::dg::subcell::fd
|