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 `HalfFourier` for a dimension that is spatially periodic and in
49 : * which the expected solution is smooth and each tensor component has a
50 : * definite parity, i.e. and be expanded purely in terms of either sines or
51 : * cosines. A Mesh with this Basis cannot be split by h-refinement in this
52 : * dimension.
53 : *
54 : * \note Choose two consecutive dimensions to have `SphericalHarmonic` to choose
55 : * a spherical harmonic basis. By convention, the first dimension represents
56 : * the polar/zenith angle (or colatitude), while the second dimension represents
57 : * the azimuthal angle (or longitude). A Mesh with this Basis cannot be split
58 : * by h-refinement in these dimensions.
59 : *
60 : * \note Choose two consecutive dimensions to have `ZernikeB2` to choose
61 : * a basis used on a disk or cross-section of a cylinder. By convention, the
62 : * first dimension represents the radial direction, while the second dimension
63 : * represents the azimuthal angle. A Mesh with this Basis cannot be split by
64 : * h-refinement in these dimensions.
65 : *
66 : * \note Choose three consecutive dimensions to have `ZernikeB3` to choose
67 : * a basis used on a sphere. By convention, the first dimension represents the
68 : * radial direction, the second dimension represents the polar/zenith angle (or
69 : * colatitude), while the third dimension represents the azimuthal angle (or
70 : * longitude). A Mesh with this Basis cannot be split by h-refinement in these
71 : * dimensions.
72 : *
73 : * \note Choose `Cartoon` for a dimension (or consecutive dimensions) that
74 : * represent axial (or spherical) symmetry.
75 : *
76 : * \remark We store these effectively as a 4-bit integer using the highest 4
77 : * bits of a uint8_t, which is why we do the left shift. We cannot have more
78 : * than 16 bases to fit into the 4 bits, including the `Uninitialized` value.
79 : * The number of bits to shift is encoded in the variable
80 : * `Spectral::detail::basis_shift`.
81 : */
82 0 : enum class Basis : uint8_t {
83 : Uninitialized = 0 << basis_shift,
84 : Chebyshev = 1 << basis_shift,
85 : Legendre = 2 << basis_shift,
86 : FiniteDifference = 3 << basis_shift,
87 : SphericalHarmonic = 4 << basis_shift,
88 : Fourier = 5 << basis_shift,
89 : ZernikeB1 = 6 << basis_shift,
90 : ZernikeB2 = 7 << basis_shift,
91 : ZernikeB3 = 8 << basis_shift,
92 : Cartoon = 9 << basis_shift,
93 : HalfFourier = 10 << basis_shift
94 : };
95 :
96 : /// All possible values of Basis
97 1 : std::array<Basis, 11> all_bases();
98 :
99 : /// Convert a string to a Basis enum.
100 1 : Basis to_basis(const std::string& basis);
101 :
102 : /// Output operator for a Basis.
103 1 : std::ostream& operator<<(std::ostream& os, const Basis& basis);
104 :
105 : /// Shortcuts for common Basis products where the default for I1Basis is
106 : /// Basis::Legendre
107 1 : namespace bases {
108 : template <size_t VolumeDim, Basis I1Basis = Basis::Legendre>
109 0 : static constexpr auto hypercube = make_array<VolumeDim>(Basis::Legendre);
110 :
111 : template <size_t VolumeDim>
112 0 : static constexpr auto hypertorus = make_array<VolumeDim>(Basis::Fourier);
113 :
114 : template <Basis I1Basis = Basis::Legendre>
115 0 : static constexpr auto annulus = std::array{I1Basis, Basis::Fourier};
116 :
117 0 : static constexpr auto spherical_surface =
118 : make_array<2>(Basis::SphericalHarmonic);
119 :
120 0 : static constexpr auto disk = make_array<2>(Basis::ZernikeB2);
121 :
122 : template <Basis I1Basis = Basis::Legendre>
123 0 : static constexpr auto spherical_shell =
124 : std::array{I1Basis, Basis::SphericalHarmonic, Basis::SphericalHarmonic};
125 :
126 : template <Basis I1Basis = Basis::Legendre>
127 0 : static constexpr auto cylindrical_shell =
128 : std::array{I1Basis, Basis::Fourier, I1Basis};
129 :
130 : template <Basis I1Basis = Basis::Legendre>
131 0 : static constexpr auto full_cylinder =
132 : std::array{Basis::ZernikeB2, Basis::ZernikeB2, I1Basis};
133 :
134 0 : static constexpr auto full_sphere = make_array<3>(Basis::ZernikeB3);
135 :
136 : template <Basis I1Basis = Basis::Legendre>
137 0 : static constexpr auto cartoon_sphere =
138 : std::array{I1Basis, Basis::Cartoon, Basis::Cartoon};
139 :
140 0 : static constexpr auto cartoon_sphere_inner =
141 : std::array{Basis::ZernikeB1, Basis::Cartoon, Basis::Cartoon};
142 :
143 : template <Basis I1Basis = Basis::Legendre>
144 0 : static constexpr auto cartoon_cylinder =
145 : std::array{I1Basis, I1Basis, Basis::Cartoon};
146 :
147 : template <Basis I1Basis = Basis::Legendre>
148 0 : static constexpr auto cartoon_cylinder_inner =
149 : std::array{Basis::ZernikeB1, I1Basis, Basis::Cartoon};
150 : } // namespace bases
151 : } // namespace Spectral
152 :
153 : template <>
154 0 : struct Options::create_from_yaml<Spectral::Basis> {
155 : template <typename Metavariables>
156 0 : static Spectral::Basis create(const Options::Option& options) {
157 : return create<void>(options);
158 : }
159 : };
160 :
161 : template <>
162 0 : Spectral::Basis Options::create_from_yaml<Spectral::Basis>::create<void>(
163 : const Options::Option& options);
|