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 <optional>
8 :
9 : #include "Utilities/Gsl.hpp"
10 :
11 : /// \cond
12 : class DataVector;
13 : class Matrix;
14 : template <size_t>
15 : class Mesh;
16 : template <typename TagsList>
17 : class Variables;
18 : /// \endcond
19 :
20 : namespace Spectral::filtering {
21 : /*!
22 : * \brief Filters the tensors stored within a `Variables` being represented by
23 : * ZernikeB2 basis functions, with an optional exponential roll-off and an
24 : * optional top-mode cutoff.
25 : *
26 : * \details Representing functions on a filled disk requires special basis
27 : * functions, namely ZernikeB2. These are inherently two-dimensional, meaning
28 : * the radial and angular spectral spaces are intertwined. This function goes
29 : * to that combined modal space, applies the filter, and transforms back.
30 : *
31 : * When `half_power` has a value, a smooth exponential roll-off (see
32 : * exponential_filter()) is applied to the combined radial-angular modes using
33 : * the coefficient `alpha`. When `num_modes_to_kill` is nonzero, the highest
34 : * `num_modes_to_kill` angular (Fourier \f$m\f$) modes are additionally set to
35 : * zero, with the \f$m=0\f$ mode always retained. If `half_power` is
36 : * `std::nullopt` and `num_modes_to_kill` is zero this function is a no-op.
37 : *
38 : * \see exponential_filter()
39 : */
40 : template <typename TagsList>
41 1 : void zernike_b2_disk_filter(gsl::not_null<Variables<TagsList>*> u,
42 : const Mesh<2>& mesh, double alpha,
43 : std::optional<unsigned> half_power,
44 : size_t num_modes_to_kill);
45 :
46 : /*!
47 : * \brief Filters the tensors stored within a `Variables` being represented by
48 : * ZernikeB2 basis functions, with an optional exponential roll-off and an
49 : * optional top-mode cutoff.
50 : *
51 : * \details Overload taking a caller-managed working buffer. Avoids heap
52 : * allocation when the filter is applied repeatedly (e.g. in
53 : * `Filters::FilledCylinder`).
54 : */
55 : template <typename TagsList>
56 1 : void zernike_b2_disk_filter(gsl::not_null<Variables<TagsList>*> u,
57 : gsl::not_null<DataVector*> buf, const Mesh<2>& mesh,
58 : double alpha, std::optional<unsigned> half_power,
59 : size_t num_modes_to_kill);
60 :
61 : /*!
62 : * \brief Filters the tensors stored within a `Variables` being represented by
63 : * ZernikeB2 basis functions.
64 : *
65 : * \details Equivalent to `zernike_b2_disk_filter()` with `half_power` set and
66 : * no top-mode cutoff. Kept for callers that only want the exponential filter.
67 : *
68 : * \see exponential_filter()
69 : */
70 : template <typename TagsList>
71 1 : void zernike_b2_disk_exponential_filter(gsl::not_null<Variables<TagsList>*> u,
72 : const Mesh<2>& mesh, double alpha,
73 : unsigned half_power);
74 :
75 : /*!
76 : * \brief Filters the tensors stored within a `Variables` being represented by
77 : * ZernikeB2 \f$\times\f$ Legendre basis functions, with optional independent
78 : * roll-offs for the combined radial-angular disk modes and the axial \f$z\f$
79 : * modes plus an optional angular top-mode cutoff.
80 : *
81 : * \details Representing functions on a filled cylinder requires special basis
82 : * functions, namely a filled disk with ZernikeB2 cross Legendre. This requires
83 : * inherently two-dimensional basis functions, meaning the radial and angular
84 : * spectral spaces are intertwined. This function goes to that combined modal
85 : * space, applies the disk filter, transforms back, and then filters the third
86 : * I1 dimension.
87 : *
88 : * The combined radial-angular (disk) modes are filtered with an exponential
89 : * roll-off when `radial_angular_half_power` has a value and with a top-mode
90 : * cutoff of the highest `num_modes_to_kill` angular (Fourier \f$m\f$) modes
91 : * when `num_modes_to_kill` is nonzero (the \f$m=0\f$ mode is always retained).
92 : * The axial \f$z\f$ direction is filtered with an independent exponential
93 : * roll-off when `z_half_power` has a value. The coefficient `alpha` is shared
94 : * by all exponential roll-offs. Any direction whose half-power is
95 : * `std::nullopt` (and, for the disk, with `num_modes_to_kill` zero) is left
96 : * untouched.
97 : *
98 : * While the radial-angular plane is fixed to ZernikeB2 \f$\times\f$ Fourier,
99 : * the axial \f$z\f$ filter is applied with exponential_filter() in whatever 1D
100 : * spectral basis the mesh uses in the \f$z\f$ direction, so both Legendre and
101 : * Chebyshev (with any quadrature) are supported there.
102 : *
103 : * \see exponential_filter()
104 : */
105 : template <typename TagsList>
106 1 : void zernike_b2_cylinder_filter(
107 : gsl::not_null<Variables<TagsList>*> u, const Mesh<3>& mesh, double alpha,
108 : std::optional<unsigned> radial_angular_half_power,
109 : std::optional<unsigned> z_half_power, size_t num_modes_to_kill);
110 :
111 : /*!
112 : * \brief Filters the tensors stored within a `Variables` being represented by
113 : * ZernikeB2 \f$\times\f$ Legendre basis functions, with optional independent
114 : * roll-offs for the combined radial-angular disk modes and the axial \f$z\f$
115 : * modes plus an optional angular top-mode cutoff.
116 : *
117 : * \details Overload taking a caller-managed working buffer. Avoids heap
118 : * allocation when the filter is applied repeatedly (e.g. in
119 : * `Filters::FilledCylinder`). One can optionally pass the exponential filter
120 : * to apply in the z direction, otherwise it will be computed.
121 : *
122 : */
123 : template <typename TagsList>
124 1 : void zernike_b2_cylinder_filter(
125 : gsl::not_null<Variables<TagsList>*> u, gsl::not_null<DataVector*> buf,
126 : const Mesh<3>& mesh, double alpha,
127 : std::optional<unsigned> radial_angular_half_power,
128 : std::optional<unsigned> z_half_power, size_t num_modes_to_kill,
129 : const std::optional<Matrix>& z_filter);
130 :
131 : /*!
132 : * \brief Filters the tensors stored within a `Variables` being represented by
133 : * ZernikeB2 \f$\times\f$ Legendre basis functions.
134 : *
135 : * \details Equivalent to `zernike_b2_cylinder_filter()` with both the disk and
136 : * axial half-powers set to `half_power` and no top-mode cutoff. Kept for
137 : * callers that only want a single exponential filter applied everywhere.
138 : *
139 : * \see exponential_filter()
140 : */
141 : template <typename TagsList>
142 1 : void zernike_b2_cylinder_exponential_filter(
143 : gsl::not_null<Variables<TagsList>*> u, const Mesh<3>& mesh, double alpha,
144 : unsigned half_power);
145 : } // namespace Spectral::filtering
|