Investigated 2026-10-12 (read-only) from ~/workspace/hec-ras-research/example-projects-7.0/.
Priority was the TEXT files (.prj / .g## / .p## / .u## / .rasmap) — the middleware's
actual interface surface — plus one HDF peek for mesh statistics.
Muncie's own .prj description says it outright:
"The 2D areas are not detailed models (i.e. not a lot of time was spent laying out breaklines and testing cell size, time step, etc..."
These are demonstration models, not best-practice exemplars for mesh settings. Treat them as an anatomy reference (how a well-formed HEC project is structured, linked, and stored) and a parser specification (exact text formats the middleware must read/write) — not as QC calibration targets for cell sizing or breakline density. Glenn's mesh templates come from CHAMP production models; these examples are the reference shelf the middleware validates against, not the standard it validates to.
2D Unsteady Flow Hydraulics/Muncie/ (the classic 2D example)Muncie.prj lists every file by role: Geom File=g01/g02/g04, Flow File=f01,
Unsteady File=u01, Plan File=p01/p03/p04, Current Plan=p04, English Units.
The .prj is a manifest — so the middleware should parse the .prj first and treat it
as the project's file inventory, validating that every referenced file exists.g01 "Muncie Base Geometry - 9 SAs" → p01 "Unsteady Multi 9-SA run"g02 "Muncie Geometry - 2D 50ft Grid" → p03 "Unsteady Run with 2D 50ft Grid"g04 "Muncie Geometry - 50ft User n Value Regi[on]" → p04 "Unsteady Run with 2D 50ft User n Value R" (current)Geom Title= / Plan Title= on generated projects
(not defaults) and record the geometry→plan mapping explicitly in provenance.Program Version= is per-file and stale: g02 says 5.04, p04 says 5.10, u01 says
6.30 — all in one working project. So the middleware must never trust Program Version
as provenance; record the RAS version that generated each artifact in its own catalog
record instead.Muncie.g02, Muncie.g04)Storage Area block with Storage Area Is2D=-1 (not 1;
0 = classic storage area). So the middleware's geometry parser must key on Is2D=-1.Storage Area Point Generation Data=,,50,50 — the last two fields are
dx,dy in project units (feet here). Variants seen: 0,0,, (non-2D SA), ,,, (empty),
0,0,0.1,0.05 (Weise lab flume, meters). So the middleware should parse all four fields
tolerantly and treat empty/zero dx,dy as "no 2D mesh."Storage Area 2D Points= 5391 followed by that many XY pairs (cell centers,
in project coordinates). g02 = g04 = 5,391 cells at 50 ft — the n-region variant
changes roughness, not the mesh. So the middleware can diff two geometries' 2D Points
blocks to prove "same mesh, different parameters," a useful provenance assertion.2D Cell Volume Filter Tolerance=0.01, 2D Cell Minimum Area Fraction=0.01,
2D Face Profile Filter Tolerance=0.01, 2D Face Area Elevation Profile Filter Tolerance=0.01,
2D Face Area Elevation Conveyance Ratio=0.02, 2D Face Area Laminar Depth=0.2.
So the middleware's project writer must emit these (or consciously inherit them) and its
validator should check they exist — a geometry missing them was hand-edited or truncated.Muncie.g02:5091-):
BreakLine Name=Road 1 / BreakLine CellSize Min=0 / BreakLine CellSize Max=0 /
BreakLine Near Repeats=0 / BreakLine Polyline= 21 + 21 XY pairs.
0 = use nominal spacing. (BaldEagle uses empty BreakLine CellSize Min= for the same
meaning.) So the middleware must treat empty and 0 as equivalent "default" and must
preserve breakline names — they are the human-readable handle QC reports reference.LCMann Table=7 + 7 name,n lines (NoData,0.06 … Trees,0.12 … Building,10),
with Storage Area Mannings=0.06 as the fallback/uniform value.
So the middleware's roughness pipeline should mirror this two-level design: a land-cover
lookup table plus an explicit default n, both recorded in provenance.Muncie.g04:5167-): LCMann Region Name=Flat Area /
LCMann Region Table=6 (modified n's, here 0.9× base) / LCMann Region Polygon=41 + 41
vertices. This is the calibration-variant pattern without touching the mesh.
So the middleware should support n-regions as first-class calibration levers and record
region polygon + table per variant — this is cleaner provenance than "we edited the mesh."Muncie.p04)Geom File=g04, Flow File=u01. So the middleware's plan writer must
always set these explicitly; a plan whose Geom File doesn't match the intended geometry
is a classic misconfiguration the validator should catch.Computation Interval=10SEC, UNET D2 Equation= 0, UNET D2 Theta= 1,
UNET D2 Theta Warmup= 1, UNET D2 Z Tol= 0.01, UNET D2 Volume Tol= 0.01,
UNET D2 Max Iterations= 20, UNET D2 TimeSlices= 1, UNET D2 RampUpFraction=0.5,
UNET D2 SolverType=Pardiso (Direct), UNET D2 Cores= 6,
UNET D2 Eddy Viscosity=0, UNET D2 BCVolumeCheck=0.
(Equation= 0 = diffusion wave here; the code→equation-set mapping should be verified
against HEC docs before the middleware asserts on it.)
So the middleware should treat this block as its computation-settings checklist:
every generated plan gets these set deliberately and recorded — no silent defaults.UNET D1D2 MaxIter= 0, D1D2 ZTol=0.01,
D1D2 QTol=0.1 — relevant the moment the middleware builds 1D-2D coupled models.Output Interval=5MIN, Instantaneous Interval=5MIN,
Mapping Interval=5MIN, and HDF write flags mostly 0 with HDF Compression= 1.
So the middleware's plan writer should set output intervals as a conscious storage-vs-
diagnostic tradeoff, not leave HEC defaults.Muncie.u01)Flow Hydrograph= 65 (65 ordinates at
Interval=1HOUR) at RS 15696.24, downstream Friction Slope=0.00064,0.Met BC= / precipitation blocks are all disabled defaults.
So the middleware must support the "2D area fed entirely by 1D coupling" pattern, not
assume every 2D area needs BC lines.Muncie.rasmap)GIS_Data\Muncie_IA_Clip.prj), per-geometry .g##.hdf layers,
land-cover layers, terrain layers. The .rasmap is display state, not model state —
but it records two things the middleware does need:MeshTolerance_MinFaceLength=0.05,
MeshTolerance_EnsureCellPoint=False under ProjectSettings. So the middleware's
mesh QC should read/assert these — they're the project's own definition of an
acceptable mesh.Terrain, TerrainWithChannel);
TerrainWithChannel is Checked="True". The Terrain/ folder holds
Terrain.<name>.tif (source) + .hdf (compiled) + .vrt. So the middleware's
terrain pipeline should mirror this: keep source TIFF + compiled HDF + the
channel-burned variant, and record which variant the geometry was built against.LandCoverUserShapefile → LandCoverUSGSGrid →
LandCoverCombined (each .tif + .hdf). So the middleware should version land-cover
inputs the same way — raw source, authoritative grid, combined product — not a single
mystery raster.Muncie.g02.hdf, via h5py)Geometry/2D Flow Areas/<name> carries mesh statistics as attributes:
Cell Average Size=2543.089, Cell Minimum Size=1629.5957,
Cell Maximum Size=4726.1104, Cell Maximum Index=120, Extents=[...].
sqrt(2543) ≈ 50.4 ft — matches the nominal 50 ft.
So the middleware's mesh QC gate can read these attributes straight from the compiled
HDF and sanity-check them against the nominal cell size (min/max/avg ratios bound mesh
quality without parsing 5,391 points).Geometry/2D Flow Area Break Lines/Attributes is a typed table:
Name|S32, Cell Spacing Near|f4, Cell Spacing Far|f4, Near Repeats|i4, Protection Radius|u1.
So the middleware can validate breakline enforcement from the HDF alone.Muncie.u01.hdf is an empty placeholder (800 bytes, no groups) and no .p##.hdf
result files ship — examples carry inputs + geometry HDFs only.
So the middleware must never assume a .u##.hdf or .p##.hdf exists next to its text
twin; missing HDF = "not yet run," not "corrupt."2D Unsteady Flow Hydraulics/BaldEagleCrkMulti2D/A pattern catalog, not one model: 10 geometries × 10 unsteady files × 12 plans, each
geometry demonstrating one 2D configuration. The .prj lists them all; Current Plan=p05.
| Geometry | Title pattern | 2D areas | Nominal cell | Cells |
|---|---|---|---|---|
| g01 | SA to 2D Flow Area – Detailed | 1 | 100 ft | 87,039 |
| g02 | Single 2D Area – With Infiltration | 1 | 200 ft | 28,449 |
| g03 | Single 2D Area with Bridges and Breaklines | 1 | 250 ft | 24,718 |
| g06 | Multi 2D Areas | 3 | 200 ft | 974 / 1,191 / 1,955 |
| g08 | 1D-2D Dam Break, Refined Grid | 1 | 250 ft | 14,206 |
| g09 | Single 2D Area – Internal Dam Structure | 1 | 250 ft | 18,066 |
| g10 | U.S. 2D – D.S. 1D, No Dam | 2 | 200 ft | 2,005 / 5,330 |
| g11 | 2D to 2D Connection | 2 | 500 ft | 3,359 / 1,066 |
| g12 | SA to 2D Connection | 2 | 500 ft | 3,439 / 1,066 |
| g13 | SA to 2D Flow Area | 2 | 250/500 ft | 14,364 / 1,066 |
BaldEagleDamBrk.g11:3028-): stored as Connection= blocks with
Connection Up SA= / Connection Dn SA= naming the two 2D areas, Connection Line= N
polyline, weir coefficients (Conn Weir Coef=3.82, Conn Weir WD=25), and gate
definitions. So the middleware's geometry builder must treat inter-2D-area connections
as first-class objects with named endpoints — a mesh library tiling units will need
exactly this when study areas span tiles.g11:3060-):
BC Line Name=DSNormalDepth / BC Line Storage Area=BaldEagleCr /
BC Line Start/Middle/End Position= / BC Line Arc= 3.
And the BC data lives in the .u file keyed by area+line
(u03:4: Boundary Location= … ,BaldEagleCr , ,DSNormalDepth + Friction Slope=0.0003,0).
So the middleware must keep the geometry-side line definition and the unsteady-side BC
data in sync by (area, line-name) key — a validator should check every BC line named in
the .u file exists in the .g file and vice versa.BreakLine CellSize Min= means "use nominal" (Muncie used 0 for the same).
So the middleware should normalize empty≡0 on read and use semantic names
(road/rail/levee/feature names, not "Breakline 7") when generating.Storage Area Mannings=0.04 + one LCMann Table in g02: same two-level roughness
design as Muncie. Consistent — so the middleware can standardize on it..b06 bridge, .bco06, .IC.O06 initial
conditions, breach blocks in plans) — noted, not pursued; the 2D middleware doesn't
need them until it builds dam-break templates.Chippewa_2D/, Weise_2D/Chippewa_2D.g01, title "100ft_Mod" — but actual
Point Generation Data=,,600,600, 354 cells): titles lie; the text doesn't.
So the middleware must derive nominal cell size from Point Generation Data, never
from Geom Title.Chippewa_2D.p02:88-114): the plan file has a global 2D
defaults section followed by per-2D-area sections delimited by
UNET D2 Name=<area> — and they disagree: global UNET D2 Equation= 1,
per-area UNET D2 Equation= 0; global RampUpFraction=0.1, per-area 0.5.
So the middleware's plan parser must be section-aware (global defaults, then
per-area overrides keyed by UNET D2 Name) — a naive first-match/last-match key=value
reader gets the wrong answer. Same for UNET D2 Cores, repeated per area.UNET D2 Turbulence Formulation=None, Eddy Viscosity=0.3,
Transverse Eddy Viscosity=0.1, Smagorinsky Mixing=0.05.Computation Interval=0.2SEC)
— confirms the text format at metric/lab scale, not field-relevant otherwise.Project validator (new capability — high value, low cost):
1. Parse the .prj as the manifest; assert every referenced .g/.f/.u/.p file exists.
2. Assert every plan's Geom File= / Flow File= (Unsteady File=) points at the intended
files — misconfiguration, not modeling, is the common failure.
3. Cross-check 2D BC lines: every (area, line) named in the .u file must exist as a
BC Line in the .g file and vice versa.
4. Require meaningful Geom Title= / Plan Title= (reject defaults/empties on write).
5. Never trust Program Version= for provenance — record generating RAS version per artifact
in the catalog.
Plan parser/writer:
6. Section-aware parsing: global 2D defaults, then per-area overrides after each
UNET D2 Name= — this is the single most bug-prone format detail found.
7. Emit a deliberate computation-settings block on every generated plan (interval, equation
set, theta, tolerances, solver, cores, eddy viscosity, ramp-up) and record it; derive
Computation Interval from nominal cell size by a documented rule.
8. Set output intervals (Output/Instantaneous/Mapping) and HDF write flags as a
conscious storage-vs-diagnostic choice.
Geometry parser/writer:
9. Key 2D areas on Storage Area Is2D=-1; parse Point Generation Data tolerantly
(,,50,50 / 0,0,, / ,,,); derive nominal size from the text, never the title.
10. Normalize breakline CellSize Min/Max: empty ≡ 0 ≡ "use nominal"; preserve breakline
names; use semantic names on write.
11. Standardize the two-level roughness design: LCMann Table (land-cover lookup) +
Storage Area Mannings= default; support LCMann Region polygons as calibration
levers with per-variant provenance (same mesh, different tables — diffable).
12. Emit the 2D cell property-table tolerances on write; validate their presence on read.
Mesh QC gates:
13. Read compiled-HDF mesh statistics attributes (Cell Average/Minimum/Maximum Size,
Cell Maximum Index, Extents) and bound them against nominal cell size —
cheap mesh-quality check without parsing points.
14. Read .rasmap ProjectSettings mesh tolerances (MeshTolerance_MinFaceLength,
MeshTolerance_EnsureCellPoint) and enforce the project's own definitions.
15. Reference ranges observed (field scale, English units): nominal cells 100–500 ft;
cell counts from ~1k (small areas) to ~87k (100 ft detailed); computation intervals
5 s–1 min scaling roughly with cell size. Calibrate real QC bounds from CHAMP
production models, not these demos — but these are sane order-of-magnitude anchors.
Terrain/land-cover pipeline:
16. Mirror HEC's folder pattern: Terrain/<name>.tif source + .hdf compiled + .vrt;
keep the channel-burned variant distinct and record which variant the geometry used
(the .rasmap-checked terrain).
17. Version land cover as source → authoritative grid → combined product, with the
LCMann table provenance pointing at the combined product.
Mesh-library specific:
18. Geometry variants as named, titled alternatives (Muncie's g01→g02→g04 progression) is
the right model for library tiers: same HUC-10, multiple mesh/roughness variants,
titles naming the pattern.
19. Inter-2D-area Connection= blocks (named upstream/downstream areas + weir/gate
parameters) are the mechanism for study areas spanning tiles — the library's
subset/assembly logic will need to author these.
20. The .rasmap is display state — the middleware should read mesh tolerances and
active-terrain/land-cover selections from it but never treat layer visibility or
symbology as model content.
2D Unsteady Flow Hydraulics/Muncie/Muncie.prj — manifest, disclaimer2D Unsteady Flow Hydraulics/Muncie/Muncie.g02 (2D area @2383, breaklines @5091, LCMann @5117, tolerances @5084–5089), Muncie.g04 (n-regions @5167)2D Unsteady Flow Hydraulics/Muncie/Muncie.p04 — 2D computation settings; Muncie.p01/p03 — plan↔geometry mapping2D Unsteady Flow Hydraulics/Muncie/Muncie.u01 — 1D-only BCs; Muncie.u01.hdf — empty placeholder2D Unsteady Flow Hydraulics/Muncie/Muncie.rasmap — mesh tolerances, active terrain, land-cover layers2D Unsteady Flow Hydraulics/Muncie/Muncie.g02.hdf — Geometry/2D Flow Areas attributes, 2D Flow Area Break Lines/Attributes2D Unsteady Flow Hydraulics/BaldEagleCrkMulti2D/BaldEagleDamBrk.g11 — 2D-2D connection @3028, BC lines @30602D Unsteady Flow Hydraulics/BaldEagleCrkMulti2D/BaldEagleDamBrk.u03 — 2D BC data keyed by (area, line)2D Unsteady Flow Hydraulics/BaldEagleCrkMulti2D/BaldEagleDamBrk.p13 — multi-2D plan settings2D Sediment Transport/Chippewa_2D/Chippewa_2D.p02 — global vs per-area 2D sections @88–1142D Sediment Transport/Chippewa_2D/Chippewa_2D.g01, 2D Sediment Transport/Weise_2D/Weise.g08 — cell-size formats