Skip to content

Commit a9df729

Browse files
committed
fv_ops: WENO3 cell edge reconstruction
1 parent 4b6da43 commit a9df729

4 files changed

Lines changed: 89 additions & 0 deletions

File tree

examples/finite-volume/fluid/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,7 @@ for the second order MinMod method.
5454
Or, to use a smooth symmetric limiter:
5555

5656
FV::Div_par<FV::VanAlbada>
57+
58+
Or a higher-order smooth WENO reconstruction:
59+
60+
FV::Div_par<FV::WENO3>

include/bout/fv_ops.hxx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,61 @@ struct VanAlbada {
208208
}
209209
};
210210

211+
/*!
212+
* WENO3-JS (Jiang-Shu) reconstruction to cell faces
213+
*
214+
* This is a third-order essentially non-oscillatory reconstruction using two
215+
* candidate second-order polynomials and smoothness-weighted blending.
216+
*
217+
* Unlike TVD slope limiters (e.g. ``MC``), WENO reconstruction is generally
218+
* smooth (differentiable) for all inputs, but it does not enforce strict
219+
* monotonicity.
220+
*
221+
* Uses only the three-point stencil (`m`, `c`, `p`), so it is a drop-in
222+
* replacement anywhere `Stencil1D` is populated with those values.
223+
*/
224+
struct WENO3 {
225+
void operator()(Stencil1D& n) {
226+
// Right face (between c and p): value from cell c (left state at i+1/2)
227+
const BoutReal p0_r = 0.5 * (-n.m + 3.0 * n.c);
228+
const BoutReal p1_r = 0.5 * (n.c + n.p);
229+
230+
const BoutReal beta0_r = SQ(n.c - n.m);
231+
const BoutReal beta1_r = SQ(n.p - n.c);
232+
233+
// Left face (between m and c): value from cell c (right state at i-1/2)
234+
const BoutReal p0_l = 0.5 * (-n.p + 3.0 * n.c);
235+
const BoutReal p1_l = 0.5 * (n.m + n.c);
236+
237+
const BoutReal beta0_l = beta1_r;
238+
const BoutReal beta1_l = beta0_r;
239+
240+
// Smoothness parameter (scaled to local variation)
241+
const BoutReal eps = 1e-12 * (beta0_r + beta1_r) + 1e-30;
242+
243+
// Linear weights for WENO3-JS
244+
constexpr BoutReal d0 = 1.0 / 3.0;
245+
constexpr BoutReal d1 = 2.0 / 3.0;
246+
247+
// Right face weights
248+
const BoutReal a0_r = d0 / SQ(eps + beta0_r);
249+
const BoutReal a1_r = d1 / SQ(eps + beta1_r);
250+
const BoutReal wsum_r = a0_r + a1_r;
251+
const BoutReal w0_r = a0_r / wsum_r;
252+
const BoutReal w1_r = a1_r / wsum_r;
253+
254+
// Left face weights (mirrored)
255+
const BoutReal a0_l = d0 / SQ(eps + beta0_l);
256+
const BoutReal a1_l = d1 / SQ(eps + beta1_l);
257+
const BoutReal wsum_l = a0_l + a1_l;
258+
const BoutReal w0_l = a0_l / wsum_l;
259+
const BoutReal w1_l = a1_l / wsum_l;
260+
261+
n.R = w0_r * p0_r + w1_r * p1_r;
262+
n.L = w0_l * p0_l + w1_l * p1_l;
263+
}
264+
};
265+
211266
/*!
212267
* Communicate fluxes between processors
213268
* Takes values in guard cells, and adds them to cells

manual/sphinx/user_docs/differential_operators.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,10 @@ values. Several slope limiters are defined in ``fv_ops.hxx``:
671671
avoids piecewise branches at extrema. This can be useful for nonlinear
672672
solvers and finite-difference Jacobian calculations.
673673

674+
* ``WENO3`` - A third-order smooth WENO (Jiang-Shu) cell-face reconstruction
675+
using a three-point stencil. This is typically less dissipative than TVD
676+
slope limiters, but is not strictly monotonicity-preserving.
677+
674678
Useful resources on slope limiters include:
675679

676680
* `Wikipedia's Flux Limiter page <https://en.wikipedia.org/wiki/Flux_limiter>`_

tests/unit/include/bout/test_fv_ops.cxx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,29 @@ TEST(FVOpsLimiterTest, VanAlbadaLimitsToSmallerGradient) {
5454
EXPECT_NEAR(s.L, 0.7, 1e-12);
5555
EXPECT_NEAR(s.R, 1.3, 1e-12);
5656
}
57+
58+
TEST(FVOpsLimiterTest, WENO3Constant) {
59+
FV::Stencil1D s{};
60+
s.m = 1.0;
61+
s.c = 1.0;
62+
s.p = 1.0;
63+
64+
FV::WENO3 recon;
65+
recon(s);
66+
67+
EXPECT_DOUBLE_EQ(s.L, 1.0);
68+
EXPECT_DOUBLE_EQ(s.R, 1.0);
69+
}
70+
71+
TEST(FVOpsLimiterTest, WENO3Linear) {
72+
FV::Stencil1D s{};
73+
s.m = 0.0;
74+
s.c = 1.0;
75+
s.p = 2.0;
76+
77+
FV::WENO3 recon;
78+
recon(s);
79+
80+
EXPECT_NEAR(s.L, 0.5, 1e-14);
81+
EXPECT_NEAR(s.R, 1.5, 1e-14);
82+
}

0 commit comments

Comments
 (0)