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