HEC-RAS failure taxonomy

HEC-RAS 6.6 Linux — Failure Taxonomy & Runtime Behavior

Experimental campaign 2026-10-12 on the Linux compute lab (~/workspace/hec-ras-research/hecras-v66-linux/, binaries via git LFS from github.com/neeraip/hecras-v66-linux). Muncie 2D example, Workflow A staging. Each experiment ran in its own /tmp/ras-exp-<name>/ from pristine inputs.

The single most important finding: exit code 0 means nothing. A 426%-volume-error run, a truncated HDF, and a missing plan file ALL exited 0. The only non-zero exits observed were Fortran file-not-found (29) and SIGKILL (137).


1. Per-experiment results

BASE (pristine, harness validation)

P1 — .b01 text interval 1MIN→10MIN (HDF still 1MIN)

A1 — HDF Computation Time Step Base → 12HOUR (.b01 still 1MIN)

A1b — .b01 text interval → 12HOUR (TRUE Courant violation; 2 steps for 24 h)

A2a / A2b — Manning's n → 0.5 / 0.001 (plan HDF Cells Center Manning's n)

A3 — .b01 deleted

A4 — plan HDF truncated to half

A5 — plan HDF deleted

A6 — zero-flow event (US BC hydrograph ordinates → 0 in plan HDF)

A7 — SIGKILL at 2 s (mid-run, was at SIMTIME 9.2/24 h)

B8a / B8b — baseline variance (pristine ×2 more)

B9 — .b01 text interval → 10SEC (6× steps)


2. Consolidated failure taxonomy

Failure mode Log signature Exit Triage
Missing input file forrtl: severe (29): file not found, unit NN, file <path> + Fortran traceback (openfiles_, Openfile.for) 29 Config error. Catchable pre-run by staging validation. Not retryable as-is.
Corrupt/truncated HDF HDF5-DIAG: Error detected … File has been truncated … HDF_ERROR trying to open HDF output file 0 ⚠️ Fatal. Exit code lies; must grep log. Never retry blindly.
Missing plan HDF HDF_ERROR trying to open HDF output file: <name> 0 ⚠️ Fatal. Same as above.
Courant violation (absurd dt) FONT= RED + Overall Volume Accounting Error as percentage: <huge> + The maximum cell wsel error was <x> + At <area> cell <n> … then Finished anyway 0 ⚠️ Config error. Engine won't save you — validate dt pre-run (Courant check vs cell size). Never trust Finished alone.
Killed / timeout No Finished line; exit 137 (SIGKILL) / 143 (SIGTERM); stray .bco01/.ic.o01/systemInfoEncoded.txt; HDF readable, no Results 137/143 Retryable after cleaning the run dir.
Silent bad physics (n ignored) No signature at all — bit-identical outputs 0 Validation gap. Detect by diffing inputs pre-run, not by reading logs.
Dry / zero-flow event None — completes normally, volume error ~0.08% 0 Not a failure. No special-casing.

3. Log parser spec

What to key on (in priority order):

  1. Pass/fail: Overall Volume Accounting Error as percentage: — the ONLY trustworthy quality signal. Suggested gates: warn > 1%, fail > 5% (baseline 0.05%; 10MIN dt gave 0.77%; 12HOUR dt gave 427%).
  2. Completion: Finished Unsteady Flow Simulation / Finished Processing Geometry — necessary but NOT sufficient (A1b printed it with 427% error).
  3. Color markers: FONT= RED = bad news nearby (volume error); FONT= BLUE = warning (maximum cell wsel error); FONT= GREEN BOLD = done. All other FONT= lines are noise — strip them.
  4. Phase tracking: LABEL= <phase> — Reading Data, Initializing, Reading 2D Area(s), initializing 2D Area(s), Initial Backwater, Unsteady Flow Computations. Use for progress reporting.
  5. Step tracking: SIMTIME= <hours> + ABSDATE=/ABSTIME= per output step; ITER2D= <n> (nonzero = solver iterating that step; long nonzero runs = struggling). PROGRESS= <0..1> resets per phase — not monotonic overall, don't use as a global bar.
  6. Hard errors: forrtl: severe (NN): (Fortran runtime; 29 = file not found); HDF5-DIAG: + HDF_ERROR (HDF layer); a following Image | PC | Routine | Line | Source block = Fortran traceback.
  7. Run identity: Performing Unsteady Flow Simulation HEC-RAS 6.6 September 2024 (version string); 2D Unsteady Diffusion Wave Equation Set (equation set); 2D number of Solver Cores: N (actual cores used).
  8. Noise to ignore: sh: 1: wmic: not found (Linux core detection fails; falls back to 2 cores — benign but note the default), Writing Results to DSS, Please review "Computational Log File" output…, *** The file must be closed… (this one is benign boilerplate appended to HDF errors, not a real lock).

4. Middleware implications (concrete rules)

  1. Never gate on exit code alone. Gate on: log contains Finished… AND volume error % below threshold AND Results/Unsteady group exists in the output HDF. All three. (A4/A5 exit 0 with no results; A1b exits 0 with garbage.)
  2. Volume-error gates: warn > 1%, fail > 5%. Calibrate against CHAMP production models once available; these bounds come from one demo.
  3. Pre-run Courant validation is mandatory. The engine will happily run a 12-hour dt on 50-ft cells, exit 0, and write garbage. The middleware must check dt against nominal cell size before launch — this is a deterministic QC gate, not a triage judgment.
  4. Timeout heuristic: wall ≈ linear in step count (~6s per 1440 steps here → ~4 ms/step + ~1 s fixed). Estimate timeout = 10 × (sim_hours/dt_hours) × sec_per_step measured from a pilot run; the ±15% run variance means anything tighter than 5× risks false kills. Memory is flat (~110 MB here) — no memory-based timeout needed at this scale; re-measure per model size.
  5. Stage validation before launch: assert every file the .prj/plan needs exists (.b01, .x01, HDFs). The forrtl (29) is catchable before spending a run.
  6. Text-vs-HDF precedence: the .b01 text's Job Control (Computation Interval) is LIVE and beats the HDF's Computation Time Step Base (dead). If the middleware writes text inputs, it must set the interval in the text. If it writes HDFs, it must ALSO keep the text in sync — or stop shipping text the engine will read. (Untested: .p01 text vs .b01 text precedence — both carry the interval.)
  7. The plan HDF is the artifact of record. RasUnsteady reads Geometry from the plan HDF, not from Muncie.g01.hdf. Fingerprint and archive the plan HDF for provenance; the .g##.hdf is only preprocessor input.
  8. Retry hygiene after kill/timeout: delete .bco01, .ic.o01, systemInfoEncoded.txt and re-stage the plan HDF (strip Results) before retry. The HDF itself survives SIGKILL readable — no repair needed, just cleanup.
  9. Set solver cores explicitly. Linux core autodetect fails (wmic: not found) → silent default of 2. If the worker has more, pass it; don't rely on detection.
  10. Roughness changes need input-level validation. Editing Cells Center Manning's n is silently ignored (bit-identical outputs, exit 0) — the engine gives no signal. The middleware must diff roughness inputs pre-run and confirm effect post-run (e.g., compare WSE summaries), not trust the run to complain.
  11. Dry runs are safe — no orchestrator special-casing for zero-flow events.
  12. Keep the .bco01. It's a small human-readable run record (project, plan, sim window, timestamp) — cheap provenance, archive it per run.

5. Open questions (need 7.0.1 Windows engine or RAS Mapper)

  1. Where does RasUnsteady actually read 2D Manning's n from? — investigated 2026-10-12, see §6. Short version: NONE of the candidate inputs moved the needle on this Linux build in the Muncie regime; a roughness liveness probe gate is now the recommended middleware rule instead of assuming a live knob.
  2. .p01 text vs .b01 text precedence for Computation Interval (both carry it).
  3. Does RasSteady share the exit-0-on-failure behavior? (Not tested.)
  4. 7.0.1 engine differences in any of the above (only 6.6 tested).
  5. Whether the Windows engine's wmic core detection changes default-core behavior (and whether explicit core setting is honored the same way).
  6. What ITER2D sustained-nonzero patterns look like for a genuinely struggling (but converging) model — needed to set a "solver struggling" warning threshold.
  7. Whether 2D roughness becomes a live knob in a friction-dominated regime (steeper/channelized 2D model) — the Muncie regime is level-pool-like (mean|v| ≈ 0.02), intrinsically n-insensitive. Needs a different test model.

6. Roughness-input investigation (follow-up campaign, 2026-10-12)

Motivation: open question §5.1 — the A2a/A2b finding that editing per-cell Manning's n is silently ignored. Goal: find the LIVE 2D roughness input for the middleware's calibration use case. Result: no live 2D roughness input found on this Linux build in the Muncie regime. Campaign scripts: /tmp/ras-campaign.py, /tmp/ras-campaign2.py, /tmp/ras-campaign3.py, /tmp/ras-campaign4.py (transient); experiment dirs /tmp/ras-exp-C*.

6.1 Input-path mapping (established first)

6.2 Perturbation results (all vs unsteady-only baselines)

| ID | Perturbation | max|dWSE| vs baseline | Verdict | |---|---|---|---| | C2 | Perimeter 1 attr Manning's n 0.06 → 0.35 | 0.0000 ft | dead | | C3 | same, through full pipeline (geompre+unsteady) | 0.0000 ft | dead; attr survives geompre | | C4 | per-cell n → 0.5, unsteady only (clean A2a replication) | 0.0000 ft | dead | | C6 | Composite LC 0 → 1 alone | 0.0000 ft | dead | | C5/C10 | per-cell n → 0.5 AND Composite LC = 1 | 0.0070 / 0.0007 ft | not reproduced — noise (see §6.3) | | C11 | plan-HDF Calibration Table base n → 0.5 (all 16 classes) | 0.0000 ft | dead | | C7 | 1D XS n 0.03 → 0.30 in .x01 text | 0.0000 ft | dead (1D not simulated) | | C8/C9 | 50× US inflow (1415 cfs peak, 1287 wet cells, 14.65 ft max depth): per-cell n pristine vs 0.5 | 0.0183 ft | dead within noise (see §6.3) |

6.3 New finding: run-to-run result nondeterminism

The original campaign measured ±15% WALL-TIME variance only. Re-running bit-identical inputs and diffing WSE fields shows the RESULTS also vary: ~0.001–0.007 ft at baseline regime (C5 vs C10), ~0.004 ft at 50× flow (C8 vs C12 replicate). Likely source: threaded solver (PARDISO/MKL, 2 cores) reduction ordering. Middleware consequence: regression tests on engine outputs must use tolerances (≈ 0.01 ft for this model scale), never bit-equality.

6.4 Middleware rules (added)

  1. Roughness liveness probe (deterministic gate). Before ANY calibration campaign, perturb the candidate roughness input ±, run, and verify the objective moves beyond the nondeterminism envelope (~0.01 ft here). If it doesn't move, the knob is dead — halt the campaign, do not "calibrate". Never assume a roughness input is live on the basis of where it is stored.
  2. Regression-test with tolerances, not bit-equality. Engine WSE outputs vary run-to-run at the mm level (threaded solver). Gate on |Δ| < tolerance.
  3. Know the model's regime before trusting sensitivity. A level-pool-like 2D regime (low velocity, normal-depth outlet) is intrinsically friction-insensitive — a dead liveness probe may indict the regime, not the input. Re-probe on a friction-dominated model before concluding the Linux build can't steer roughness at all (§5.7).

Appendix: experiment index

ID Change Dir
BASE, B8a, B8b pristine (×3) /tmp/ras-exp-BASE|B8a|B8b
P1 .b01 interval → 10MIN /tmp/ras-exp-P1
A1 HDF Computation Time Step Base → 12HOUR /tmp/ras-exp-A1
A1b .b01 interval → 12HOUR (Courant) /tmp/ras-exp-A1b
A2a / A2b plan-HDF n → 0.5 / 0.001 /tmp/ras-exp-A2a|A2b
A3 .b01 deleted /tmp/ras-exp-A3
A4 plan HDF truncated 50% /tmp/ras-exp-A4
A5 plan HDF deleted /tmp/ras-exp-A5
A6 US hydrograph → 0 flow /tmp/ras-exp-A6
A7 SIGKILL at 2 s /tmp/ras-exp-A7
B9 .b01 interval → 10SEC /tmp/ras-exp-B9

Harness: ~/workspace/hec-ras-research/run_exp.sh + sup.py (timing/peak-RSS) + per-experiment modifiers in ~/workspace/hec-ras-research/mods/. Reusable for the next campaign (RasSteady, 7.0.1, production-model calibration).

Liveness probe (rule 13, implemented 2026-10-12): liveness_probe.py --mod mods/<name>.py stages the model fresh, runs baseline ×2 + mod ×1, and compares the 2D Water Surface field. Verdict LIVE if the mod shift exceeds max(3×envelope, 0.01 ft), DEAD otherwise (exit 0/2/1 = live/dead/error), with max|Volume Error| per run. Verified: A2a (dead n knob) → DEAD; POS (US flow ×10) → LIVE (shift 8.09 ft vs 0.0038 ft envelope). Mods: POS.py is the positive control; any calibration campaign must pass this gate first. Lab Python: .venv (h5py/numpy); run_exp.sh prefers it on PATH.