@@ -36,7 +36,7 @@ enum redoFlag { none = 0, redo = 1 };
3636} // namespace quokka
3737
3838// Define enum for slope limiter type
39- enum SlopeLimiter { minmod = 0 , MC };
39+ enum SlopeLimiter { minmod = 0 , sweby, MC };
4040
4141using array_t = amrex::Array4<amrex::Real> const ;
4242using arrayconst_t = amrex::Array4<const amrex::Real> const ;
@@ -47,25 +47,45 @@ template <typename problem_t> class HyperbolicSystem
4747 public:
4848 template <SlopeLimiter limiter> AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE static auto SlopeFunc (amrex::Real x, amrex::Real y) -> amrex::Real
4949 {
50- static_assert (limiter == SlopeLimiter::minmod || limiter == SlopeLimiter::MC , " Invalid slope limiter specified." );
50+ static_assert (limiter == SlopeLimiter::minmod || limiter == SlopeLimiter::sweby || limiter == SlopeLimiter::MC ,
51+ " Invalid slope limiter specified." );
5152 if constexpr (limiter == SlopeLimiter::minmod) {
52- return minmod (x, y);
53+ return Sweby (x, y, 1.0 );
54+ }
55+ if constexpr (limiter == SlopeLimiter::sweby) {
56+ return Sweby (x, y, 1.5 );
5357 }
5458 if constexpr (limiter == SlopeLimiter::MC ) {
55- return MC (x, y);
59+ return Sweby (x, y, 2.0 );
5660 }
5761 }
5862
5963 [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE static auto MC (double a, double b) -> double
6064 {
61- return 0.5 * ( sgn (a) + sgn (b)) * std::min ({ 0.5 * std::abs (a + b) , 2.0 * std::abs (a), 2.0 * std::abs (b)} );
65+ return Sweby (a, b , 2.0 );
6266 }
6367
6468 [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE static auto minmod (double a, double b) -> double
6569 {
6670 return 0.5 * (sgn (a) + sgn (b)) * std::min (std::abs (a), std::abs (b));
6771 }
6872
73+ [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE static auto minmod3 (double a, double b, double c) -> double
74+ {
75+ if ((sgn (a) == sgn (b)) && (sgn (a) == sgn (c))) {
76+ return sgn (a) * std::min ({std::abs (a), std::abs (b), std::abs (c)});
77+ }
78+ return 0.0 ;
79+ }
80+
81+ [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE static auto Sweby (double a, double b, double sigma) -> double
82+ {
83+ const double sigma_a = sigma * a;
84+ const double sigma_b = sigma * b;
85+ const double centered = 0.5 * (a + b);
86+ return minmod3 (sigma_a, centered, sigma_b);
87+ }
88+
6989 [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE static auto median (double a, double b, double c) -> double
7090 {
7191 return std::max (std::min (a, b), std::min (std::max (a, b), c));
@@ -255,7 +275,7 @@ HyperbolicSystem<problem_t>::ReconstructStatesPLM(quokka::Array4View<amrex::Real
255275 // permute array indices according to dir
256276 auto [i, j, k] = quokka::reorderMultiIndex<DIR >(i_in, j_in, k_in);
257277
258- // Unlike PPM, PLM with MC or minmod limiters is TVD.
278+ // Unlike PPM, PLM with Sweby limiters (sigma=1 midmod, sigma=1.5 Sweby, sigma=2 MC) is TVD.
259279 // (There are no spurious oscillations, *except* in the slow-moving shock problem,
260280 // which can produce unphysical oscillations even when using upwind Godunov fluxes.)
261281 // However, most tests fail when using PLM reconstruction because
@@ -273,8 +293,8 @@ HyperbolicSystem<problem_t>::ReconstructStatesPLM(quokka::Array4View<amrex::Real
273293 // (This converges at second order in spatial resolution.)
274294 const auto lslope = HyperbolicSystem<problem_t >::template SlopeFunc<limiter>(q (i, j, k, n) - q (i - 1 , j, k, n), q (i - 1 , j, k, n) - q (i - 2 , j, k, n));
275295 const auto rslope = HyperbolicSystem<problem_t >::template SlopeFunc<limiter>(q (i + 1 , j, k, n) - q (i, j, k, n), q (i, j, k, n) - q (i - 1 , j, k, n));
276- leftState (i, j, k, n) = q (i - 1 , j, k, n) + 0.25 * lslope; // NOLINT
277- rightState (i, j, k, n) = q (i, j, k, n) - 0.25 * rslope; // NOLINT
296+ leftState (i, j, k, n) = q (i - 1 , j, k, n) + 0.5 * lslope; // NOLINT
297+ rightState (i, j, k, n) = q (i, j, k, n) - 0.5 * rslope; // NOLINT
278298}
279299
280300template <typename problem_t >
0 commit comments