SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/FiniteDifference - MonotonicityPreserving5.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 50.0 % 2 1
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              : 
      10              : #include "NumericalAlgorithms/FiniteDifference/Reconstruct.hpp"
      11              : #include "NumericalAlgorithms/FiniteDifference/Unlimited.hpp"
      12              : #include "Utilities/ConstantExpressions.hpp"
      13              : #include "Utilities/ErrorHandling/Assert.hpp"
      14              : #include "Utilities/ForceInline.hpp"
      15              : #include "Utilities/Gsl.hpp"
      16              : #include "Utilities/Math.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              : struct MonotonicityPreserving5Reconstructor {
      31              :   SPECTRE_ALWAYS_INLINE static std::array<double, 2> pointwise(
      32              :       const double* const q, const int stride, const double alpha,
      33              :       const double epsilon) {
      34              :     using std::abs;
      35              :     using std::max;
      36              :     using std::min;
      37              : 
      38              :     // define minmod function for 2 and 4 args
      39              :     const auto minmod2 = [](const double x, const double y) {
      40              :       return 0.5 * (sgn(x) + sgn(y)) * min(abs(x), abs(y));
      41              :     };
      42              :     const auto minmod4 = [](const double w, const double x, const double y,
      43              :                             const double z) {
      44              :       const double sign_w = sgn(w);
      45              :       return 0.125 * (sign_w + sgn(x)) *
      46              :              abs((sign_w + sgn(y)) * (sign_w + sgn(z))) *
      47              :              min(abs(w), min(abs(x), min(abs(y), abs(z))));
      48              :     };
      49              : 
      50              :     // first, compute unlimited fifth-order finite difference reconstruction
      51              :     // values
      52              :     auto result = UnlimitedReconstructor<4>::pointwise(q, stride);
      53              : 
      54              :     // compute q_{j+1/2}
      55              :     const double q_mp_plus =
      56              :         q[0] + minmod2(q[stride] - q[0], alpha * (q[0] - q[-stride]));
      57              :     // compute q_{j-1/2}
      58              :     const double q_mp_minus =
      59              :         q[0] + minmod2(q[-stride] - q[0], alpha * (q[0] - q[stride]));
      60              : 
      61              :     const bool limit_q_plus =
      62              :         ((result[1] - q[0]) * (result[1] - q_mp_plus) > epsilon);
      63              :     const bool limit_q_minus =
      64              :         ((result[0] - q[0]) * (result[0] - q_mp_minus) > epsilon);
      65              : 
      66              :     if (limit_q_plus or limit_q_minus) {
      67              :       const double dp = q[2 * stride] + q[0] - 2.0 * q[stride];
      68              :       const double dj = q[stride] + q[-stride] - 2.0 * q[0];
      69              :       const double dm = q[0] + q[-2 * stride] - 2.0 * q[-stride];
      70              :       const double dm4_plus = minmod4(4.0 * dj - dp, 4 * dp - dj, dj, dp);
      71              :       const double dm4_minus = minmod4(4.0 * dj - dm, 4 * dm - dj, dj, dm);
      72              : 
      73              :       if (limit_q_plus) {
      74              :         const double q_ul = q[0] + alpha * (q[0] - q[-stride]);
      75              :         const double q_md =
      76              :             0.5 * (q[0] + q[stride] - dm4_plus);  // inline q^{AV}
      77              :         const double q_lc =
      78              :             q[0] + 0.5 * (q[0] - q[-stride]) + 1.3333333333333333 * dm4_minus;
      79              :         const double q_min =
      80              :             max(min(q[0], min(q[stride], q_md)), min(q[0], min(q_ul, q_lc)));
      81              :         const double q_max =
      82              :             min(max(q[0], max(q[stride], q_md)), max(q[0], max(q_ul, q_lc)));
      83              : 
      84              :         result[1] = result[1] + minmod2(q_min - result[1], q_max - result[1]);
      85              :       }
      86              : 
      87              :       if (limit_q_minus) {
      88              :         const double q_ul = q[0] + alpha * (q[0] - q[stride]);
      89              :         const double q_md =
      90              :             0.5 * (q[0] + q[-stride] - dm4_minus);  // inline q^{AV}
      91              :         const double q_lc =
      92              :             q[0] + 0.5 * (q[0] - q[stride]) + 1.3333333333333333 * dm4_plus;
      93              :         const double q_min =
      94              :             max(min(q[0], min(q[-stride], q_md)), min(q[0], min(q_ul, q_lc)));
      95              :         const double q_max =
      96              :             min(max(q[0], max(q[-stride], q_md)), max(q[0], max(q_ul, q_lc)));
      97              : 
      98              :         result[0] = result[0] + minmod2(q_min - result[0], q_max - result[0]);
      99              :       }
     100              :     }
     101              : 
     102              :     return result;
     103              :   }
     104              : 
     105              :   SPECTRE_ALWAYS_INLINE static constexpr size_t stencil_width() { return 5; }
     106              : };
     107              : }  // namespace detail
     108              : 
     109              : /*!
     110              :  * \ingroup FiniteDifferenceGroup
     111              :  * \brief Performs the fifth order monotonicity-preserving (MP5) reconstruction
     112              :  * \cite Suresh1997.
     113              :  *
     114              :  * First, calculate the original interface value \f$q_{j+1/2}^\text{OR}\f$ with
     115              :  * the (unlimited) fifth order finite difference reconstruction
     116              :  *
     117              :  * \f{align}
     118              :  *  q_{j+1/2}^\text{OR} = \frac{1}{128}( 3 q_{j-2} - 20 q_{j-1} + 90 q_{j}
     119              :  *            + 60 q_{j+1} - 5 q_{j+2}) .
     120              :  * \f}
     121              :  *
     122              :  * and compute
     123              :  *
     124              :  * \f{align}
     125              :  *  q^\text{MP} = q_j + \text{minmod}(q_{j+1} - q_j, \alpha(q_j - q_{j-1}))
     126              :  * \f}
     127              :  *
     128              :  * for a given value of \f$\alpha\f$, which is usually set to \f$\alpha=4\f$.
     129              :  *
     130              :  * If \f$ (q_{j+1/2}^\text{OR} - q_j)(q_{j+1/2}^\text{OR} - q^\text{MP}) \leq
     131              :  * \epsilon\f$ where \f$\epsilon\f$ is a small tolerance value, use $q_{1/2}
     132              :  * = q_{j+1/2}^\text{OR}$.
     133              :  *
     134              :  * \note A proper value of \f$\epsilon\f$ may depend on the scale of the
     135              :  * quantity \f$q\f$ to be reconstructed; reference \cite Suresh1997 suggests
     136              :  * 1e-10. For hydro simulations with atmosphere treatment, setting
     137              :  * \f$\epsilon=0.0\f$ would be safe.
     138              :  *
     139              :  * Otherwise, calculate
     140              :  *
     141              :  * \f{align}
     142              :  *  d_{j+1} & = q_{j+2} - 2q_{j+1} + q_{j}       \\
     143              :  *  d_j     & = q_{j+1} - 2q_j + q_{j-1}         \\
     144              :  *  d_{j-1} & = q_{j} - 2q_{j-1} + q_{j-2} ,
     145              :  * \f}
     146              :  *
     147              :  * \f{align}
     148              :  *  d^\text{M4}_{j+1/2} =
     149              :  *                \text{minmod}(4d_j - d_{j+1}, 4d_{j+1}-d_j, d_j, d_{j+1}) \\
     150              :  *  d^\text{M4}_{j-1/2} =
     151              :  *                \text{minmod}(4d_j - d_{j-1}, 4d_{j-1}-d_j, d_j, d_{j-1}),
     152              :  * \f}
     153              :  *
     154              :  * \f{align}
     155              :  *  q^\text{UL} & = q_j + \alpha(q_j - q_{j-1})                             \\
     156              :  *  q^\text{AV} & = (q_j + q_{j+1}) / 2                                     \\
     157              :  *  q^\text{MD} & = q^\text{AV} -  d^\text{M4}_{j+1/2} / 2                  \\
     158              :  *  q^\text{LC} & = q_j + (q_j - q_{j-1}) / 2 + (4/3) d^\text{M4}_{j-1/2}
     159              :  * \f}
     160              :  *
     161              :  * and
     162              :  * \f{align}
     163              :  *  q^\text{min} & = \text{max}[ \text{min}(q_j, q_{j+1}, q^\text{MD}),
     164              :  *                               \text{min}(q_j, q^\text{UL}, q^\text{LC}) ] \\
     165              :  *  q^\text{max} & = \text{min}[ \text{max}(q_j, q_{j+1}, q^\text{MD}),
     166              :  *                               \text{max}(q_j, q^\text{UL}, q^\text{LC}) ].
     167              :  * \f}
     168              :  *
     169              :  * The reconstructed value is given as
     170              :  * \f{align}
     171              :  *  q_{i+1/2} = \text{median}(q_{j+1/2}^\text{OR},  q^\text{min}, q^\text{max})
     172              :  * \f}
     173              :  * where the median function can be expressed as
     174              :  * \f{align}
     175              :  *  \text{median}(x,y,z) = x + \text{minmod}(y-x, z-x).
     176              :  * \f}
     177              :  *
     178              :  */
     179              : template <size_t Dim>
     180            1 : void monotonicity_preserving_5(
     181              :     const gsl::not_null<std::array<gsl::span<double>, Dim>*>
     182              :         reconstructed_upper_side_of_face_vars,
     183              :     const gsl::not_null<std::array<gsl::span<double>, Dim>*>
     184              :         reconstructed_lower_side_of_face_vars,
     185              :     const gsl::span<const double>& volume_vars,
     186              :     const DirectionMap<Dim, gsl::span<const double>>& ghost_cell_vars,
     187              :     const Index<Dim>& volume_extents, const size_t number_of_variables,
     188              :     const double alpha, const double epsilon) {
     189              :   detail::reconstruct<detail::MonotonicityPreserving5Reconstructor>(
     190              :       reconstructed_upper_side_of_face_vars,
     191              :       reconstructed_lower_side_of_face_vars, volume_vars, ghost_cell_vars,
     192              :       volume_extents, number_of_variables, alpha, epsilon);
     193              : }
     194              : }  // namespace fd::reconstruction
        

Generated by: LCOV version 2.0-1