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