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 <cstddef>
8 :
9 : #include "DataStructures/DataVector.hpp"
10 : #include "DataStructures/Index.hpp"
11 : #include "DataStructures/Matrix.hpp"
12 : #include "DataStructures/Tensor/Tensor.hpp"
13 : #include "NumericalAlgorithms/Spectral/Basis.hpp"
14 : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
15 : #include "NumericalAlgorithms/Spectral/Parity.hpp"
16 : #include "NumericalAlgorithms/Spectral/ParityFromSymmetry.hpp"
17 : #include "Utilities/Gsl.hpp"
18 :
19 : namespace evolution::dg::subcell {
20 : namespace detail {
21 : template <size_t Dim>
22 : bool persson_tci_impl(
23 : gsl::not_null<DataVector*> filtered_component, const DataVector& component,
24 : const Mesh<Dim>& dg_mesh, double alpha, size_t num_highest_modes,
25 : Spectral::Parity parity = Spectral::Parity::Uninitialized);
26 : } // namespace detail
27 :
28 : /*!
29 : * \brief Troubled cell indicator using the idea of spectral falloff by
30 : * \cite Persson2006sub
31 : *
32 : * Consider a discontinuity sensing quantity \f$U\f$, which is typically a
33 : * scalar but could be a tensor of any rank. Let \f$U\f$ have the 1d spectral
34 : * decomposition (generalization to higher-dimensional tensor product bases is
35 : * done dimension-by-dimension):
36 : *
37 : * \f{align*}{
38 : * U(x)=\sum_{i=0}^{N}c_i P_i(x),
39 : * \f}
40 : *
41 : * where \f$P_i(x)\f$ are the basis functions, in our case the Legendre
42 : * polynomials, and \f$c_i\f$ are the spectral coefficients. We then define a
43 : * filtered solution \f$\hat{U}\f$ as
44 : *
45 : * \f{align*}{
46 : * \hat{U}(x)=\sum_{i=N+1-M}^{N} c_i P_i(x).
47 : * \f}
48 : *
49 : * where $M$ is the number of highest modes to include in the filtered solution.
50 : *
51 : * Note that when an exponential filter is being used to deal with aliasing,
52 : * lower modes can be included in \f$\hat{U}\f$. The main goal of \f$\hat{U}\f$
53 : * is to measure how much power is in the highest modes, which are the modes
54 : * responsible for Gibbs phenomena.
55 : *
56 : * A cell is troubled if
57 : *
58 : * \f{align*}{
59 : * \frac{(\hat{U}, \hat{U})}{(U, U)} > (N + 1 - M)^{-\alpha}
60 : * \f}
61 : *
62 : * where \f$(\cdot,\cdot)\f$ is an inner product, which we take to be the
63 : * Euclidean \f$L_2\f$ norm (i.e. we do not divide by the number of grid points
64 : * since that cancels out anyway) computed as
65 : *
66 : * \f{align*}{
67 : * (U, U) \equiv \sqrt{\sum_{i=0}^N U_i^2}
68 : * \f}
69 : *
70 : * where $U_i$ are nodal values of the quantity $U$ at grid points.
71 : *
72 : * Typically, \f$\alpha=4.0\f$ and $M=1$ is a good choice.
73 : *
74 : * This function supports Legendre, Chebyshev, ZernikeB1, and Cartoon bases.
75 : */
76 : template <size_t Dim, typename SymmList, typename IndexList>
77 1 : bool persson_tci(const Tensor<DataVector, SymmList, IndexList>& tensor,
78 : const Mesh<Dim>& dg_mesh, const double alpha,
79 : const size_t num_highest_modes) {
80 : DataVector filtered_component(dg_mesh.number_of_grid_points());
81 : if constexpr (Dim == 3) {
82 : if (dg_mesh.basis(0) == Spectral::Basis::ZernikeB1) {
83 : using TensorType = Tensor<DataVector, SymmList, IndexList>;
84 : constexpr auto component_parities =
85 : Spectral::make_component_parity_array<TensorType>();
86 : for (size_t component_index = 0; component_index < tensor.size();
87 : ++component_index) {
88 : if (detail::persson_tci_impl(
89 : make_not_null(&filtered_component), tensor[component_index],
90 : dg_mesh, alpha, num_highest_modes,
91 : gsl::at(component_parities, component_index))) {
92 : return true;
93 : }
94 : }
95 : return false;
96 : }
97 : }
98 : for (size_t component_index = 0; component_index < tensor.size();
99 : ++component_index) {
100 : if (detail::persson_tci_impl(make_not_null(&filtered_component),
101 : tensor[component_index], dg_mesh, alpha,
102 : num_highest_modes)) {
103 : return true;
104 : }
105 : }
106 : return false;
107 : }
108 : } // namespace evolution::dg::subcell
|