Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4b0eddb
feat: add fp-stability command for Verrou-based FP instability testing
sbryngelson May 6, 2026
ae917e1
ci: add weekly FP stability workflow using Verrou
sbryngelson May 6, 2026
b0951f0
ci: trigger fp-stability on every push
sbryngelson May 6, 2026
5c8eaab
ci: remove concurrency group from fp-stability
sbryngelson May 6, 2026
13a6faf
style: collapse multi-line raise ValueError to satisfy CI ruff formatter
sbryngelson May 6, 2026
3e0a258
feat: add sod_standard baseline, enlarge cases, run dd_sym on failure
sbryngelson May 6, 2026
d561934
feat: add float proxy, VPREC sweep, dd_line, air_water_interface case
sbryngelson May 6, 2026
f932c4a
fix: add missing air_water_interface case input files
sbryngelson May 6, 2026
d363ca2
fix: add alpha(2) for both patches in air_water_interface pre_process…
sbryngelson May 6, 2026
0e7f365
fix: add reduced-energy (E-tilde) scheme for model_eqns=2 FP stability
sbryngelson May 6, 2026
7e80db0
ci: increase fp-stability case step counts to 50 for better sweep cov…
sbryngelson May 6, 2026
ab8ae6c
revert: remove reduced-energy (E-tilde) scheme — moving to separate PR
sbryngelson May 6, 2026
ae16849
fix: protect HLLC xi-factor denominators from division by zero with s…
sbryngelson May 6, 2026
09ce85a
ci: loosen water_stiffened threshold to 1e-8 until Etilde scheme merges
sbryngelson May 6, 2026
4055404
ci: GitHub step summary, file annotations, and float-proxy metric in …
sbryngelson May 6, 2026
11a98c9
ci: remove pass/fail markers from VPREC sweep table
sbryngelson May 6, 2026
2d1d6f9
fix: move cons.unindent into finally block; use MFC_ROOT_DIR in _find…
sbryngelson May 6, 2026
a6c76e2
ci: always run dd_line to surface FP hotspots on every run
sbryngelson May 6, 2026
8b70a32
ci: add bubble_rp and low_mach FP cases; fix dd threshold to use median
sbryngelson May 6, 2026
0f0f29e
fix: bubble_rp pre_process.inp (remove bubble_model); loosen low_mach…
sbryngelson May 6, 2026
281bd32
fix: loosen bubble_rp threshold to 1e-8 (RP ODE cancellation observed…
sbryngelson May 6, 2026
2fdc718
ci: use float-mode dd bisection (deterministic, nruns=1) instead of r…
sbryngelson May 7, 2026
48051dd
fix: dd_run.sh must honour VERROU_ROUNDING_MODE=nearest for reference…
sbryngelson May 7, 2026
b3656c8
feat: add cancellation detection, MCA sig-bits, and float-max checks …
sbryngelson May 7, 2026
cdb2156
fix: emit up to 3 dd_line + 3 cancellation annotations per case
sbryngelson May 7, 2026
6e5932e
fix: source context in summary, branch filter on workflow, reviewer f…
sbryngelson May 7, 2026
25736fc
fix: eliminate xi_L/R - 1 cancellation in 5-eq HLLC solver
sbryngelson May 7, 2026
08da8a8
Merge branch 'master' into fp-stability
sbryngelson May 7, 2026
66d12dd
Update fp-stability.yml
sbryngelson May 8, 2026
a41594f
Merge branch 'master' into fp-stability
sbryngelson May 8, 2026
ef20c51
Merge branch 'master' into fp-stability
sbryngelson May 9, 2026
c85f950
fix: loosen low_mach FP-stability threshold to 2e-7
sbryngelson May 9, 2026
47ac8cf
Merge branch 'master' into fp-stability
sbryngelson May 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions .github/workflows/fp-stability.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: FP Stability

# Runs the Verrou-based floating-point stability suite.
#
# What it tests (./mfc.sh fp-stability):
# sod_standard 1-D standard Sod, p_L/p_R=10, ideal gas (well-conditioned baseline)
# 25 cells, 5 steps, WENO5 + HLLC
# Threshold 1e-13 — should always pass
#
# sod_strong 1-D Sod shock, p_L/p_R=100,000, ideal gas
# 50 cells, 10 steps, WENO5 + HLLC
# Threshold 1e-10
# Probes: HLLC xi-factor cancellation near sonic contact
# (s_L - vel_L)/(s_L - s_S) when s_L ≈ s_S
#
# water_stiffened 1-D water shock, stiffened EOS (pi_inf=4046)
# 50 cells, 10 steps, WENO5 + HLLC
# Threshold 1e-8 (loosened; tightens to 1e-10 once Etilde scheme merges)
# Probes: pressure-recovery cancellation p=(E-pi_inf)/gamma
# loses ~4 decimal digits when pi_inf/p_right ~ 40,000
#
# For each case: 1 nearest-rounding reference run + N random-rounding runs.
# PASS if max L∞ deviation across all N samples stays below threshold.
# On FAIL: verrou_dd_sym runs to identify the responsible function symbols.
# Logs are uploaded as CI artifacts.
#
# Verrou (Valgrind 3.26.0 + edf-hpc/verrou@a58d434) is built once and cached.
# Build takes ~20 min uncached; cached runs restore in ~30 s.

on:
push:
branches: [master]
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
workflow_dispatch:

jobs:
fp-stability:
name: Floating-Point Stability (Verrou)
runs-on: ubuntu-latest

steps:
- name: Clone
uses: actions/checkout@v4

- name: Cache Verrou
id: cache-verrou
uses: actions/cache@v4
with:
path: ~/.local/verrou
key: verrou-a58d434-valgrind-3.26.0-${{ runner.os }}

- name: Install system dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y \
build-essential automake python3 python3-numpy libc6-dbg \
cmake gfortran

- name: Build Verrou
if: steps.cache-verrou.outputs.cache-hit != 'true'
run: |
cd /tmp
wget -q https://sourceware.org/pub/valgrind/valgrind-3.26.0.tar.bz2
tar xf valgrind-3.26.0.tar.bz2

git clone https://github.com/edf-hpc/verrou.git
git -C verrou checkout a58d434

# Merge Verrou into Valgrind source tree and patch
cp -r verrou valgrind-3.26.0/verrou
cd valgrind-3.26.0
cat verrou/valgrind.*diff | patch -p1

./autogen.sh
./configure --enable-only64bit --prefix="$HOME/.local/verrou"
make -j"$(nproc)"
make install

- name: Verify Verrou
run: ~/.local/verrou/bin/valgrind --version

- name: Build MFC (debug, serial)
run: ./mfc.sh build -t pre_process simulation --no-mpi --debug -j"$(nproc)"

- name: Run FP Stability Suite
run: ./mfc.sh fp-stability -N 5

- name: Upload FP stability logs
if: always()
uses: actions/upload-artifact@v4
with:
name: fp-stability-logs
path: fp-stability-logs/
if-no-files-found: ignore
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ docs/documentation/parameters.md
/tests/*/**
!/tests/*/golden.txt
!/tests/*/golden-metadata.txt
!/tests/fp_stability/**

# NVIDIA Nsight Compute
*.nsys-rep
Expand Down
78 changes: 42 additions & 36 deletions src/simulation/m_riemann_solvers.fpp
Original file line number Diff line number Diff line change
Expand Up @@ -1756,7 +1756,8 @@ contains
real(wp) :: qv_avg
real(wp) :: c_avg
real(wp) :: s_L, s_R, s_M, s_P, s_S
real(wp) :: xi_L, xi_R !< Left and right wave speeds functions
real(wp) :: xi_L, xi_R !< Left and right wave speeds functions
real(wp) :: xi_L_m1, xi_R_m1 !< xi_L/R - 1, computed without cancellation
real(wp) :: xi_M, xi_P
real(wp) :: xi_MP, xi_PP
#:if not MFC_CASE_OPTIMIZATION and USING_AMD
Expand Down Expand Up @@ -2040,8 +2041,8 @@ contains
s_M = min(0._wp, s_L); s_P = max(0._wp, s_R)

! goes with q_star_L/R = xi_L/R * (variable) xi_L/R = ( ( s_L/R - u_L/R )/(s_L/R - s_star) )
xi_L = (s_L - vel_L(dir_idx(1)))/(s_L - s_S)
xi_R = (s_R - vel_R(dir_idx(1)))/(s_R - s_S)
xi_L = (s_L - vel_L(dir_idx(1)))/min(s_L - s_S, -sgm_eps)
xi_R = (s_R - vel_R(dir_idx(1)))/max(s_R - s_S, sgm_eps)

! goes with numerical star velocity in x/y/z directions xi_P/M = 0.5 +/m sgn(0.5,s_star)
xi_M = (5.e-1_wp + sign(0.5_wp, s_S))
Expand Down Expand Up @@ -2331,8 +2332,8 @@ contains
s_M = min(0._wp, s_L); s_P = max(0._wp, s_R)

! goes with q_star_L/R = xi_L/R * (variable) xi_L/R = ( ( s_L/R - u_L/R )/(s_L/R - s_star) )
xi_L = (s_L - vel_L(dir_idx(1)))/(s_L - s_S)
xi_R = (s_R - vel_R(dir_idx(1)))/(s_R - s_S)
xi_L = (s_L - vel_L(dir_idx(1)))/min(s_L - s_S, -sgm_eps)
xi_R = (s_R - vel_R(dir_idx(1)))/max(s_R - s_S, sgm_eps)

! goes with numerical velocity in x/y/z directions xi_P/M = 0.5 +/m sgn(0.5,s_star)
xi_M = (5.e-1_wp + sign(5.e-1_wp, s_S))
Expand Down Expand Up @@ -2688,8 +2689,8 @@ contains
s_M = min(0._wp, s_L); s_P = max(0._wp, s_R)

! goes with q_star_L/R = xi_L/R * (variable) xi_L/R = ( ( s_L/R - u_L/R )/(s_L/R - s_star) )
xi_L = (s_L - vel_L(dir_idx(1)))/(s_L - s_S)
xi_R = (s_R - vel_R(dir_idx(1)))/(s_R - s_S)
xi_L = (s_L - vel_L(dir_idx(1)))/min(s_L - s_S, -sgm_eps)
xi_R = (s_R - vel_R(dir_idx(1)))/max(s_R - s_S, sgm_eps)

! goes with numerical velocity in x/y/z directions xi_P/M = 0.5 +/m sgn(0.5,s_star)
xi_M = (5.e-1_wp + sign(5.e-1_wp, s_S))
Expand Down Expand Up @@ -2846,10 +2847,11 @@ contains
& rho_L, gamma_L, pi_inf_L, qv_L, rho_R, gamma_R, pi_inf_R, qv_R, alpha_L_sum, &
& alpha_R_sum, E_L, E_R, MW_L, MW_R, R_gas_L, R_gas_R, Cp_L, Cp_R, Cv_L, Cv_R, Gamm_L, &
& Gamm_R, Y_L, Y_R, H_L, H_R, qv_avg, rho_avg, gamma_avg, H_avg, c_L, c_R, c_avg, s_P, &
& s_M, xi_P, xi_M, xi_L, xi_R, Ms_L, Ms_R, pres_SL, pres_SR, vel_L, vel_R, Re_L, Re_R, &
& alpha_L, alpha_R, s_L, s_R, s_S, vel_avg_rms, pcorr, zcoef, vel_L_tmp, vel_R_tmp, Ys_L, &
& Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, tau_e_L, tau_e_R, xi_field_L, &
& xi_field_R, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, G_L, G_R]', copyin='[is1, is2, is3]')
& s_M, xi_P, xi_M, xi_L, xi_R, xi_L_m1, xi_R_m1, Ms_L, Ms_R, pres_SL, pres_SR, vel_L, &
& vel_R, Re_L, Re_R, alpha_L, alpha_R, s_L, s_R, s_S, vel_avg_rms, pcorr, zcoef, &
& vel_L_tmp, vel_R_tmp, Ys_L, Ys_R, Xs_L, Xs_R, Gamma_iL, Gamma_iR, Cp_iL, Cp_iR, &
& tau_e_L, tau_e_R, xi_field_L, xi_field_R, Yi_avg, Phi_avg, h_iL, h_iR, h_avg_2, G_L, &
& G_R]', copyin='[is1, is2, is3]')
do l = is3%beg, is3%end
do k = is2%beg, is2%end
do j = is1%beg, is1%end
Expand Down Expand Up @@ -3127,8 +3129,11 @@ contains
s_M = min(0._wp, s_L); s_P = max(0._wp, s_R)

! goes with q_star_L/R = xi_L/R * (variable) xi_L/R = ( ( s_L/R - u_L/R )/(s_L/R - s_star) )
xi_L = (s_L - vel_L(dir_idx(1)))/(s_L - s_S)
xi_R = (s_R - vel_R(dir_idx(1)))/(s_R - s_S)
xi_L = (s_L - vel_L(dir_idx(1)))/min(s_L - s_S, -sgm_eps)
xi_R = (s_R - vel_R(dir_idx(1)))/max(s_R - s_S, sgm_eps)
! xi_L/R - 1 = (s_S - u_L/R)/(s_L/R - s_star): avoids cancellation when xi \approx 1
xi_L_m1 = (s_S - vel_L(dir_idx(1)))/min(s_L - s_S, -sgm_eps)
xi_R_m1 = (s_S - vel_R(dir_idx(1)))/max(s_R - s_S, sgm_eps)

! goes with numerical velocity in x/y/z directions xi_P/M = 0.5 +/m sgn(0.5,s_star)
xi_M = (5.e-1_wp + sign(5.e-1_wp, s_S))
Expand All @@ -3145,30 +3150,31 @@ contains
$:GPU_LOOP(parallelism='[seq]')
do i = 1, eqn_idx%cont%end
flux_rs${XYZ}$_vf(j, k, l, i) = xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, &
& i)*(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) + xi_P*qR_prim_rs${XYZ}$_vf(j &
& + 1, k, l, i)*(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp))
& i)*(vel_L(dir_idx(1)) + s_M*xi_L_m1) + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, &
& k, l, i)*(vel_R(dir_idx(1)) + s_P*xi_R_m1)
end do

! MOMENTUM FLUX. f = \rho u u - \sigma, q = \rho u, q_star = \xi * \rho*(s_star, v, w)
! MOMENTUM FLUX. f = \rho u u - \sigma, q = \rho u, q_star = \xi * \rho*(s_star, v, w) identity:
! xi*(dir_flg*s_S+(1-dir_flg)*u_i)-u_i = (dir_flg*s_L/R+(1-dir_flg)*u_i)*xi_m1
$:GPU_LOOP(parallelism='[seq]')
do i = 1, num_dims
flux_rs${XYZ}$_vf(j, k, l, &
& eqn_idx%cont%end + dir_idx(i)) = xi_M*(rho_L*(vel_L(dir_idx(1)) &
& *vel_L(dir_idx(i)) + s_M*(xi_L*(dir_flg(dir_idx(i))*s_S + (1._wp &
& - dir_flg(dir_idx(i)))*vel_L(dir_idx(i))) - vel_L(dir_idx(i)))) &
& + dir_flg(dir_idx(i))*(pres_L)) + xi_P*(rho_R*(vel_R(dir_idx(1)) &
& *vel_R(dir_idx(i)) + s_P*(xi_R*(dir_flg(dir_idx(i))*s_S + (1._wp &
& - dir_flg(dir_idx(i)))*vel_R(dir_idx(i))) - vel_R(dir_idx(i)))) &
& + dir_flg(dir_idx(i))*(pres_R)) + (s_M/s_L)*(s_P/s_R)*dir_flg(dir_idx(i)) &
& *pcorr
& *vel_L(dir_idx(i)) + s_M*(dir_flg(dir_idx(i))*s_L + (1._wp &
& - dir_flg(dir_idx(i)))*vel_L(dir_idx(i)))*xi_L_m1) + dir_flg(dir_idx(i)) &
& *(pres_L)) + xi_P*(rho_R*(vel_R(dir_idx(1))*vel_R(dir_idx(i)) &
& + s_P*(dir_flg(dir_idx(i))*s_R + (1._wp - dir_flg(dir_idx(i))) &
& *vel_R(dir_idx(i)))*xi_R_m1) + dir_flg(dir_idx(i))*(pres_R)) + (s_M/s_L) &
& *(s_P/s_R)*dir_flg(dir_idx(i))*pcorr
end do

! ENERGY FLUX. f = u*(E-\sigma), q = E, q_star = \xi*E+(s-u)(\rho s_star - \sigma/(s-u))
! xi*(E+expr)-E = E*xi_m1 + xi*expr avoids E*(xi-1) cancellation
flux_rs${XYZ}$_vf(j, k, l, &
& eqn_idx%E) = xi_M*(vel_L(dir_idx(1))*(E_L + pres_L) + s_M*(xi_L*(E_L + (s_S &
& - vel_L(dir_idx(1)))*(rho_L*s_S + pres_L/(s_L - vel_L(dir_idx(1))))) - E_L)) &
& + xi_P*(vel_R(dir_idx(1))*(E_R + pres_R) + s_P*(xi_R*(E_R + (s_S &
& - vel_R(dir_idx(1)))*(rho_R*s_S + pres_R/(s_R - vel_R(dir_idx(1))))) - E_R)) &
& eqn_idx%E) = xi_M*(vel_L(dir_idx(1))*(E_L + pres_L) + s_M*(E_L*xi_L_m1 &
& + xi_L*(s_S - vel_L(dir_idx(1)))*(rho_L*s_S + pres_L/(s_L - vel_L(dir_idx(1))) &
& ))) + xi_P*(vel_R(dir_idx(1))*(E_R + pres_R) + s_P*(E_R*xi_R_m1 + xi_R*(s_S &
& - vel_R(dir_idx(1)))*(rho_R*s_S + pres_R/(s_R - vel_R(dir_idx(1)))))) &
& + (s_M/s_L)*(s_P/s_R)*pcorr*s_S

! ELASTICITY. Elastic shear stress additions for the momentum and energy flux
Expand Down Expand Up @@ -3206,25 +3212,25 @@ contains
$:GPU_LOOP(parallelism='[seq]')
do i = eqn_idx%adv%beg, eqn_idx%adv%end
flux_rs${XYZ}$_vf(j, k, l, i) = xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, &
& i)*(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) + xi_P*qR_prim_rs${XYZ}$_vf(j &
& + 1, k, l, i)*(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp))
& i)*(vel_L(dir_idx(1)) + s_M*xi_L_m1) + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, &
& k, l, i)*(vel_R(dir_idx(1)) + s_P*xi_R_m1)
end do

! VOLUME FRACTION SOURCE FLUX.
$:GPU_LOOP(parallelism='[seq]')
do i = 1, num_dims
vel_src_rs${XYZ}$_vf(j, k, l, &
& dir_idx(i)) = xi_M*(vel_L(dir_idx(i)) + dir_flg(dir_idx(i))*s_M*(xi_L &
& - 1._wp)) + xi_P*(vel_R(dir_idx(i)) + dir_flg(dir_idx(i))*s_P*(xi_R &
& - 1._wp))
& dir_idx(i)) = xi_M*(vel_L(dir_idx(i)) + dir_flg(dir_idx(i)) &
& *s_M*xi_L_m1) + xi_P*(vel_R(dir_idx(i)) + dir_flg(dir_idx(i)) &
& *s_P*xi_R_m1)
end do

! COLOR FUNCTION FLUX
if (surface_tension) then
flux_rs${XYZ}$_vf(j, k, l, eqn_idx%c) = xi_M*qL_prim_rs${XYZ}$_vf(j, k, l, &
& eqn_idx%c)*(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) &
& eqn_idx%c)*(vel_L(dir_idx(1)) + s_M*xi_L_m1) &
& + xi_P*qR_prim_rs${XYZ}$_vf(j + 1, k, l, &
& eqn_idx%c)*(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp))
& eqn_idx%c)*(vel_R(dir_idx(1)) + s_P*xi_R_m1)
end if

! Hyperelastic reference map flux for material deformation tracking
Expand All @@ -3248,8 +3254,8 @@ contains
Y_R = qR_prim_rs${XYZ}$_vf(j + 1, k, l, i)

flux_rs${XYZ}$_vf(j, k, l, &
& i) = xi_M*rho_L*Y_L*(vel_L(dir_idx(1)) + s_M*(xi_L - 1._wp)) &
& + xi_P*rho_R*Y_R*(vel_R(dir_idx(1)) + s_P*(xi_R - 1._wp))
& i) = xi_M*rho_L*Y_L*(vel_L(dir_idx(1)) + s_M*xi_L_m1) &
& + xi_P*rho_R*Y_R*(vel_R(dir_idx(1)) + s_P*xi_R_m1)
flux_src_rs${XYZ}$_vf(j, k, l, i) = 0.0_wp
end do
end if
Expand Down
39 changes: 39 additions & 0 deletions tests/fp_stability/cases/air_water_interface/pre_process.inp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions tests/fp_stability/cases/air_water_interface/simulation.inp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions tests/fp_stability/cases/bubble_rp/pre_process.inp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading