2026-07-26 06:47:36 +00:00
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR = " $( cd " $( dirname " ${ BASH_SOURCE [0] } " ) /.. " && pwd -P) "
JOBS = " ${ JOBS :- $( nproc) } "
PYTHON_BIN = " ${ PYTHON_BIN :- ${ ROOT_DIR } /.venv/bin/python } "
REPORT = ""
PASSTHRU = ( )
while [ [ $# -gt 0 ] ] ; do
case " $1 " in
--report)
if [ [ $# -lt 2 ] ] ; then
echo "--report requires a path" >& 2
exit 2
fi
REPORT = " $2 "
PASSTHRU += ( " $1 " " $2 " )
shift 2
; ;
--report= *)
REPORT = " ${ 1 #--report= } "
PASSTHRU += ( " $1 " )
shift
; ;
--backend| --backend= *)
echo "verify_gpu_rans_solver.sh always requests --backend gpu; do not pass --backend" >& 2
exit 2
; ;
*)
PASSTHRU += ( " $1 " )
shift
; ;
esac
done
if [ [ -z " ${ REPORT } " ] ] ; then
echo "--report is required so the full GPU RANS guard can inspect verifier evidence" >& 2
exit 2
fi
if [ [ ! -x " ${ PYTHON_BIN } " ] ] ; then
uv sync --dev
fi
if ! PYTHONPATH = " ${ PYTHON_BIN } " -c 'import pybind11, numpy, quadrants' >/dev/null 2>& 1; then
uv sync --dev
fi
" ${ ROOT_DIR } /scripts/build_openfoam_airfrans_subset.sh " >/dev/null
set +u
source " ${ ROOT_DIR } /OpenFOAM-14/etc/bashrc " \
WM_MPLIB = Dummy \
ParaView_TYPE = none \
SCOTCH_TYPE = none \
ZOLTAN_TYPE = none
set -u
unset FOAM_SIGFPE
" ${ ROOT_DIR } /scripts/build_python_stepper.sh " >/dev/null
set +e
PYTHONPATH = " ${ PYTHON_BIN } " " ${ ROOT_DIR } /scripts/verify_airfrans_stepper.py " --backend gpu " ${ PASSTHRU [@] } "
VERIFY_STATUS = $?
set -e
PYTHONPATH = " ${ PYTHON_BIN } " - " ${ REPORT } " " ${ VERIFY_STATUS } " <<'PY'
from __future__ import annotations
import json
import sys
from pathlib import Path
report_path = Path( sys.argv[ 1] )
verify_status = int( sys.argv[ 2] )
required_fields = ( "U" , "p" , "phi" , "nut" , "k" , "omega" )
required_modes = ( "run_one" , "split" )
failures: list[ str] = [ ]
if not report_path.exists( ) :
failures.append( f"report missing: {report_path}" )
report = { }
else :
try:
report = json.loads( report_path.read_text( ) )
except Exception as exc: # pragma: no cover - shell guard diagnostic
failures.append( f"report is not valid JSON: {exc}" )
report = { }
def require( condition: bool, message: str) -> None:
if not condition:
failures.append( message)
backend = report.get( "backend" ) if isinstance( report.get( "backend" ) , dict) else { }
verifier_evidence = report.get( "verifier_evidence" ) if isinstance( report.get( "verifier_evidence" ) , dict) else { }
2026-07-27 08:35:44 +00:00
backend_trust = ( ( verifier_evidence.get( "mode_criteria" ) or { } ) .get( "backend_trust" ) or { } ) if isinstance( verifier_evidence.get( "mode_criteria" ) , dict) else { }
2026-07-26 06:47:36 +00:00
modes = report.get( "modes" ) if isinstance( report.get( "modes" ) , dict) else { }
provider = str( backend.get( "provider" ) or "" ) .lower( )
device = str( backend.get( "device" ) or "" ) .lower( )
2026-07-27 08:35:44 +00:00
capabilities = set( backend.get( "capabilities" ) or [ ] )
primitive = backend.get( "primitive_evidence" ) if isinstance( backend.get( "primitive_evidence" ) , dict) else { }
2026-07-26 06:47:36 +00:00
require( verify_status = = 0, f"underlying AirfRANS verifier exited {verify_status}" )
require( report.get( "status" ) = = "passed" , f"report.status is {report.get('status')!r}, expected 'passed'" )
require( backend.get( "requested" ) = = "gpu" , f"backend.requested is {backend.get('requested')!r}, expected 'gpu'" )
require( backend.get( "selected" ) = = "gpu" , f"backend.selected is {backend.get('selected')!r}, expected 'gpu'" )
require( "cpu" not in provider and provider not in { "foam_stepper_cpu" , "openfoam" } , f"backend.provider looks CPU-backed: {backend.get('provider')!r}" )
require( device not in { "host" , "cpu" } , f"backend.device looks CPU-backed: {backend.get('device')!r}" )
2026-07-27 08:35:44 +00:00
require( backend.get( "used_cpu_fallback" ) is False, f"backend.used_cpu_fallback is {backend.get('used_cpu_fallback')!r}, expected false" )
require( ( backend.get( "cpu_fallback" ) or { } ) .get( "allowed" ) is False, "backend.cpu_fallback.allowed is not false" )
require( "no_cpu_fallback" in capabilities, "backend capabilities do not include no_cpu_fallback" )
require( primitive.get( "counts_as_full_gpu_rans_solver" ) is False, "primitive GPU evidence is not explicitly marked non-acceptance" )
require( backend_trust.get( "status" ) = = "trusted" , f"backend trust status is {backend_trust.get('status')!r}, expected 'trusted'" )
2026-07-26 06:47:36 +00:00
require( verifier_evidence.get( "passed" ) is True, "verifier_evidence.passed is not true" )
for mode_name in required_modes:
mode = modes.get( mode_name) if isinstance( modes.get( mode_name) , dict) else { }
require( mode.get( "enabled" ) is True, f"modes.{mode_name}.enabled is not true" )
mode_backend = mode.get( "backend" ) if isinstance( mode.get( "backend" ) , dict) else backend
require( mode_backend.get( "selected" ) = = "gpu" , f"modes.{mode_name}.backend.selected is not 'gpu'" )
execution_path = str( mode.get( "execution_path" ) or "" ) .lower( )
require( "gpu" in execution_path, f"modes.{mode_name}.execution_path does not identify a GPU path: {mode.get('execution_path')!r}" )
2026-07-27 08:35:44 +00:00
require( mode_backend.get( "used_cpu_fallback" ) is False, f"modes.{mode_name}.backend.used_cpu_fallback is not false" )
gpu_solver = mode.get( "gpu_solver" ) if isinstance( mode.get( "gpu_solver" ) , dict) else { }
gpu_solver_backend = gpu_solver.get( "backend" ) if isinstance( gpu_solver.get( "backend" ) , dict) else { }
require( gpu_solver.get( "status" ) = = "executed" , f"modes.{mode_name}.gpu_solver.status is not executed" )
require( gpu_solver_backend.get( "selected" ) = = "gpu" , f"modes.{mode_name}.gpu_solver.backend.selected is not 'gpu'" )
require( gpu_solver_backend.get( "used_cpu_fallback" ) is False, f"modes.{mode_name}.gpu_solver.backend.used_cpu_fallback is not false" )
2026-07-26 06:47:36 +00:00
comparisons = mode.get( "comparisons" ) if isinstance( mode.get( "comparisons" ) , dict) else { }
for field in required_fields:
comparison = comparisons.get( field) if isinstance( comparisons.get( field) , dict) else { }
require( comparison.get( "allclose" ) is True, f"modes.{mode_name}.comparisons.{field}.allclose is not true" )
require( "actual_shape" in comparison or "shape" in comparison, f"modes.{mode_name}.comparisons.{field} has no actual shape evidence" )
require( "expected_shape" in comparison or "shape" in comparison, f"modes.{mode_name}.comparisons.{field} has no expected shape evidence" )
require( "max_abs" in comparison or "max_abs_error" in comparison, f"modes.{mode_name}.comparisons.{field} has no max error evidence" )
if failures:
print( "full GPU RANS solver guard failed:" , file = sys.stderr)
for failure in failures:
print( f"- {failure}" , file = sys.stderr)
print( f"report={report_path}" , file = sys.stderr)
sys.exit( 1)
print( "full GPU RANS solver guard passed" )
print( f"report={report_path}" )
PY