Skip to content

Density correction v37: pooled n=484 refit (supersedes v33) (#49) #163

Density correction v37: pooled n=484 refit (supersedes v33) (#49)

Density correction v37: pooled n=484 refit (supersedes v33) (#49) #163

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
fortran-syntax:
name: Fortran syntax check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install gfortran
run: sudo apt-get update && sudo apt-get install -y gfortran
- name: Check base module files compile
run: |
PASS=0
FAIL=0
# Check critical base files that have been modernized
# Note: CONTRL.f90 excluded because it INCLUDEs variant headers
for f in src-converted/base/main.f90 \
src-converted/base/myopen.f90 \
src-converted/base/volkey.f90 \
src-converted/base/algevl.f90 \
src-converted/base/evldx.f90 \
src-converted/base/errgro.f90; do
if [ -f "$f" ]; then
if gfortran -c -fsyntax-only -ffree-form -fPIC "$f" 2>/dev/null; then
echo "[OK] $f"
PASS=$((PASS+1))
else
echo "[FAIL] $f"
FAIL=$((FAIL+1))
fi
fi
done
echo ""
echo "Results: $PASS passed, $FAIL failed"
[ "$FAIL" -eq 0 ] || exit 1
build-ne-variant:
name: Build FVS-NE shared library
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install gfortran
run: sudo apt-get update && sudo apt-get install -y gfortran
- name: Build NE variant
run: |
bash deployment/scripts/build_fvs_libraries.sh \
src-converted lib ne
echo ""
echo "Build output:"
ls -lh lib/FVS*.so 2>/dev/null || echo "No .so files produced"
- name: Verify NE library symbols
run: |
SO=lib/FVSne.so
if [ ! -f "$SO" ]; then
echo "FAIL: FVSne.so not found"
exit 1
fi
SIZE=$(stat -c%s "$SO")
echo "FVSne.so size: $SIZE bytes"
if [ "$SIZE" -lt 1000000 ]; then
echo "FAIL: Library suspiciously small (<1MB)"
exit 1
fi
# Check API symbols that fvs2py and rFVS use to drive simulations
MISSING=0
for sym in fvssetcmdline_ fvssummary_ fvsdimsizes_ fvstreeattr_ volinit_; do
if nm "$SO" 2>/dev/null | grep -q " [Tt] ${sym}"; then
echo "[OK] $sym"
else
echo "[WARN] $sym not found"
MISSING=$((MISSING+1))
fi
done
# fvssetcmdline_ and fvssummary_ are essential API entry points
for sym in fvssetcmdline_ fvssummary_; do
nm "$SO" 2>/dev/null | grep -q " [Tt] ${sym}" || {
echo "FAIL: critical API symbol $sym missing"
exit 1
}
done
echo ""
TOTAL=$(nm "$SO" 2>/dev/null | grep -c " T ")
echo "Total exported text symbols: $TOTAL"
- name: Python ctypes load test
run: |
python3 << 'PYEOF'
import ctypes, ctypes.util, os, sys
so_path = os.path.abspath('lib/FVSne.so')
print(f'Loading {so_path} via ctypes...')
# FVS .so files have some unresolved internal symbols (e.g., debug_mod
# from NVEL) that are harmless at runtime but cause RTLD_NOW to fail
# on some Python/glibc combinations. Use RTLD_LAZY (0x1 on Linux).
RTLD_LAZY = 0x1
try:
lib = ctypes.CDLL(so_path, mode=RTLD_LAZY)
except OSError:
# Fallback: try default mode (works on some Python versions)
try:
lib = ctypes.CDLL(so_path)
except OSError as e:
print(f'FAIL: Could not load library: {e}')
sys.exit(1)
print(f' Loaded successfully: {lib._name}')
# Verify key API functions are callable
api_funcs = ['fvssetcmdline_', 'fvssummary_', 'fvsdimsizes_']
for fname in api_funcs:
try:
fn = getattr(lib, fname)
print(f' [OK] {fname} -> {fn}')
except AttributeError:
print(f' [WARN] {fname} not found')
# Verify fvssetcmdline_ is present (critical for any simulation)
try:
_ = lib.fvssetcmdline_
print()
print('PASS: FVSne.so loads and API entry points are accessible')
except AttributeError:
print('FAIL: fvssetcmdline_ missing from loaded library')
sys.exit(1)
PYEOF
build-executables:
name: Build FVS executables (NE, LS)
needs: build-ne-variant
runs-on: ubuntu-latest
# Exe builds may fail on CI due to gfortran version differences in
# F77->F90 conversion handling. This job is informational: the
# .so library build (above) is the gate that must pass.
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Install gfortran
run: sudo apt-get update && sudo apt-get install -y gfortran
- name: Build shared libraries (needed for fallback linking)
run: bash deployment/scripts/build_fvs_libraries.sh . lib ne ls
- name: Build executables (NE + LS)
run: |
echo "gfortran version: $(gfortran --version | head -1)"
ls -lh lib/FVS*.so 2>/dev/null || echo "No .so files yet"
echo ""
bash deployment/scripts/build_fvs_executables.sh . lib ne ls || true
echo ""
ls -lh lib/FVS* 2>/dev/null || echo "No executables found"
echo ""
for var in ne ls; do
EXE="lib/FVS${var}"
if [ -f "$EXE" ]; then
SIZE=$(stat -c%s "$EXE")
echo "FVS${var}: $SIZE bytes"
else
echo "FVS${var}: not built (gfortran version may differ from local)"
fi
done
- name: Smoke test (banner prints and exits)
run: |
export LD_LIBRARY_PATH="$(pwd)/lib:${LD_LIBRARY_PATH:-}"
for var in ne ls; do
EXE="./lib/FVS${var}"
if [ ! -f "$EXE" ]; then
echo "SKIP: FVS${var} not available"
continue
fi
OUTPUT=$(echo "" | timeout 10 "$EXE" 2>&1 || true)
echo "=== FVS${var} ==="
echo "$OUTPUT"
if echo "$OUTPUT" | grep -q "FVS VARIANT"; then
echo "PASS: FVS${var} banner detected"
else
echo "WARN: FVS${var} banner not found"
fi
done
nvel-audit:
name: NVEL coefficient audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Run NVEL upstream audit
run: |
python3 scripts/audit_nvel_upstream.py --verbose \
--allow-differ r8clist.inc
lint:
name: Lint scripts
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Shellcheck deployment scripts
run: |
ERRORS=0
for f in deployment/scripts/*.sh; do
echo "Checking $f..."
shellcheck --severity=error "$f" || ERRORS=$((ERRORS+1))
done
# Report but don't fail on shellcheck warnings for now
echo "Scripts with errors: $ERRORS"
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install ruff
run: pip install ruff
- name: Lint Python code
run: |
ruff check calibration/python/ deployment/fvs2py/ config/ \
--select=E,F,W --ignore=E501 || true