SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/FiniteDifference - Wcns5z.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 66.7 % 3 2
Test Date: 2026-10-22 17:29:42
Legend: Lines:     hit not hit

            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 <cmath>
       8              : #include <cstddef>
       9              : #include <tuple>
      10              : 
      11              : #include "NumericalAlgorithms/FiniteDifference/FallbackReconstructorType.hpp"
      12              : #include "NumericalAlgorithms/FiniteDifference/Reconstruct.hpp"
      13              : #include "Utilities/ConstantExpressions.hpp"
      14              : #include "Utilities/ErrorHandling/Assert.hpp"
      15              : #include "Utilities/ForceInline.hpp"
      16              : #include "Utilities/Gsl.hpp"
      17              : 
      18              : /// \cond
      19              : class DataVector;
      20              : template <size_t>
      21              : class Direction;
      22              : template <size_t Dim, typename T>
      23              : class DirectionMap;
      24              : template <size_t Dim>
      25              : class Index;
      26              : /// \endcond
      27              : 
      28              : namespace fd::reconstruction {
      29              : namespace detail {
      30              : // pointwise reconstruction routine for the original Wcns5z scheme
      31              : template <size_t NonlinearWeightExponent>
      32              : struct Wcns5zWork {
      33              :   SPECTRE_ALWAYS_INLINE static std::array<double, 2> pointwise(
      34              :       const double* const q, const int stride, const double epsilon) {
      35              :     ASSERT(epsilon > 0.0,
      36              :            "epsilon must be greater than zero but is " << epsilon);
      37              : 
      38              :     using std::abs;
      39              : 
      40              :     const std::array beta{
      41              :         1.0833333333333333 * square(q[-2 * stride] - 2.0 * q[-stride] + q[0]) +
      42              :             0.25 * square(q[-2 * stride] - 4.0 * q[-stride] + 3.0 * q[0]),
      43              :         1.0833333333333333 * square(q[-stride] - 2.0 * q[0] + q[stride]) +
      44              :             0.25 * square(q[stride] - q[-stride]),
      45              :         1.0833333333333333 * square(q[2 * stride] - 2.0 * q[stride] + q[0]) +
      46              :             0.25 * square(q[2 * stride] - 4.0 * q[stride] + 3.0 * q[0])};
      47              : 
      48              :     const double tau5{abs(beta[2] - beta[0])};
      49              : 
      50              :     const std::array epsilon_k{
      51              :         epsilon * (1.0 + abs(q[0]) + abs(q[-stride]) + abs(q[-2 * stride])),
      52              :         epsilon * (1.0 + abs(q[0]) + abs(q[-stride]) + abs(q[stride])),
      53              :         epsilon * (1.0 + abs(q[0]) + abs(q[stride]) + abs(q[2 * stride]))};
      54              : 
      55              :     const std::array nw_buffer{
      56              :         1.0 + pow<NonlinearWeightExponent>(tau5 / (beta[0] + epsilon_k[0])),
      57              :         1.0 + pow<NonlinearWeightExponent>(tau5 / (beta[1] + epsilon_k[1])),
      58              :         1.0 + pow<NonlinearWeightExponent>(tau5 / (beta[2] + epsilon_k[2]))};
      59              : 
      60              :     // nonlinear weights for upper and lower reconstructions. The factor 1/16
      61              :     // for `alpha`s is omitted here since it is eventually canceled out by
      62              :     // denominator when evaluating modified nonlinear weight `omega`s (see the
      63              :     // documentation of the `wcns5z()` function below).
      64              :     const std::array alpha_upper{nw_buffer[0], 10.0 * nw_buffer[1],
      65              :                                  5.0 * nw_buffer[2]};
      66              :     const std::array alpha_lower{nw_buffer[2], 10.0 * nw_buffer[1],
      67              :                                  5.0 * nw_buffer[0]};
      68              :     const double alpha_norm_upper =
      69              :         alpha_upper[0] + alpha_upper[1] + alpha_upper[2];
      70              :     const double alpha_norm_lower =
      71              :         alpha_lower[0] + alpha_lower[1] + alpha_lower[2];
      72              : 
      73              :     // reconstruction stencils
      74              :     const std::array recons_stencils_upper{
      75              :         0.375 * q[-2 * stride] - 1.25 * q[-stride] + 1.875 * q[0],
      76              :         -0.125 * q[-stride] + 0.75 * q[0] + 0.375 * q[stride],
      77              :         0.375 * q[0] + 0.75 * q[stride] - 0.125 * q[2 * stride]};
      78              :     const std::array recons_stencils_lower{
      79              :         0.375 * q[2 * stride] - 1.25 * q[stride] + 1.875 * q[0],
      80              :         -0.125 * q[stride] + 0.75 * q[0] + 0.375 * q[-stride],
      81              :         0.375 * q[0] + 0.75 * q[-stride] - 0.125 * q[-2 * stride]};
      82              : 
      83              :     // reconstructed solutions
      84              :     return {{(alpha_lower[0] * recons_stencils_lower[0] +
      85              :               alpha_lower[1] * recons_stencils_lower[1] +
      86              :               alpha_lower[2] * recons_stencils_lower[2]) /
      87              :                  alpha_norm_lower,
      88              :              (alpha_upper[0] * recons_stencils_upper[0] +
      89              :               alpha_upper[1] * recons_stencils_upper[1] +
      90              :               alpha_upper[2] * recons_stencils_upper[2]) /
      91              :                  alpha_norm_upper}};
      92              :   }
      93              : };
      94              : 
      95              : template <size_t NonlinearWeightExponent, class FallbackReconstructor>
      96              : struct Wcns5zReconstructor {
      97              :   SPECTRE_ALWAYS_INLINE static std::array<double, 2> pointwise(
      98              :       const double* const q, const int stride, const double epsilon,
      99              :       const size_t max_number_of_extrema) {
     100              :     // count the number of extrema in the given FD stencil
     101              :     size_t n_extrema{0};
     102              :     for (int i = -1; i < 2; ++i) {
     103              :       // check if q[i * stride] is local maximum
     104              :       n_extrema += (q[i * stride] > q[(i - 1) * stride]) and
     105              :                    (q[i * stride] > q[(i + 1) * stride]);
     106              :       // check if q[i * stride] is local minimum
     107              :       n_extrema += (q[i * stride] < q[(i - 1) * stride]) and
     108              :                    (q[i * stride] < q[(i + 1) * stride]);
     109              :     }
     110              : 
     111              :     // if `n_extrema` is equal or smaller than a specified number, use the
     112              :     // original Wcns5z reconstruction
     113              :     if (n_extrema < max_number_of_extrema + 1) {
     114              :       return Wcns5zWork<NonlinearWeightExponent>::pointwise(q, stride, epsilon);
     115              :     } else {
     116              :       // otherwise use a fallback reconstruction method
     117              :       return FallbackReconstructor::pointwise(q, stride);
     118              :     }
     119              :   }
     120              : 
     121              :   SPECTRE_ALWAYS_INLINE static constexpr size_t stencil_width() { return 5; }
     122              : };
     123              : 
     124              : template <size_t NonlinearWeightExponent>
     125              : struct Wcns5zReconstructor<NonlinearWeightExponent, void> {
     126              :   SPECTRE_ALWAYS_INLINE static std::array<double, 2> pointwise(
     127              :       const double* const q, const int stride, const double epsilon,
     128              :       const size_t /*max_number_of_extrema*/) {
     129              :     return Wcns5zWork<NonlinearWeightExponent>::pointwise(q, stride, epsilon);
     130              :   }
     131              :   SPECTRE_ALWAYS_INLINE static constexpr size_t stencil_width() { return 5; }
     132              : };
     133              : 
     134              : }  // namespace detail
     135              : 
     136              : /*!
     137              :  * \ingroup FiniteDifferenceGroup
     138              :  * \brief Performs fifth order weighted compact nonlinear scheme reconstruction
     139              :  * based on the WENO-Z method (WCNS-5Z). Adaptive fallback combined with
     140              :  * an auxiliary reconstruction method (e.g. monotonised central) is also
     141              :  * supported.
     142              :  *
     143              :  * Using the WENO oscillation indicators given by \cite Jiang1996
     144              :  *
     145              :  * \f{align}
     146              :  *  \beta_0 & = \frac{13}{12} (q_{i-2} - 2q_{i-1} + q_{i})^2
     147              :  *              + \frac{1}{4} (q_{i-2} - 4q_{i-1} + 3q_{i})^2  \\
     148              :  *  \beta_1 & = \frac{13}{12} (q_{i-1} - 2q_{i} + q_{i+1})^2
     149              :  *              + \frac{1}{4} (q_{i+1} - q_{i-1})^2            \\
     150              :  *  \beta_2 & = \frac{13}{12} (q_{i} - 2q_{i+1} + q_{i+2})^2
     151              :  *              + \frac{1}{4} (3q_{i} - 4q_{i+1} + q_{i+2})^2 ,
     152              :  * \f}
     153              :  *
     154              :  * compute the modified nonlinear weights (cf. WENO-Z scheme: see Eq. 42 of
     155              :  * \cite Borges20083191)
     156              :  *
     157              :  * \f{align}
     158              :  *  \omega_k^z = \frac{\alpha_k^z}{\sum_{l=0}^z \alpha_l^z}, \quad
     159              :  *  \alpha_k^z = c_k \left(1 + \left(
     160              :  *                       \frac{\tau_5}{\beta_k + \epsilon_k} \right)^q \right),
     161              :  *  \quad k = 0, 1, 2
     162              :  * \f}
     163              :  *
     164              :  * where \f$\epsilon_k\f$ is a factor used to avoid division by zero and is set
     165              :  * to
     166              :  *
     167              :  * \f{align}
     168              :  *  \epsilon_k = \varepsilon (1 + |q_{i+k}| + |q_{i+k-1}| + |q_{i+k-2}|),
     169              :  *  \quad k = 0, 1, 2,
     170              :  * \f}
     171              :  *
     172              :  * linear weights \f$c_k\f$ are adopted from \cite Nonomura2013 (see Table 17
     173              :  * of it)
     174              :  *
     175              :  * \f{align}
     176              :  *  c_0 = 1/16, \quad c_1 = 10/16, \quad c_2 = 5/16,
     177              :  * \f}
     178              :  *
     179              :  * and \f$\tau_5 \equiv |\beta_2-\beta_0|\f$.
     180              :  *
     181              :  * Reconstruction stencils are given by Lagrange interpolations (e.g. see Eq.
     182              :  * 29d - 29f of \cite Brehm2015)
     183              :  * \f{align}
     184              :  * q_{i+1/2}^0 &= \frac{3}{8}q_{i-2} -\frac{5}{4}q_{i-1} +\frac{15}{8}q_{i} \\
     185              :  * q_{i+1/2}^1 &= -\frac{1}{8}q_{i-1} +\frac{3}{4}q_{i} +\frac{3}{8}q_{i+1} \\
     186              :  * q_{i+1/2}^2 &= \frac{3}{8}q_{i} +\frac{3}{4}q_{i+1} -\frac{1}{8}q_{i+2}
     187              :  * \f}
     188              :  *
     189              :  * and the final reconstructed solution is given by
     190              :  * \f{align}
     191              :  *   q_{i+1/2} = \sum_{k=0}^2 \omega_k q_{i+1/2}^k .
     192              :  * \f}
     193              :  *
     194              :  * The nonlinear weights exponent \f$q (=1 \text{ or } 2)\f$ and the small
     195              :  * factor \f$\varepsilon\f$ can be chosen via an input file.
     196              :  *
     197              :  * If the template parameter `FallbackReconstructor` is set to one of
     198              :  * the FD reconstructor structs of which names are listed in
     199              :  * `fd::reconstruction::FallbackReconstructorType`, adaptive reconstruction
     200              :  * is performed as follows. For each finite difference stencils, first check how
     201              :  * many extrema are in the stencil. If the number of local extrema is less than
     202              :  * or equal to a non-negative integer `max_number_of_extrema` which is given as
     203              :  * an input parameter, perform the WCNS-5Z reconstruction; otherwise switch to
     204              :  * the given `FallbackReconstructor` for performing reconstruction. If
     205              :  * `FallbackReconstructor` is set to `void`, the adaptive method is disabled and
     206              :  * WCNS-5Z is always used.
     207              :  *
     208              :  */
     209              : template <size_t NonlinearWeightExponent, class FallbackReconstructor,
     210              :           size_t Dim>
     211            1 : void wcns5z(const gsl::not_null<std::array<gsl::span<double>, Dim>*>
     212              :                 reconstructed_upper_side_of_face_vars,
     213              :             const gsl::not_null<std::array<gsl::span<double>, Dim>*>
     214              :                 reconstructed_lower_side_of_face_vars,
     215              :             const gsl::span<const double>& volume_vars,
     216              :             const DirectionMap<Dim, gsl::span<const double>>& ghost_cell_vars,
     217              :             const Index<Dim>& volume_extents, const size_t number_of_variables,
     218              :             const double epsilon, const size_t max_number_of_extrema) {
     219              :   detail::reconstruct<detail::Wcns5zReconstructor<NonlinearWeightExponent,
     220              :                                                   FallbackReconstructor>>(
     221              :       reconstructed_upper_side_of_face_vars,
     222              :       reconstructed_lower_side_of_face_vars, volume_vars, ghost_cell_vars,
     223              :       volume_extents, number_of_variables, epsilon, max_number_of_extrema);
     224              : }
     225              : 
     226              : /*!
     227              :  * \brief Returns function pointers to the `wcns5z` function, lower neighbor
     228              :  * reconstruction, and upper neighbor reconstruction.
     229              :  *
     230              :  */
     231              : template <size_t Dim>
     232            1 : auto wcns5z_function_pointers(size_t nonlinear_weight_exponent,
     233              :                               FallbackReconstructorType fallback_recons)
     234              :     -> std::tuple<
     235              :         void (*)(gsl::not_null<std::array<gsl::span<double>, Dim>*>,
     236              :                  gsl::not_null<std::array<gsl::span<double>, Dim>*>,
     237              :                  const gsl::span<const double>&,
     238              :                  const DirectionMap<Dim, gsl::span<const double>>&,
     239              :                  const Index<Dim>&, size_t, double, size_t),
     240              :         void (*)(gsl::not_null<DataVector*>, const DataVector&,
     241              :                  const DataVector&, const Index<Dim>&, const Index<Dim>&,
     242              :                  const Direction<Dim>&, const double&, const size_t&),
     243              :         void (*)(gsl::not_null<DataVector*>, const DataVector&,
     244              :                  const DataVector&, const Index<Dim>&, const Index<Dim>&,
     245              :                  const Direction<Dim>&, const double&, const size_t&)>;
     246              : 
     247              : }  // namespace fd::reconstruction
        

Generated by: LCOV version 2.0-1