Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
585eed5
Add 2D isentropic vortex convergence test and hcid=283 GL IC
sbryngelson May 6, 2026
aa557b2
Add convergence CI workflow for 2D isentropic vortex
sbryngelson May 6, 2026
403470b
Use weak vortex (eps=0.01) to reveal WENO5 rate-5 convergence
sbryngelson May 6, 2026
a4dd621
Add 1D advection convergence test; split CI into 1D and 2D jobs
sbryngelson May 6, 2026
7558af4
Extend CI resolutions: 1D to N=256, 2D to N=128
sbryngelson May 6, 2026
b96d303
Switch 1D convergence to single-fluid Euler; add muscl_lim=0 unlimited
sbryngelson May 6, 2026
da94a26
Fix 2D convergence CI: start at N=32, lower WENO3 threshold to 1.8
sbryngelson May 6, 2026
22822a0
1D convergence: raise resolutions to 128-1024, tighten WENO1 threshol…
sbryngelson May 6, 2026
ff0cfa3
Add per-scheme min_N/max_N bounds and tighten convergence thresholds
sbryngelson May 6, 2026
af94035
Restrict convergence CI to workflow_dispatch only
sbryngelson May 6, 2026
12c8ac0
Trigger convergence CI on push to master and workflow_dispatch
sbryngelson May 6, 2026
3a069d2
Trigger convergence CI on push to any branch
sbryngelson May 6, 2026
3592620
Add TENO5, WENO7, TENO7 to convergence runners
sbryngelson May 6, 2026
b43873d
Fix convergence CI: activate MFC venv before running runners
sbryngelson May 6, 2026
98623f1
Fix convergence runners: let MFC build case-specific binaries
sbryngelson May 6, 2026
09266d1
Use per-scheme CFL for WENO7/TENO7 to expose 7th-order spatial rate
sbryngelson May 6, 2026
c7d3ff4
Fix WENO7/TENO7 convergence test resolution windows
sbryngelson May 6, 2026
76e1d26
Add --num-ranks to convergence runners; use 4 MPI ranks in CI
sbryngelson May 7, 2026
4ea3182
Fix readers to collect data from all MPI ranks
sbryngelson May 7, 2026
5336315
Add RK3 temporal order verification runner and CI job
sbryngelson May 7, 2026
14e4076
Add RK1/RK2/RK3 temporal order verification; add --time-stepper to 1D…
sbryngelson May 7, 2026
1d8a888
Add conservation checks (density, momentum, energy) to all convergenc…
sbryngelson May 7, 2026
c188577
Fix CI: set OMPI_MCA_rmaps_base_oversubscribe=1 to allow 4 ranks on 2…
sbryngelson May 7, 2026
76e7e0c
Add Sod shock tube L1 self-convergence runner across all MFC schemes
sbryngelson May 7, 2026
728e1d7
Fix 2D convergence: set min_N=64 for WENO5/TENO5 and exclude momentum…
sbryngelson May 7, 2026
93380a5
Fix Sod runner: add min_N per scheme, set min_N=128 for MUSCL-SUPERBEE
sbryngelson May 7, 2026
781912b
Fix convergence CI: only run on push to master and PRs
sbryngelson May 7, 2026
5d2e710
Skip convergence example dirs in main regression test suite
sbryngelson May 7, 2026
4346aa5
Improve error handling in convergence runners: print stderr on failur…
sbryngelson May 7, 2026
743016a
Add 2D axisymmetric WENO5 convergence test and fix three bugs
sbryngelson May 8, 2026
5b00648
Revert HLL/LF adv gsrc change; update comment to explain PR #800 intent
sbryngelson May 8, 2026
bf2712d
Merge branch 'master' into fix/axisym-single-fluid-nan
sbryngelson May 9, 2026
418df66
fix: extract single-fluid alpha reset to subroutine to dodge AMD flan…
sbryngelson May 9, 2026
cb935f8
test: skip 2D_axisym_convergence example test (WENO5 needs nr>=26)
sbryngelson May 9, 2026
b239015
Delete docs/superpowers/plans/2026-05-05-convergence-ci.md
sbryngelson May 9, 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
154 changes: 154 additions & 0 deletions .github/workflows/convergence.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
name: Convergence

on:
push:
branches: [master]
pull_request:
workflow_dispatch:

env:
OMPI_MCA_rmaps_base_oversubscribe: 1

jobs:
convergence-1d:
name: "1D Advection Convergence"
runs-on: ubuntu-latest
timeout-minutes: 60

steps:
- uses: actions/checkout@v4

- name: Setup Ubuntu
run: |
sudo apt update -y
sudo apt install -y cmake gcc g++ python3 python3-dev \
openmpi-bin libopenmpi-dev

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Initialize MFC
run: ./mfc.sh init

- name: Run 1D convergence tests
run: |
source build/venv/bin/activate
python toolchain/mfc/test/run_convergence_1d.py \
--resolutions 64 128 256 512 1024 \
--num-ranks 4

convergence-2d:
name: "2D Isentropic Vortex Convergence"
runs-on: ubuntu-latest
timeout-minutes: 60

steps:
- uses: actions/checkout@v4

- name: Setup Ubuntu
run: |
sudo apt update -y
sudo apt install -y cmake gcc g++ python3 python3-dev \
openmpi-bin libopenmpi-dev

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Initialize MFC
run: ./mfc.sh init

- name: Run 2D convergence tests
run: |
source build/venv/bin/activate
python toolchain/mfc/test/run_convergence.py \
--resolutions 32 64 128 \
--num-ranks 4

convergence-sod:
name: "1D Sod Shock Tube L1 Convergence"
runs-on: ubuntu-latest
timeout-minutes: 90

steps:
- uses: actions/checkout@v4

- name: Setup Ubuntu
run: |
sudo apt update -y
sudo apt install -y cmake gcc g++ python3 python3-dev \
openmpi-bin libopenmpi-dev

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Initialize MFC
run: ./mfc.sh init

- name: Run Sod shock tube L1 convergence tests
run: |
source build/venv/bin/activate
python toolchain/mfc/test/run_sod.py \
--resolutions 64 128 256 512 \
--num-ranks 4

convergence-2d-axisym:
name: "2D Axisymmetric WENO5 Convergence"
runs-on: ubuntu-latest
timeout-minutes: 60

steps:
- uses: actions/checkout@v4

- name: Setup Ubuntu
run: |
sudo apt update -y
sudo apt install -y cmake gcc g++ python3 python3-dev \
openmpi-bin libopenmpi-dev

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Initialize MFC
run: ./mfc.sh init

- name: Run 2D axisymmetric convergence test
run: |
source build/venv/bin/activate
python toolchain/mfc/test/run_convergence_axisym.py \
--resolutions 64 128 256

convergence-temporal:
name: "RK3 Temporal Order"
runs-on: ubuntu-latest
timeout-minutes: 60

steps:
- uses: actions/checkout@v4

- name: Setup Ubuntu
run: |
sudo apt update -y
sudo apt install -y cmake gcc g++ python3 python3-dev \
openmpi-bin libopenmpi-dev

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Initialize MFC
run: ./mfc.sh init

- name: Run temporal order tests
run: |
source build/venv/bin/activate
python toolchain/mfc/test/run_temporal_order.py \
--num-ranks 4
103 changes: 103 additions & 0 deletions examples/1D_advection_convergence/case.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/usr/bin/env python3
"""
1D periodic advection convergence case.

Two identical fluids (same gamma, same density = 1) with a sine-wave volume
fraction. Since both EOS are identical, alpha_1 advects passively at u = 1
with no acoustic coupling. After exactly one period (T = L/u = 1), the
exact solution equals the IC, so L2(q_cons_vf1(T) - q_cons_vf1(0)) is
purely the scheme's accumulated spatial truncation error.
"""

import argparse
import json
import math

parser = argparse.ArgumentParser(description="1D advection convergence case")
parser.add_argument("--mfc", type=json.loads, default="{}", metavar="DICT")
parser.add_argument("-N", type=int, default=64, help="Grid points (default: 64)")
parser.add_argument("--order", type=int, default=5, help="WENO order: 1, 3, or 5")
parser.add_argument("--muscl", action="store_true", help="Use MUSCL-2 instead of WENO")
parser.add_argument("--cfl", type=float, default=0.4, help="CFL number (default: 0.4)")
parser.add_argument("--mp-weno", action="store_true", help="Enable MP-WENO limiter")
parser.add_argument("--muscl-lim", type=int, default=1, help="MUSCL limiter: 1=minmod 2=MC 3=VanAlbada 4=VanLeer 5=Superbee")
args = parser.parse_args()

gamma = 1.4
N = args.N
m = N - 1
L = 1.0
dx = L / N

# Max wave speed: acoustic speed + convective speed
# c_sound = sqrt(gamma * p / rho) = sqrt(gamma) ≈ 1.183 (for p=1, rho=1)
c_max = math.sqrt(gamma) + 1.0
dt = args.cfl * dx / c_max
T_end = 1.0 # exactly one period: u=1, L=1
Nt = max(4, math.ceil(T_end / dt))
dt = T_end / Nt # snap to land exactly on T_end

if args.muscl:
scheme_params = {
"recon_type": 2,
"muscl_order": 2,
"muscl_lim": args.muscl_lim,
}
else:
scheme_params = {
"recon_type": 1,
"weno_order": args.order,
"weno_eps": 1.0e-16,
"weno_Re_flux": "F",
"weno_avg": "F",
"mapped_weno": "F" if args.order == 1 else "T",
"null_weights": "F",
"mp_weno": "T" if args.mp_weno else "F",
}

print(
json.dumps(
{
"run_time_info": "F",
"x_domain%beg": 0.0,
"x_domain%end": L,
"m": m,
"n": 0,
"p": 0,
"dt": dt,
"t_step_start": 0,
"t_step_stop": Nt,
"t_step_save": Nt,
"num_patches": 1,
"model_eqns": 2,
"alt_soundspeed": "F",
"num_fluids": 2,
"mpp_lim": "F",
"mixture_err": "F",
"time_stepper": 3,
"riemann_solver": 2,
"wave_speeds": 1,
"avg_state": 2,
"bc_x%beg": -1,
"bc_x%end": -1,
"format": 1,
"precision": 2,
"prim_vars_wrt": "T",
"parallel_io": "F",
"patch_icpp(1)%geometry": 1,
"patch_icpp(1)%x_centroid": 0.5,
"patch_icpp(1)%length_x": L,
"patch_icpp(1)%vel(1)": 1.0,
"patch_icpp(1)%pres": 1.0,
"patch_icpp(1)%alpha_rho(1)": "0.5 + 0.2 * sin(2.0 * pi * x / lx)",
"patch_icpp(1)%alpha_rho(2)": "0.5 - 0.2 * sin(2.0 * pi * x / lx)",
"patch_icpp(1)%alpha(1)": "0.5 + 0.2 * sin(2.0 * pi * x / lx)",
"patch_icpp(1)%alpha(2)": "0.5 - 0.2 * sin(2.0 * pi * x / lx)",
"fluid_pp(1)%gamma": 1.0 / (gamma - 1.0),
"fluid_pp(1)%pi_inf": 0.0,
"fluid_pp(2)%gamma": 1.0 / (gamma - 1.0),
"fluid_pp(2)%pi_inf": 0.0,
**scheme_params,
}
)
)
105 changes: 105 additions & 0 deletions examples/1D_euler_convergence/case.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env python3
"""
1D single-fluid Euler convergence case.

Single fluid with a density sine wave: rho = 1 + 0.2*sin(2*pi*x).
Constant velocity u=1 and pressure p=1. For this IC, the Euler equations
reduce to pure advection of all variables at speed u=1. After exactly one
period (T = L/u = 1), the exact solution equals the IC, so
L2(rho(T) - rho(0)) measures the accumulated scheme spatial truncation error.

No non-conservative alpha equation — clean benchmark for WENO/MUSCL rates.
"""

import argparse
import json
import math

parser = argparse.ArgumentParser(description="1D Euler convergence case")
parser.add_argument("--mfc", type=json.loads, default="{}", metavar="DICT")
parser.add_argument("-N", type=int, default=64, help="Grid points (default: 64)")
parser.add_argument("--order", type=int, default=5, help="WENO order: 1, 3, 5, or 7")
parser.add_argument("--muscl", action="store_true", help="Use MUSCL-2 instead of WENO")
parser.add_argument("--teno", action="store_true", help="Use TENO instead of WENO")
parser.add_argument("--teno-ct", type=float, default=1e-6, help="TENO CT threshold (default: 1e-6)")
parser.add_argument("--cfl", type=float, default=0.4, help="CFL number (default: 0.4)")
parser.add_argument("--no-mapped", action="store_true", help="Disable mapped WENO")
parser.add_argument("--muscl-lim", type=int, default=0, help="MUSCL limiter: 0=unlimited 1=minmod ... (default: 0)")
parser.add_argument("--time-stepper", type=int, default=3, help="Time stepper: 1=Euler 2=RK2 3=RK3 (default: 3)")
args = parser.parse_args()

gamma = 1.4
N = args.N
m = N - 1
L = 1.0
dx = L / N

# c_sound = sqrt(gamma * p / rho) = sqrt(gamma) for p=1, rho=1
c_max = math.sqrt(gamma) + 1.0 # acoustic + convective
dt = args.cfl * dx / c_max
T_end = 1.0
Nt = max(4, math.ceil(T_end / dt))
dt = T_end / Nt

if args.muscl:
scheme_params = {
"recon_type": 2,
"muscl_order": 2,
"muscl_lim": args.muscl_lim,
}
else:
scheme_params = {
"recon_type": 1,
"weno_order": args.order,
"weno_eps": 1.0e-40,
"weno_Re_flux": "F",
"weno_avg": "F",
"mapped_weno": "F" if (args.order == 1 or args.no_mapped or args.teno) else "T",
"null_weights": "F",
"mp_weno": "F",
"teno": "T" if args.teno else "F",
**({"teno_CT": args.teno_ct} if args.teno else {}),
}

print(
json.dumps(
{
"run_time_info": "F",
"x_domain%beg": 0.0,
"x_domain%end": L,
"m": m,
"n": 0,
"p": 0,
"dt": dt,
"t_step_start": 0,
"t_step_stop": Nt,
"t_step_save": Nt,
"num_patches": 1,
"model_eqns": 2,
"alt_soundspeed": "F",
"num_fluids": 1,
"mpp_lim": "F",
"mixture_err": "F",
"time_stepper": args.time_stepper,
"riemann_solver": 2,
"wave_speeds": 1,
"avg_state": 2,
"bc_x%beg": -1,
"bc_x%end": -1,
"format": 1,
"precision": 2,
"prim_vars_wrt": "T",
"parallel_io": "F",
"patch_icpp(1)%geometry": 1,
"patch_icpp(1)%x_centroid": 0.5,
"patch_icpp(1)%length_x": L,
"patch_icpp(1)%vel(1)": 1.0,
"patch_icpp(1)%pres": 1.0,
"patch_icpp(1)%alpha_rho(1)": "1.0 + 0.2 * sin(2.0 * pi * x / lx)",
"patch_icpp(1)%alpha(1)": 1.0,
"fluid_pp(1)%gamma": 1.0 / (gamma - 1.0),
"fluid_pp(1)%pi_inf": 0.0,
**scheme_params,
}
)
)
Loading
Loading