geometry

Geometry — read HEC-RAS geometry HDF5 files (.g*.hdf).

Provides structured access to 2-D flow-area mesh data: cell centres, face connectivity, hydraulic property tables, etc.

Also provides access to storage areas and boundary condition lines.

class rivia.hdf.geometry.BoundaryConditionCollection(hdf)[source]

Bases: Mapping[str, BoundaryConditionLine]

Access all boundary condition lines in an HDF geometry file.

Implements the collections.abc.Mapping protocol: supports len(), iteration, in, [], .keys(), .values(), .items(), and .get().

Parameters:

hdf (File) – Open h5py.File handle.

property names: list[str]

Names of all boundary condition lines in the file.

property summary: DataFrame

One row per BC line with basic attributes.

Columns: name, connected_area, type, n_points.

class rivia.hdf.geometry.BoundaryConditionLine(name, connected_area, bc_type, polyline)[source]

Bases: object

A single HEC-RAS boundary condition line.

Variables:
  • name – Name of the BC line (e.g. "DSNormalDepth1").

  • connected_area – Name of the 2-D flow area or storage area this line belongs to (the SA-2D field in the HDF attributes table).

  • bc_type – Type string (e.g. "External" or "Internal").

  • polyline – x, y coordinates of the BC line. Shape (n_pts, 2).

Parameters:
bc_type: str
connected_area: str
name: str
polyline: ndarray
class rivia.hdf.geometry.Bridge(mode, upstream_type, downstream_type, centerline, location=('', '', ''), upstream_node=('', '', ''), downstream_node=('', '', ''), weir=None, gate_groups=<factory>)[source]

Bases: Structure

Bridge structure embedded in a 1-D HEC-RAS reach.

Both sides are always 'XS'.

Variables:
  • location(river, reach, rs) of this bridge in the 1-D geometry (HDF River / Reach / RS fields).

  • upstream_node(river, reach, rs) of the adjacent upstream cross section (HDF US River / US Reach / US RS).

  • downstream_node(river, reach, rs) of the adjacent downstream cross section (HDF DS River / DS Reach / DS RS).

  • weir – Weir overflow parameters; None when mode is empty (pure bridge, no overflow weir modelled).

  • gate_groups – Gate groups attached to this structure (empty list when none).

Parameters:
downstream_node: tuple[str, str, str] = ('', '', '')
gate_groups: list[GateGroup]
location: tuple[str, str, str] = ('', '', '')
upstream_node: tuple[str, str, str] = ('', '', '')
weir: Weir | None = None
class rivia.hdf.geometry.CrossSection(river='', reach='', rs='', name='', description='', left_bank=nan, right_bank=nan, len_left=nan, len_channel=nan, len_right=nan, contraction=nan, expansion=nan, friction_mode='', hp_count=0, hp_start_elev=nan, hp_vert_incr=nan, station_elevation=<factory>, mannings_n=<factory>, ineffective_areas=<factory>, cut_line=<factory>, orthogonal_vector=<factory>, centerline_polyline=<factory>)[source]

Bases: object

One HEC-RAS 1-D cross section from Geometry/Cross Sections/Attributes.

Variables:
  • river – River name (HDF River field).

  • reach – Reach name (HDF Reach field).

  • rs – River station string (HDF RS field).

  • name – Optional user label (HDF Name field).

  • description – Optional extended description (HDF Description field).

  • left_bank – Left bank station separating LOB from the channel (HDF Left Bank).

  • right_bank – Right bank station separating the channel from ROB (HDF Right Bank).

  • len_left – Reach length for the left overbank (HDF Len Left).

  • len_channel – Reach length for the main channel (HDF Len Channel).

  • len_right – Reach length for the right overbank (HDF Len Right).

  • contraction – Contraction energy loss coefficient (HDF Contr).

  • expansion – Expansion energy loss coefficient (HDF Expan).

  • friction_mode – Friction mode string, e.g. 'Basic Mann n' (HDF Friction Mode).

  • hp_count – Number of rows in the precomputed hydraulic-property table (HDF HP Count).

  • hp_start_elev – Starting elevation for the hydraulic-property table (HDF HP Start Elev).

  • hp_vert_incr – Vertical elevation increment between hydraulic-property table rows (HDF HP Vert Incr).

  • station_elevation – Cross-section survey points, shape (n, 2). Columns: [station, elevation]. Source: Geometry/Cross Sections/Station Elevation Values.

  • mannings_n – Manning’s n breakpoints, shape (n, 2). Columns: [station, n_value]. Source: Geometry/Cross Sections/Manning's n Values.

  • ineffective_areas – Ineffective-flow block regions, shape (n, 3). Columns: [left_sta, right_sta, elevation]. Source: Geometry/Cross Sections/Ineffective Blocks. Empty (0, 3) when no ineffective areas are defined.

  • cut_line – Plan-view GIS cut-line coordinates, shape (n, 2). Columns: [x, y]. This is the polyline drawn across the floodplain from the left edge to the right edge of the cross section. Use station_coordinates() to project survey stations onto this line and obtain 3-D point coordinates. Source: Geometry/Cross Sections/Polyline Points.

  • orthogonal_vector – Unit vector perpendicular to the cut line, shape (2,): [cos θ, sin θ] where θ is measured CCW from the x-axis. Source: Geometry/Cross Sections/Orthogonal Vectors.

  • centerline_polyline – Plan-view river centreline polyline for this reach, shape (n, 2). Populated automatically by CrossSectionCollection from Geometry/River Centerlines by matching on river and reach. Empty (0, 2) when no matching centreline is found. Used by centerline_coordinates.

Parameters:
property centerline_coordinates: ndarray | None

Intersection of the cut line with the river centreline, shape (2,).

Computes the point where cut_line crosses centerline_polyline. Returns None when centerline_polyline is empty (no centreline matched this reach), or when the two polylines do not intersect.

Returns:

[x, y] of the intersection, or None.

Return type:

ndarray, shape (2,) or None

centerline_polyline: ndarray
contraction: float = nan
cut_line: ndarray
description: str = ''
expansion: float = nan
friction_mode: str = ''
hp_count: int = 0
hp_start_elev: float = nan
hp_vert_incr: float = nan
ineffective_areas: ndarray
left_bank: float = nan
property left_bank_coordinates: ndarray

Spatial coordinates of the left bank station, shape (3,).

Interpolates [x, y, elevation] at left_bank from the output of station_coordinates().

Returns:

[x, y, elevation]. Returns array([nan, nan, nan]) when station_coordinates() returns no points or when left_bank is NaN.

Return type:

ndarray, shape (3,)

len_channel: float = nan
len_left: float = nan
len_right: float = nan
property location: tuple[str, str, str]

(river, reach, rs) identity tuple for this cross section.

mannings_n: ndarray
name: str = ''
orthogonal_vector: ndarray
reach: str = ''
right_bank: float = nan
property right_bank_coordinates: ndarray

Spatial coordinates of the right bank station, shape (3,).

Interpolates [x, y, elevation] at right_bank from the output of station_coordinates().

Returns:

[x, y, elevation]. Returns array([nan, nan, nan]) when station_coordinates() returns no points or when right_bank is NaN.

Return type:

ndarray, shape (3,)

river: str = ''
rs: str = ''
station_coordinates()[source]

Project each survey station onto the GIS cut line to get 3-D coordinates.

Interpolates (x, y) for every row of station_elevation by walking the cut_line polyline. The leftmost survey station maps to the first cut-line vertex; the rightmost maps to the last. Elevation values are taken directly from station_elevation.

Returns:

Columns: [x, y, elevation] for each station/elevation point. Returns an empty (0, 3) array when cut_line or station_elevation contains no points.

Return type:

ndarray, shape (n, 3)

Notes

The mapping assumes the cut line runs from the left bank (station = min) to the right bank (station = max) in the same direction as the survey. This matches the HEC-RAS convention stored in the HDF file.

station_elevation: ndarray
class rivia.hdf.geometry.CrossSectionCollection(hdf)[source]

Bases: object

Access all 1-D cross sections in Geometry/Cross Sections.

Keyed by "River Reach RS" — the same convention used by StructureCollection and the DSS Hydrograph Output group names.

Parameters:

hdf (File) – Open h5py.File handle.

property names: list[str]

Keys of all cross sections in the collection.

class rivia.hdf.geometry.FlowArea(group, name, n_cells)[source]

Bases: object

Geometry data for one named 2-D flow area.

All properties are loaded eagerly on first access and cached; they are small static arrays compared with the time-series results.

Parameters:
  • group (Group) – The h5py.Group at Geometry/2D Flow Areas/<name>.

  • name (str) – Human-readable name of the flow area.

  • n_cells (int) – Number of real computational cells (ghost cells excluded).

property boundary_cell_mask: ndarray

Boolean mask of cells that touch the flow area perimeter.

Shape (n_cells,). True for any real cell that has at least one boundary face (see boundary_face_mask).

Computed once and cached.

property boundary_face_mask: ndarray

Boolean mask of faces on the 2D flow area perimeter.

Shape (n_faces,). True for faces where one side has no neighbouring cell (face_cell_indexes value is -1).

Computed once and cached.

property cell_aspect_ratio: ndarray

Aspect ratio of each cell. Shape (n_cells,).

Ratio of the longest face to the shortest face (by arc length from face_lengths). Value of 1.0 for a regular cell; large values indicate elongated cells.

Computed once and cached.

property cell_bbox: ndarray

Axis-aligned bounding box per cell. Shape (n_cells, 4).

Columns: [xmin, ymin, xmax, ymax]. Derived from the polygon corner facepoints in cell_facepoint_indexes. Interior perimeter points on curved faces are not included; the error is negligible for the near-convex cells HEC-RAS requires.

Computed once and cached.

property cell_centers: ndarray

x, y coordinates of real cell centres. Shape (n_cells, 2).

property cell_compactness: ndarray

Isoperimetric compactness of each cell. Shape (n_cells,).

compactness = × area / perimeter². A circle scores 1.0; elongated or irregular cells score lower. Uses cell_surface_area for area and face_lengths for the perimeter.

Computed once and cached.

property cell_face_info: tuple[ndarray, ndarray]

Cell-to-face connectivity index and values.

Returns:

  • info (ndarray, shape (n_cells, 2)) – Columns: [start_index, count] into values.

  • values (ndarray, shape (total, 2)) – Columns: [face_index, orientation].

    The orientation flag identifies which role this cell plays for that face, using the RasMapper Face object convention (Face.cs): every face stores cellA and cellB (columns 0 and 1 of face_cell_indexes) and fpA and fpB (columns 0 and 1 of face_facepoint_indexes). RasMapper guarantees the following CCW traversal invariant:

    • Walking CCW around cellA, the face edge runs fpA fpB (fpA is the entry facepoint, fpB is the exit facepoint).

    • Walking CCW around cellB, the edge runs fpB fpA (fpB is the entry facepoint, fpA is the exit facepoint).

    The orientation flag encodes which role this cell plays:

    • +1 — this cell is cellA for that face. The stored face normal points outward (away from this cell toward cellB). The entry facepoint for CCW traversal is fpA (column 0 of face_facepoint_indexes).

    • -1 — this cell is cellB for that face. The stored face normal points inward (toward this cell from cellA). The entry facepoint for CCW traversal is fpB (column 1 of face_facepoint_indexes).

    To pick the CCW-entry facepoint for a face given its orientation flag ori:

    fp = face_facepoint_indexes[fi, 0] if ori > 0                      else face_facepoint_indexes[fi, 1]
    

    This is equivalent to Face.GetFPPrev(cellIdx) in RasMapperLib/RasMapperLib.Mesh/Face.cs.

Example

Given:

info = np.array([[0, 3], [3, 4]])
values = np.array([
    [10, +1], [11, -1], [12, +1],
    [20, +1], [21, +1], [22, -1], [23, +1],
])

Cell 0 uses values[0:3] (faces 10, 11, 12), and cell 1 uses values[3:7] (faces 20, 21, 22, 23).

property cell_facepoint_indexes: ndarray

Corner facepoint indices per cell in polygon order.

Shape (n_cells, 8). Each row contains up to 8 facepoint indices (into facepoint_coordinates) in polygon-traversal order; unused slots are padded with -1.

Example

A triangular cell and a quadrilateral cell:

cell_facepoint_indexes = np.array([
    [ 5, 12, 18, -1, -1, -1, -1, -1],  # triangle
    [ 0,  3,  7, 11, -1, -1, -1, -1],  # quad
])
property cell_mannings_n: ndarray

Manning’s n at each cell centre. Shape (n_cells,).

property cell_min_elevation: ndarray

Minimum bed elevation per cell. Shape (n_cells,). Real cells only (ghost rows excluded). See _cell_min_elevation for the full array.

property cell_neighbors: list[ndarray]

Adjacent real cell indices for each cell.

Returns a list of length n_cells. Element c is an int64 array of real cell indices (< n_cells) that share a face with cell c. Boundary faces (where the neighbour index is -1) contribute no entry. Order follows the face order in cell_face_info.

Computed once and cached.

property cell_polygons: list[ndarray]

Polygon vertices for every cell in counter-clockwise order.

Returns a list of length n_cells. Each element is an ndarray of shape (n_vertices, 2) containing the (x, y) coordinates of the cell polygon in counter-clockwise winding (GeoJSON / OGC / Shapely exterior-ring convention).

For cells that border curved faces the interior perimeter points from face_perimeter are inserted between the corner facepoints, giving an accurate boundary representation. Cells whose face adjacency graph cannot be traversed as a closed cycle emit an empty (0, 2) array.

Computed once and cached.

Examples

Create Shapely geometries:

from shapely.geometry import Polygon
polys = [Polygon(pts) for pts in fa.cell_polygons]

Create a GeoDataFrame (requires geopandas):

import geopandas as gpd
from shapely.geometry import Polygon
gdf = gpd.GeoDataFrame(
    geometry=[Polygon(pts) for pts in fa.cell_polygons],
    crs="EPSG:…",
)
property cell_surface_area: ndarray

Plan-view surface area per cell. Shape (n_cells,).

property cell_volume_elevation: tuple[ndarray, ndarray]

Volume-elevation table index and values.

Returns:

  • info (ndarray, shape (n_cells, 2)) – Columns: [start_index, count] into values.

  • values (ndarray, shape (total, 2)) – Columns: [elevation, volume].

cells_containing_points(xy)[source]

Return the cell index containing each query point.

Parameters:

xy (ndarray, shape (m, 2) or (2,)) – Query (x, y) coordinates.

Returns:

0-based cell index for each point, or -1 when outside all cells (or the cell polygon is malformed).

Return type:

ndarray, shape (m,), dtype int64

Notes

Uses cell_bbox for a fast bounding-box pre-filter then cell_polygons for exact ray-casting containment. No spatial index is built; for very large query sets consider building an external RTree over cell_bbox.

check_cells(*, check_boundary=True, tol=1e-10)[source]

Check all mesh cells against HEC-RAS geometric validity rules.

Calls rivia.geo.mesh_validation.check_mesh_cells() with the HDF arrays for this flow area.

Parameters:
  • check_boundary (bool) – When True (default) each cell centre is also tested against the 2D flow area perimeter polygon (rule 5).

  • tol (float) – Absolute tolerance for near-collinear edge detection.

Returns:

Full validation report. Pass to rivia.geo.mesh_validation.print_mesh_report() for a human-readable summary.

Return type:

dict

property face_area_elevation: tuple[ndarray, ndarray]

Hydraulic property table for each face.

Returns:

  • info (ndarray, shape (n_faces, 2)) – Columns: [start_index, count] into values.

  • values (ndarray, shape (total, 4)) – Columns: [elevation, flow_area, wetted_perimeter, mannings_n].

Example

Given:

info = np.array([[0, 2], [2, 3]])
values = np.array([
    [100.0, 0.0, 10.0, 0.030],
    [101.0, 5.0, 11.0, 0.030],
    [100.0, 0.0, 12.0, 0.035],
    [101.0, 6.0, 13.0, 0.035],
    [102.0, 9.0, 14.0, 0.035],
])

Face 0 uses values[0:2] and face 1 uses values[2:5]. For face 0 specifically: [100.0, 0.0, 10.0, 0.030] means at elevation 100.0 the flow area is 0.0 (dry threshold), wetted perimeter is 10.0, and Manning’s n is 0.030; [101.0, 5.0, 11.0, 0.030] is the next stage row with larger flow area/perimeter at elevation 101.0.

property face_cell_indexes: ndarray

Left and right cell index for each face.

Shape (n_faces, 2). A value of -1 indicates a boundary face with no neighbour on that side.

Example

Given:

face_cell_indexes = np.array([
    [0, 1],
    [1, 2],
    [2, -1],
    [-1, 0],
])

Face 0 is interior between cells 0 (left) and 1 (right). Face 2 is a boundary face for cell 2 on the left side, and face 3 is a boundary face for cell 0 on the right side.

property face_centroids: ndarray

Centroid coordinate of each face. Shape (n_faces, 2).

For straight faces (no interior perimeter points) this equals the midpoint of the chord between the two endpoint facepoints. For curved faces this is the arc midpoint — the point on the face polyline at exactly half the total arc length — which guarantees the result lies on the face itself. An arc-length-weighted average of segment midpoints is not used because it can float off the polyline for non-convex shapes (V-notches, loops).

Computed once and cached; subsequent accesses return the same array.

face_elevation_area(face_index)[source]

Elevation and flow-area arrays for a single face.

Parameters:

face_index (int) – Zero-based face index.

Return type:

tuple[ndarray, ndarray]

Returns:

  • elevation (ndarray, shape (n_rows,))

  • area (ndarray, shape (n_rows,))

property face_facepoint_indexes: ndarray

Start and end face-point indices for each face.

Shape (n_faces, 2).

Example

Given:

face_facepoint_indexes = np.array([
    [12, 18],
    [18, 24],
    [24, 12],
])

Face 0 connects facepoints 12 and 18; face 1 connects 18 and 24; face 2 connects 24 and 12.

property face_invert_coordinates: ndarray

(x, y) coordinates of the invert point on each face.

Interpolates along each face polyline at the station distance stored in face_invert_station to produce a projected (x, y) position. Handles both straight faces (two endpoints) and curved faces (with interior perimeter points) correctly.

Shape (n_faces, 2).

property face_invert_station: ndarray

Station of the invert centroid of each face.

HEC-RAS stores the station distance (from one end of the face) to the centroid of the bottom 5% of the face cross-sectional area — the invert region used internally for flow calculations.

Shape (n_faces,), dtype float32.

property face_lengths: ndarray

Arc length of each face polyline. Shape (n_faces,).

Straight faces: Euclidean chord length (equals column 2 of face_normals). Curved faces: sum of segment lengths along the full polyline from face_perimeter.

Computed once and cached.

property face_min_elevation: ndarray

Minimum bed elevation at each face centroid. Shape (n_faces,).

property face_normal_intercept: ndarray

(x, y) coordinate on each face that lies on the cell-centre connecting line.

For each interior face (both neighbours present), this is the point where the straight line through the two adjacent cell centres crosses the face polyline. HEC-RAS uses this intersection implicitly when computing face-normal hydraulic gradients and finite-difference slopes.

For boundary faces (one neighbour absent), the face centroid is returned as a fallback.

Shape (n_faces, 2). Computed once and cached.

Notes

Parametric 2D line–segment intersection: given the infinite line P = cell_L + t * (cell_R - cell_L) and face segment Q = A + s * (B - A) the system is solved for s (segment parameter, must satisfy 0 s 1) and the hit point is A + s * (B - A). For curved faces all segments are tested and the first hit is used.

property face_normals: ndarray

Face unit normal vectors and plan-view lengths.

Shape (n_faces, 3). Columns: [nx, ny, length]. The normal points from the left cell to the right cell as defined by face_cell_indexes.

Example

Given:

face_normals = np.array([
    [1.0, 0.0, 12.5],
    [0.0, -1.0, 8.0],
])

Face 0 has a unit normal pointing in +nx with length 12.5. Face 1 has a unit normal pointing in -ny with length 8.0.

property face_perimeter: tuple[ndarray, ndarray]

Interior perimeter points along curved faces.

Most faces are straight lines between their two endpoint facepoints. For curved faces, one or more intermediate (x, y) coordinate points are stored here. These points are not indexed facepoints; they do not appear in facepoint_coordinates.

Returns:

  • info (ndarray, shape (n_faces, 2)) – [start_index, count] into values. count == 0 for straight faces.

  • values (ndarray, shape (total_interior_pts, 2)) – (x, y) coordinates of interior perimeter points in order along the face polyline.

property face_polylines: list[ndarray]

Full vertex sequence for each face.

Returns a list of length n_faces. Each element is an ndarray of shape (n_pts, 2) in canonical HDF order (facepoint 0 → interior points → facepoint 1). Straight faces yield 2-point arrays; curved faces have 3 or more points.

Computed once and cached.

property facepoint_coordinates: ndarray

x, y coordinates of all face endpoints. Shape (n_facepoints, 2).

property facepoint_face_orientation: tuple[ndarray, ndarray]

Angle-sorted facepoint→face mapping with orientation flags.

Returns (fp_face_info, fp_face_values) where:

  • fp_face_info: shape (n_facepoints, 2), dtype int32. Each row is [start, count] — a slice into fp_face_values for that facepoint.

  • fp_face_values: shape (total_entries, 2), dtype int32. Each row is [face_idx, orientation] where orientation = 0 means this facepoint is fpA (first endpoint) of that face and orientation = 1 means it is fpB (second endpoint).

Entries for each facepoint are sorted in counter-clockwise (ascending bearing) angular order around the facepoint coordinate. Bearing is measured from the positive x-axis using atan2(dy, dx), mapped to [0, 2π) in RasMapper (SegmentM.Bearing()) and [-π, π) in the Python re-implementation (np.arctan2); both produce the same relative ordering. This ordering is required for correct arc traversal in the RASMapper vertex-velocity algorithm (Step 3, MeshFV2D.cs).

Uses facepoint_face_orientation_info and facepoint_face_orientation_values when present (production HDF files always include them). Falls back to building the CSR arrays from face_facepoint_indexes for older or minimal test fixtures. The angle sort is always applied.

Computed once and cached.

Examples

Terminology used in this example:

  • fp0 … fp4 — facepoint indices (mesh vertices, integer row numbers in facepoint_coordinates).

  • fpA / fpB — the two endpoint roles of a face. Every face has exactly two endpoint facepoints stored as [fpA_index, fpB_index] in face_facepoint_indexes. fpA is the first column (index 0), fpB is the second column (index 1).

Five-facepoint mesh with fp0 at the centre and four faces created in arbitrary order:

          fp2 (0,1)
           |
  face 0   |   face 3
           |
 fp3 -----fp0----- fp1
(-1,0)     |       (1,0)
  face 2   |   face 1
           |
          fp4 (0,-1)

 # face_facepoint_indexes — each face stores [fpA_index, fpB_index]
 face 0: fpA=fp0, fpB=fp2  (North)
 face 1: fpA=fp0, fpB=fp4  (South)
 face 2: fpA=fp0, fpB=fp3  (West)
 face 3: fpA=fp0, fpB=fp1  (East)

Bearings from fp0 to the far endpoint of each adjacent face:

face 0 → atan2(1, 0) = +π/2 (North) face 1 → atan2(-1, 0) = -π/2 (South) face 2 → atan2(0, -1) = ±π (West) face 3 → atan2(0, 1) = 0 (East)

After sorting ascending (counter-clockwise: S → E → N → W):

fp_face_info
  fp0: [0, 4]   # 4 entries starting at slot 0
  fp1: [4, 1]
  fp2: [5, 1]
  fp3: [6, 1]
  fp4: [7, 1]

fp_face_values          # [face_idx, orientation]  (-1=fpA, +1=fpB)
  slot 0: [1, -1]  ← face 1 (South), fp0 is fpA
  slot 1: [3, -1]  ← face 3 (East),  fp0 is fpA
  slot 2: [0, -1]  ← face 0 (North), fp0 is fpA
  slot 3: [2, -1]  ← face 2 (West),  fp0 is fpA
  slot 4: [3,  1]  ← face 3, fp1 is fpB
  slot 5: [0,  1]  ← face 0, fp2 is fpB
  slot 6: [2,  1]  ← face 2, fp3 is fpB
  slot 7: [1,  1]  ← face 1, fp4 is fpB

fp0’s faces in angular order: fp_face_values[0:4, 0][1, 3, 0, 2], not [0, 1, 2, 3].

Notes

Derived from _build_fp_face_connectivity and _sort_fp_faces_by_angle in RasMapperLib/MeshFV2D.cs (HEC-RAS 6.6).

property facepoint_face_orientation_info: ndarray

CSR start/count index into facepoint_face_orientation_values.

Shape (n_facepoints, 2), dtype int32. Each row is [start, count] — a slice into facepoint_face_orientation_values for that facepoint. count = number of faces adjacent to that facepoint.

HDF source: FacePoints Face and Orientation Info.

Examples

Using the 5-facepoint mesh from facepoint_face_orientation (fp0 at centre with 4 adjacent faces; fp1–fp4 each with 1):

facepoint_face_orientation_info = np.array([
    [0, 4],   # fp0: 4 entries starting at slot 0
    [4, 1],   # fp1: 1 entry  starting at slot 4
    [5, 1],   # fp2: 1 entry  starting at slot 5
    [6, 1],   # fp3: 1 entry  starting at slot 6
    [7, 1],   # fp4: 1 entry  starting at slot 7
], dtype=np.int32)

To get the entries for fp0:

start, count = info[0]          # 0, 4
fp0_entries = values[start : start + count]   # slots 0-3
property facepoint_face_orientation_values: ndarray

Face index and orientation flag for each facepoint→face entry.

Shape (total_entries, 2), dtype int32. Each row is [face_idx, orientation] where orientation = -1 means this facepoint is fpA (first endpoint) of that face and orientation = +1 means it is fpB (second endpoint). Matches the values written by RasMapper (MeshFV2D.cs: fpA → -1, fpB → +1).

Use facepoint_face_orientation_info to slice per facepoint.

HDF source: FacePoints Face and Orientation Values.

Examples

Using the 5-facepoint mesh from facepoint_face_orientation:

facepoint_face_orientation_values = np.array([
    [1, -1],   # slot 0 — face 1, fp0 is fpA
    [3, -1],   # slot 1 — face 3, fp0 is fpA
    [0, -1],   # slot 2 — face 0, fp0 is fpA
    [2, -1],   # slot 3 — face 2, fp0 is fpA
    [3,  1],   # slot 4 — face 3, fp1 is fpB
    [0,  1],   # slot 5 — face 0, fp2 is fpB
    [2,  1],   # slot 6 — face 2, fp3 is fpB
    [1,  1],   # slot 7 — face 1, fp4 is fpB
], dtype=np.int32)

Note that the face indices for fp0 (slots 0–3) are [1, 3, 0, 2], not [0, 1, 2, 3] — they are in counter-clockwise angular order, not creation order.

property facepoint_to_cells: list[ndarray]

Real cell indices surrounding each facepoint.

Returns a list of length n_facepoints. Element i is a sorted int64 array of cell indices (< n_cells) that include facepoint i as a polygon corner. Ghost cells and the sentinel value -1 are excluded.

Computed once and cached.

property facepoint_to_faces: list[ndarray]

Face indices adjacent to each facepoint.

Returns a list of length n_facepoints. Element i is an int64 array of face indices whose endpoints include facepoint i. Most interior facepoints are shared by exactly two faces; boundary facepoints may appear in more.

Computed once and cached.

property ghost_cell_centers: ndarray

x, y coordinates of ghost (boundary) cell centres.

Ghost cells occupy indices n_cells .. n_total-1 in the HDF datasets. They hold boundary-condition data and are needed when reconstructing WSE or velocity at perimeter faces.

Returns:

May be empty (shape (0, 2)) if the HDF stores no ghost rows.

Return type:

ndarray, shape (n_ghost, 2)

property mesh_bbox: ndarray

Overall bounding box of the flow area. Shape (4,).

Returns [xmin, ymin, xmax, ymax] covering all cells.

property n_cells: int

Number of real computational cells (ghost cells excluded).

property n_faces: int

Total number of cell faces.

property name: str

Name of the 2-D flow area.

property perimeter: ndarray

Boundary polygon of the 2-D flow area. Shape (n_pts, 2).

class rivia.hdf.geometry.FlowAreaCollection(hdf)[source]

Bases: Mapping[str, FlowArea]

Access all 2-D flow areas stored in an HDF geometry or plan file.

Implements the collections.abc.Mapping protocol: supports len(), iteration, in, [], .keys(), .values(), .items(), and .get().

Parameters:

hdf (File) – Open h5py.File handle.

property names: list[str]

Names of all 2-D flow areas in the file.

property summary: DataFrame

One row per 2-D flow area with geometry attributes.

Columns include name, cell_count, and all other fields from the Geometry/2D Flow Areas/Attributes structured dataset.

Raises:

KeyError – If the Geometry/2D Flow Areas group is absent (e.g. a 1D-only geometry file).

class rivia.hdf.geometry.GateGroup(name, width, height, invert, sluice_coefficient, radial_coefficient, weir_coefficient, spillway_shape, openings=<factory>)[source]

Bases: object

One gate group from Geometry/Structures/Gate Groups/Attributes.

A gate group defines a set of identical gate openings. Each opening in the group shares the same geometry (width, height, invert, coefficients) but is placed at a different station along the structure.

Variables:
  • name – Gate group label (e.g. 'Gate #1').

  • width – Gate opening width (ft or m).

  • height – Gate opening height (ft or m).

  • invert – Gate sill elevation.

  • sluice_coefficient – Sluice gate discharge coefficient.

  • radial_coefficient – Radial (Tainter) gate discharge coefficient.

  • weir_coefficient – Overflow weir coefficient for the gate crest.

  • spillway_shape – Crest shape used when gate overflows (e.g. 'Broad Crested').

  • openings – Individual openings in this group, one per physical gate bay.

Parameters:
height: float
invert: float
name: str
openings: list[GateOpening]
radial_coefficient: float
sluice_coefficient: float
spillway_shape: str
weir_coefficient: float
width: float
class rivia.hdf.geometry.GateOpening(name, station)[source]

Bases: object

One physical opening within a GateGroup.

Variables:
  • name – Opening label (HDF Name in Gate Groups/Openings/Attributes).

  • station – Lateral station of this opening along the structure centreline (HDF Station).

Parameters:
name: str
station: float
class rivia.hdf.geometry.Geometry(filename)[source]

Bases: _HdfFile

Read HEC-RAS geometry HDF5 output files (*.g*.hdf).

Parameters:

filename (str | Path) – Path to the geometry HDF file. The .hdf suffix is appended automatically if absent.

Examples

with Geometry("MyModel.g01") as g:
    print(g.flow_areas.summary)
    centers = g.flow_areas["spillway"].cell_centers
property boundary_condition_lines: BoundaryConditionCollection

Access boundary condition lines stored in the geometry HDF.

center_coordinates(location)[source]

Return the centre coordinates for a cross section, storage area, or 2-D flow area cell.

The location tuple is interpreted differently depending on which element type is identified:

  • Cross section(river, reach, rs) Both river and reach must be non-empty. Returns the intersection of the XS cut line with the river centreline polyline (i.e. CrossSection.centerline_coordinates).

  • Storage area(name, "", "") or (name, None, None) reach is empty or None. Returns the area-weighted centroid of the boundary polygon (i.e. StorageArea.centroid).

  • 2-D flow area cell(area_name, "", cell_index) or (area_name, None, cell_index) reach is empty or None; cell_index is the integer cell number as a string. Returns the cell centre coordinate from FlowArea.cell_centers.

Parameters:

location (tuple[str, str | None, str | None]) – Three-element tuple (a, b, c) described above.

Returns:

[x, y] of the requested centre point.

Return type:

ndarray, shape (2,)

Raises:
  • KeyError – If the named cross section, storage area, or flow area is not found in the HDF.

  • ValueError – If the cross section has no centreline match (its centerline_coordinates is None), or cell_index is not a valid integer or is out of range for the flow area.

Examples

with Geometry("MyModel.g01") as g:
    # 1-D cross section
    xy = g.center_coordinates(("Bald Eagle Cr.", "Lock Haven", "137520"))
    # Storage area
    xy = g.center_coordinates(("Reservoir", "", ""))
    # 2-D flow area cell 42
    xy = g.center_coordinates(("Perimeter 1", "", "42"))
property cross_sections: CrossSectionCollection

Access all 1-D cross sections stored in the geometry HDF.

property flow_areas: FlowAreaCollection

Access 2-D flow areas stored in the geometry HDF.

geometry_summary()[source]

Return metadata from the Geometry/ group attributes.

Reads the top-level attributes of the Geometry HDF group and returns a GeometrySummary dataclass. The method is available on Geometry, SteadyPlan, and UnsteadyPlan because both plan types inherit from Geometry.

Return type:

GeometrySummary

Raises:

KeyError – If the Geometry group is absent from the HDF file.

Examples

with Geometry("MyModel.g01") as g:
    s = g.geometry_summary()
    print(s.title)
    print(s.extents)
    print(s.si_units)
property projection: str | None

WKT projection string stored in the HDF root attribute, or None.

HEC-RAS writes the model CRS as a WKT string in the root-level Projection attribute. Returns None when the attribute is absent (older files or models without a defined projection).

The raw WKT string can be converted to a pyproj.CRS or a rasterio.crs.CRS object if needed:

import pyproj
crs = pyproj.CRS.from_wkt(geom.projection)
Return type:

str or None

property river_geometry: RiverGeometry

Access river centrelines, bank lines, and edge lines.

property storage_areas: StorageAreaCollection

Access storage areas (reservoirs, ponds) stored in the geometry HDF.

property structures: StructureCollection

Access all structures (connections, bridges, laterals, inline weirs).

class rivia.hdf.geometry.GeometrySummary(title, version, complete, si_units, extents, preprocessed_at, terrain, land_cover, infiltration, pct_impervious)[source]

Bases: object

Metadata from the Geometry/ group attributes.

Variables:
  • title – Geometry title string set in RASMapper.

  • version – Geometry schema version, e.g. "1.0.20 (20Sep2024)".

  • completeTrue when the geometry was fully preprocessed.

  • si_unitsTrue when the model uses SI units; False for US Customary.

  • extents – Bounding box as (xmin, xmax, ymin, ymax) in model coordinates, or None when the geometry has no spatial reference.

  • preprocessed_at – Timestamp when RASMapper last preprocessed the geometry, or None when the geometry has never been preprocessed (HEC-RAS stores the sentinel '00JAN0000 00:00:00' in that case).

  • terrain – Terrain layer reference, or None for non-geospatial models.

  • land_cover – Land-cover (Manning’s n) layer reference, or None when absent.

  • infiltration – Infiltration layer reference, or None when absent.

  • pct_impervious – Percent-impervious layer reference, or None when absent.

Parameters:
complete: bool
extents: tuple[float, float, float, float] | None
infiltration: LayerRef | None
land_cover: LayerRef | None
pct_impervious: LayerRef | None
preprocessed_at: datetime | None
si_units: bool
terrain: LayerRef | None
title: str
version: str
class rivia.hdf.geometry.InlineStructure(mode, upstream_type, downstream_type, centerline, location=('', '', ''), upstream_node=('', '', ''), downstream_node=('', '', ''), weir=None, gate_groups=<factory>)[source]

Bases: Structure

Inline structure (e.g. inline weir/dam) embedded in a 1-D HEC-RAS reach.

Both sides are always 'XS'.

Variables:
  • location(river, reach, rs) of this structure in the 1-D geometry.

  • upstream_node(river, reach, rs) of the adjacent upstream cross section.

  • downstream_node(river, reach, rs) of the adjacent downstream cross section.

  • weir – Weir overflow parameters; None when mode is empty.

  • gate_groups – Gate groups attached to this structure (empty list when none).

Parameters:
downstream_node: tuple[str, str, str] = ('', '', '')
gate_groups: list[GateGroup]
location: tuple[str, str, str] = ('', '', '')
upstream_node: tuple[str, str, str] = ('', '', '')
weir: Weir | None = None
class rivia.hdf.geometry.LateralStructure(mode, upstream_type, downstream_type, centerline, location=('', '', ''), upstream_node=('', '', ''), downstream_node='', weir=None, gate_groups=<factory>)[source]

Bases: Structure

Lateral structure connecting a 1-D reach to a Storage Area or 2-D Flow Area.

The upstream side is always 'XS' (the 1-D reach). The downstream side connects to a Storage Area ('SA'), a 2-D Flow Area ('2D'), or nothing when flow exits the system (empty downstream_type).

Variables:
  • location(river, reach, rs) of this structure in the 1-D geometry.

  • upstream_node(river, reach, rs) of the adjacent upstream cross section.

  • downstream_node – Name of the connected Storage Area or 2-D Flow Area (HDF DS SA/2D). Empty string when flow exits the system.

  • weir – Weir overflow parameters; None when mode is empty.

  • gate_groups – Gate groups attached to this structure (empty list when none).

Parameters:
downstream_node: str = ''
gate_groups: list[GateGroup]
location: tuple[str, str, str] = ('', '', '')
upstream_node: tuple[str, str, str] = ('', '', '')
weir: Weir | None = None
class rivia.hdf.geometry.LayerRef(filename, layername, file_date, date_modified)[source]

Bases: object

Reference to a RASMapper HDF layer.

Variables:
  • filename – Absolute path to the HDF file containing this layer, resolved relative to the project directory at read time.

  • layername – Layer name inside the HDF file.

  • file_date – Timestamp of the HDF file.

  • date_modified – Timestamp when the layer was last modified, or None when HEC-RAS does not record a modification date. For terrain layers in models with 2-D flow areas this is the terrain HDF mtime recorded by each flow area at preprocessing time (the most recent across all flow areas is used).

Parameters:
date_modified: datetime | None
file_date: datetime
filename: Path
layername: str
class rivia.hdf.geometry.RiverBankLine(polyline)[source]

Bases: object

One HEC-RAS river bank line from Geometry/River Bank Lines.

Bank lines are stored as an ordered pair — index 0 is the left bank, index 1 is the right bank (as drawn in RASMapper).

Variables:

polyline – Plan-view bank-line coordinates, shape (n, 2): [x, y].

Parameters:

polyline (ndarray)

polyline: ndarray
class rivia.hdf.geometry.RiverCenterline(river, reach, upstream_type, upstream_name, downstream_type, downstream_name, junction_to_us_xs, ds_xs_to_junction, polyline)[source]

Bases: object

One HEC-RAS river centreline from Geometry/River Centerlines.

Variables:
  • river – River name (HDF River Name field).

  • reach – Reach name (HDF Reach Name field).

  • upstream_type – Upstream connection type (HDF US Type field). Common values: 'XS' (cross section), '2D Flow Area', 'Storage Area', 'External'.

  • upstream_name – Name of the upstream connected element (HDF US Name field).

  • downstream_type – Downstream connection type (HDF DS Type field). Same vocabulary as upstream_type.

  • downstream_name – Name of the downstream connected element (HDF DS Name field).

  • junction_to_us_xs – Distance from the upstream junction to the nearest upstream cross section (HDF Junction to US XS field). NaN when the upstream connection is not a junction.

  • ds_xs_to_junction – Distance from the nearest downstream cross section to the downstream junction (HDF DS XS to Junction field). NaN when the downstream connection is not a junction.

  • polyline – Plan-view centreline coordinates, shape (n, 2). Columns: [x, y]. Source: Geometry/River Centerlines/Polyline Points.

Parameters:
  • river (str)

  • reach (str)

  • upstream_type (str)

  • upstream_name (str)

  • downstream_type (str)

  • downstream_name (str)

  • junction_to_us_xs (float)

  • ds_xs_to_junction (float)

  • polyline (ndarray)

downstream_name: str
downstream_type: str
ds_xs_to_junction: float
junction_to_us_xs: float
polyline: ndarray
reach: str
river: str
upstream_name: str
upstream_type: str
class rivia.hdf.geometry.RiverEdgeLine(polyline)[source]

Bases: object

One HEC-RAS river edge line from Geometry/River Edge Lines.

Edge lines define the extents of the 1-D floodplain corridor.

Variables:

polyline – Plan-view edge-line coordinates, shape (n, 2): [x, y].

Parameters:

polyline (ndarray)

polyline: ndarray
class rivia.hdf.geometry.RiverGeometry(hdf)[source]

Bases: object

Lazy-loaded river geometry lines from a HEC-RAS geometry HDF.

Provides access to river centrelines, left/right bank lines, and edge lines stored under Geometry/ in geometry or plan HDF files.

Parameters:

hdf (File) – Open h5py.File handle.

property bank_lines: tuple[RiverBankLine | None, RiverBankLine | None]

Left and right bank lines as a (left, right) tuple.

Each element is a RiverBankLine or None when absent. HEC-RAS stores exactly two bank lines (index 0 = left, 1 = right).

property centerlines: list[RiverCenterline]

River centrelines. One RiverCenterline per reach.

Returns an empty list when no centreline data is present.

property edge_lines: tuple[RiverEdgeLine | None, RiverEdgeLine | None]

Left and right edge lines as a (left, right) tuple.

Each element is a RiverEdgeLine or None when absent.

class rivia.hdf.geometry.SA2DConnection(mode, upstream_type, downstream_type, centerline, name='', upstream_node='', downstream_node='')[source]

Bases: Structure

Connection structure linking two Storage Areas or 2-D Flow Areas.

Both sides are 'SA', '2D', or '--' (treated as SA by HEC-RAS). Common examples: dam breach connection, levee between two 2-D domains, SA-to-SA link.

Variables:
  • name – User-given connection name from the HDF Connection field (e.g. "Dam", "Lower Levee").

  • upstream_node – Name of the upstream Storage Area or 2-D Flow Area (HDF US SA/2D).

  • downstream_node – Name of the downstream Storage Area or 2-D Flow Area (HDF DS SA/2D).

Parameters:
  • mode (str)

  • upstream_type (str)

  • downstream_type (str)

  • centerline (ndarray)

  • name (str)

  • upstream_node (str)

  • downstream_node (str)

Notes

Plan-result groups (see SA2DConnectionResults) may use a different naming convention: for 2D↔2D connections HEC-RAS prefixes the flow area name (e.g. geometry "Lower Levee" → plan result "BaldEagleCr Lower Levee").

downstream_node: str = ''
name: str = ''
upstream_node: str = ''
class rivia.hdf.geometry.StorageArea(name, mode, boundary, volume_elevation)[source]

Bases: object

Geometry for a single HEC-RAS storage area (reservoir, pond, etc.).

Variables:
  • name – Name of the storage area.

  • mode – Storage mode string from HEC-RAS (e.g. "Elev Vol RC" for an elevation-volume rating curve, or "Normal" for a flat-pool).

  • boundary – x, y coordinates of the storage area boundary polygon. Shape (n_pts, 2).

  • volume_elevation – Elevation-volume rating curve. Shape (n_pairs, 2) with columns [elevation, volume]. Empty array (shape (0, 2)) when the storage area has no rating curve (e.g. flat-pool mode).

Parameters:
boundary: ndarray
property centroid: ndarray

Centroid of the boundary polygon, shape (2,).

Computed using the standard shoelace formula so the result is exact for any simple (non-self-intersecting) polygon and is not biased by uneven vertex spacing along the boundary.

Returns:

[x, y] of the polygon centroid.

Return type:

ndarray, shape (2,)

Raises:

ValueError – If boundary has fewer than three points.

property elevations: ndarray

Elevation column of the rating curve. Shape (n_pairs,).

mode: str
name: str
volume_at_elevation(wse)[source]

Return interpolated stored volume at wse.

Uses linear interpolation via numpy.interp. Values outside the rating-curve range are clamped to the curve endpoints.

Raises:

ValueError – If the storage area has no volume-elevation rating curve.

Return type:

float

Parameters:

wse (float)

volume_elevation: ndarray
property volumes: ndarray

Volume column of the rating curve. Shape (n_pairs,).

class rivia.hdf.geometry.StorageAreaCollection(hdf)[source]

Bases: Mapping[str, StorageArea]

Access all storage areas stored in an HDF geometry file.

Implements the collections.abc.Mapping protocol: supports len(), iteration, in, [], .keys(), .values(), .items(), and .get().

Parameters:

hdf (File) – Open h5py.File handle.

property names: list[str]

Names of all storage areas in the file.

property summary: DataFrame

One row per storage area with basic attributes.

Columns: name, mode, n_boundary_points, n_elev_vol_pairs.

class rivia.hdf.geometry.Structure(mode, upstream_type, downstream_type, centerline)[source]

Bases: object

Base class for one HEC-RAS structure from Geometry/Structures/Attributes.

Variables:
  • mode – HDF Mode field (e.g. 'Weir/Gate/Culverts'). Empty string when the field is blank.

  • upstream_type – HDF US Type field: 'XS' (1-D cross section), 'SA' (storage area), '2D' (2-D flow area), or '--' (unspecified / treated as storage area by HEC-RAS).

  • downstream_type – HDF DS Type field — same vocabulary as upstream_type.

  • centerline – x, y coordinates of the structure centreline. Shape (n_pts, 2).

Parameters:
centerline: ndarray
downstream_type: str
mode: str
upstream_type: str
class rivia.hdf.geometry.StructureCollection(hdf)[source]

Bases: object

Access all structures stored in Geometry/Structures/Attributes.

The collection is keyed by a string identifier:

Use the typed filter properties (connections, bridges, laterals, inlines) to narrow by structure subclass.

Parameters:

hdf (File) – Open h5py.File handle.

property bridges: StructureIndex[Bridge]

All Bridge instances keyed by "River Reach RS".

property connections: StructureIndex[SA2DConnection]

All SA2DConnection instances keyed by connection name.

property inlines: StructureIndex[InlineStructure]

All InlineStructure instances keyed by "River Reach RS".

property laterals: StructureIndex[LateralStructure]

All LateralStructure instances keyed by "River Reach RS".

property names: list[str]

Keys of all structures in the collection.

property summary: DataFrame

One row per structure with basic attributes.

Columns: key, subclass, mode, upstream_type, upstream_node, downstream_type, downstream_node, n_centerline_points.

upstream_node / downstream_node are (river, reach, rs) tuples for Bridge and InlineStructure sides, and plain strings (area names) for SA2DConnection and LateralStructure downstream sides.

class rivia.hdf.geometry.StructureIndex(items)[source]

Bases: Generic[_T]

Ordered mapping of structures supporting string-key and integer-index access.

Behaves like a read-only dict but also accepts integer positions:

coll["Lower Levee"]   # by name
coll[0]               # first item (insertion order)
coll[-1]              # last item
len(coll)
list(coll.keys())
for name, obj in coll.items(): ...
Parameters:

items (dict[str, TypeVar(_T)]) – Ordered dict of {name: structure} pairs.

items()[source]

(key, value) pairs in insertion order.

keys()[source]

Keys in insertion order.

property names: list[str]

All keys in insertion order.

values()[source]

Values in insertion order.

class rivia.hdf.geometry.Weir(width, coefficient, shape, max_submergence, min_elevation, us_slope, ds_slope, skew, use_water_surface)[source]

Bases: object

Overflow weir parameters read from Geometry/Structures/Attributes.

Present on Bridge, InlineStructure, and LateralStructure structures when mode is 'Weir/Gate/Culverts'.

Variables:
  • width – Weir crest length perpendicular to flow (HDF Weir Width).

  • coefficient – Discharge coefficient (HDF Weir Coef).

  • shape – Crest shape: 'Broad Crested', 'Ogee', etc. (HDF Weir Shape).

  • max_submergence – Maximum submergence ratio above which flow is fully submerged (HDF Weir Max Submergence).

  • min_elevation – Minimum crest elevation; nan when not set (HDF Weir Min Elevation).

  • us_slope – Upstream face slope H:V (HDF Weir US Slope).

  • ds_slope – Downstream face slope H:V (HDF Weir DS Slope).

  • skew – Skew angle in degrees (HDF Weir Skew).

  • use_water_surface – When True the water-surface elevation is used as the weir reference head; when False the energy grade line is used (HDF Use WS for Weir Reference).

Parameters:
coefficient: float
ds_slope: float
max_submergence: float
min_elevation: float
shape: str
skew: float
us_slope: float
use_water_surface: bool
width: float