Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <array> 7 : #include <cstdint> 8 : #include <iosfwd> 9 : #include <string> 10 : 11 : #include "Utilities/MakeArray.hpp" 12 : 13 : /// \cond 14 : namespace Options { 15 : class Option; 16 : template <typename T> 17 : struct create_from_yaml; 18 : } // namespace Options 19 : /// \endcond 20 : 21 : namespace Spectral { 22 : /// \brief The amount we left-shift the basis integers by. 23 : /// 24 : /// We do this to be able to represent the combined Basis and Quadrature as one 25 : /// 8-bit integer. 26 1 : constexpr uint8_t basis_shift = 4; 27 : /*! 28 : * \brief Either the basis functions used by a spectral or discontinuous 29 : * Galerkin (DG) method, or the value `FiniteDifference` when a finite 30 : * difference method is used 31 : * 32 : * \details The particular choices of Basis and Quadrature determine where the 33 : * collocation points of a Mesh are located in an Element. For a spectral or DG 34 : * method, the Basis also represents the choice of basis functions used to 35 : * represent a function on an Element, which then provides a convenient choice 36 : * for the operators used for differentiation, interpolation, etc. For a finite 37 : * difference method, one needs to choose the order of the scheme (and hence the 38 : * weights, differentiation matrix, integration weights, and interpolant) 39 : * locally in space and time to handle discontinuous solutions. 40 : * 41 : * \note Choose `Legendre` for a general-purpose spectral or DG mesh, unless 42 : * you have a particular reason for choosing `Chebyshev`. 43 : * 44 : * \note Choose `Fourier` for a dimension that is spatially periodic and in 45 : * which the expected solution is smooth. A Mesh with this Basis cannot be 46 : * split by h-refinement in this dimension. 47 : * 48 : * \note Choose two consecutive dimensions to have `SphericalHarmonic` to choose 49 : * a spherical harmonic basis. By convention, the first dimension represents 50 : * the polar/zenith angle (or colatitude), while the second dimension represents 51 : * the azimuthal angle (or longitude). A Mesh with this Basis cannot be split 52 : * by h-refinement in these dimensions. 53 : * 54 : * \note Choose two consecutive dimensions to have `ZernikeB2` to choose 55 : * a basis used on a disk or cross-section of a cylinder. By convention, the 56 : * first dimension represents the radial direction, while the second dimension 57 : * represents the azimuthal angle. A Mesh with this Basis cannot be split by 58 : * h-refinement in these dimensions. 59 : * 60 : * \note Choose three consecutive dimensions to have `ZernikeB3` to choose 61 : * a basis used on a sphere. By convention, the first dimension represents the 62 : * radial direction, the second dimension represents the polar/zenith angle (or 63 : * colatitude), while the third dimension represents the azimuthal angle (or 64 : * longitude). A Mesh with this Basis cannot be split by h-refinement in these 65 : * dimensions. 66 : * 67 : * \note Choose `Cartoon` for a dimension (or consecutive dimensions) that 68 : * represent axial (or spherical) symmetry. 69 : * 70 : * \remark We store these effectively as a 4-bit integer using the highest 4 71 : * bits of a uint8_t, which is why we do the left shift. We cannot have more 72 : * than 16 bases to fit into the 4 bits, including the `Uninitialized` value. 73 : * The number of bits to shift is encoded in the variable 74 : * `Spectral::detail::basis_shift`. 75 : */ 76 0 : enum class Basis : uint8_t { 77 : Uninitialized = 0 << basis_shift, 78 : Chebyshev = 1 << basis_shift, 79 : Legendre = 2 << basis_shift, 80 : FiniteDifference = 3 << basis_shift, 81 : SphericalHarmonic = 4 << basis_shift, 82 : Fourier = 5 << basis_shift, 83 : ZernikeB1 = 6 << basis_shift, 84 : ZernikeB2 = 7 << basis_shift, 85 : ZernikeB3 = 8 << basis_shift, 86 : Cartoon = 9 << basis_shift 87 : }; 88 : 89 : /// All possible values of Basis 90 1 : std::array<Basis, 10> all_bases(); 91 : 92 : /// Convert a string to a Basis enum. 93 1 : Basis to_basis(const std::string& basis); 94 : 95 : /// Output operator for a Basis. 96 1 : std::ostream& operator<<(std::ostream& os, const Basis& basis); 97 : 98 : /// Shortcuts for common Basis products where the default for I1Basis is 99 : /// Basis::Legendre 100 1 : namespace bases { 101 : template <size_t VolumeDim, Basis I1Basis = Basis::Legendre> 102 0 : static constexpr auto hypercube = make_array<VolumeDim>(Basis::Legendre); 103 : 104 : template <size_t VolumeDim> 105 0 : static constexpr auto hypertorus = make_array<VolumeDim>(Basis::Fourier); 106 : 107 : template <Basis I1Basis = Basis::Legendre> 108 0 : static constexpr auto annulus = std::array{I1Basis, Basis::Fourier}; 109 : 110 0 : static constexpr auto spherical_surface = 111 : make_array<2>(Basis::SphericalHarmonic); 112 : 113 0 : static constexpr auto disk = make_array<2>(Basis::ZernikeB2); 114 : 115 : template <Basis I1Basis = Basis::Legendre> 116 0 : static constexpr auto spherical_shell = 117 : std::array{I1Basis, Basis::SphericalHarmonic, Basis::SphericalHarmonic}; 118 : 119 : template <Basis I1Basis = Basis::Legendre> 120 0 : static constexpr auto cylindrical_shell = 121 : std::array{I1Basis, Basis::Fourier, I1Basis}; 122 : 123 : template <Basis I1Basis = Basis::Legendre> 124 0 : static constexpr auto full_cylinder = 125 : std::array{Basis::ZernikeB2, Basis::ZernikeB2, I1Basis}; 126 : 127 0 : static constexpr auto full_sphere = make_array<3>(Basis::ZernikeB3); 128 : 129 : template <Basis I1Basis = Basis::Legendre> 130 0 : static constexpr auto cartoon_sphere = 131 : std::array{I1Basis, Basis::Cartoon, Basis::Cartoon}; 132 : 133 0 : static constexpr auto cartoon_sphere_inner = 134 : std::array{Basis::ZernikeB1, Basis::Cartoon, Basis::Cartoon}; 135 : 136 : template <Basis I1Basis = Basis::Legendre> 137 0 : static constexpr auto cartoon_cylinder = 138 : std::array{I1Basis, I1Basis, Basis::Cartoon}; 139 : 140 : template <Basis I1Basis = Basis::Legendre> 141 0 : static constexpr auto cartoon_cylinder_inner = 142 : std::array{Basis::ZernikeB1, I1Basis, Basis::Cartoon}; 143 : } // namespace bases 144 : } // namespace Spectral 145 : 146 : template <> 147 0 : struct Options::create_from_yaml<Spectral::Basis> { 148 : template <typename Metavariables> 149 0 : static Spectral::Basis create(const Options::Option& options) { 150 : return create<void>(options); 151 : } 152 : }; 153 : 154 : template <> 155 0 : Spectral::Basis Options::create_from_yaml<Spectral::Basis>::create<void>( 156 : const Options::Option& options);