Core API

This section documents the main API for using pyhnhtools.

Adapter Module

Adapter to bridge legacy backwater_qt.py GUI to new std_step_1d solver API.

Provides ModelInput, CrossSection, and run_backwater() to maintain compatibility with the PyQt5-based backwater_qt.py GUI while using the new pyhnhtools solver.

class pyhnhtools.standard_step_1d_adapter.CrossSection(river_station, geometry, left_bank_station, right_bank_station, n_lob, n_ch, n_rob, contraction_coeff, expansion_coeff, L_lob_to_next, L_ch_to_next, L_rob_to_next, ineffective_areas=<factory>)[source]

Bases: object

Legacy cross-section representation for GUI compatibility.

Parameters:
river_station: str
geometry: List[Tuple[float, float]]
left_bank_station: float
right_bank_station: float
n_lob: float
n_ch: float
n_rob: float
contraction_coeff: float
expansion_coeff: float
L_lob_to_next: float
L_ch_to_next: float
L_rob_to_next: float
ineffective_areas: List[List[float]]
class pyhnhtools.standard_step_1d_adapter.ModelInput(flow_cfs, flow_change, boundary_condition, boundary_value, sections)[source]

Bases: object

Legacy model input representation for GUI compatibility.

Parameters:
flow_cfs: float
flow_change: float | None
boundary_condition: str
boundary_value: float
sections: List[CrossSection]
class pyhnhtools.standard_step_1d_adapter.SolverResult(wse, depth_at_min, V_t, alpha, K_t, A_t, Sf_total, info)

Bases: tuple

Create new instance of SolverResult(wse, depth_at_min, V_t, alpha, K_t, A_t, Sf_total, info)

A_t

Alias for field number 5

K_t

Alias for field number 4

Sf_total

Alias for field number 6

V_t

Alias for field number 2

alpha

Alias for field number 3

depth_at_min

Alias for field number 1

info

Alias for field number 7

wse

Alias for field number 0

pyhnhtools.standard_step_1d_adapter.run_backwater(model_input, solver_method='secant')[source]

Run the backwater solver using the new std_step_1d API.

Converts legacy ModelInput to new std_step_1d.Reach and returns result objects compatible with backwater_qt.py expectations.

Parameters:
  • model_input (ModelInput) – Legacy ModelInput with sections, flow, BC

  • solver_method (str) – ‘secant’ (default, HEC-RAS standard) or ‘brent’ (faster, constrained to subcritical). Both maintain conservative fallback to critical depth for Fr > 0.92.

Return type:

List[SolverResult]

Returns:

List of SolverResult namedtuples with results for each section

pyhnhtools.standard_step_1d_adapter.compute_area(stations, elevations, wse)[source]

Compute cross-sectional flow area below water surface elevation.

Return type:

float

Parameters:
pyhnhtools.standard_step_1d_adapter.compute_wetted_perimeter(stations, elevations, wse)[source]

Compute wetted perimeter below water surface elevation.

Return type:

float

Parameters:
pyhnhtools.standard_step_1d_adapter.load_input(path)[source]

Load a ModelInput from a JSON or HEC-RAS HDF geometry file.

Supports three formats: 1. Legacy backwater JSON with ‘sections’ key 2. pyhnhtools parsed JSON with ‘cross_sections’ key 3. HEC-RAS HDF geometry file (.g##.hdf) - automatically parsed via ras-commander

IMPORTANT: Sections are sorted in ASCENDING order by river station. The Reach solver expects sections ordered downstream (low RS, index 0) to upstream (high RS, last index). The boundary condition is applied at the downstream section (index 0), and the solver marches UPSTREAM from there using the energy equation.

Example: If sections have RS [643, 31, 500], they will be reordered as [31, 500, 643] so that the solver can apply BC at RS 31 (downstream) and march upstream toward RS 643.

Return type:

ModelInput

Parameters:

path (str)

pyhnhtools.standard_step_1d_adapter.load_from_geopackage(path)[source]

Load a ModelInput from a GeoPackage (stub for now).

Return type:

ModelInput

Parameters:

path (str)

pyhnhtools.standard_step_1d_adapter.save_to_geopackage(path, model)[source]

Save a ModelInput to a GeoPackage (stub for now).

Return type:

None

Parameters:

Standard Step 1D Module

Standard-step 1D solver module ported into pyhnhtools.

This is a near-direct port of the working hec_ras_solver.py solver into the pyhnhtools package as std_step_1d so it can be imported as pyhnhtools.std_step_1d by runner scripts and the GUI.

class pyhnhtools.std_step_1d.CrossSection(stations, n_values, ich_start, ich_end, reach_station=0.0, bank_stations=None, ineffective_left_frac=0.0, ineffective_right_frac=0.0, ineffective_areas=<factory>)[source]

Bases: object

Parameters:
stations: List[Tuple[float, float]]
n_values: List[float]
ich_start: int
ich_end: int
reach_station: float = 0.0
bank_stations: Tuple[float, float] | None = None
ineffective_left_frac: float = 0.0
ineffective_right_frac: float = 0.0
ineffective_areas: List[List[float]]
area_perimeter_for_ws(ws, i0, i1)[source]
Parameters:
channel_invert()[source]
Return type:

float

top_width(ws)[source]
Return type:

float

Parameters:

ws (float)

conveyance_subdivision(ws)[source]
Parameters:

ws (float)

pyhnhtools.std_step_1d.solve_subreach_energy(Q, cs1, Y1, cs2, tol=0.01, max_iter=20, verbose=True, solver_method='secant')[source]

Solve the energy / gradually-varied flow relation for a single sub-reach.

A “sub-reach” here means a single adjacent pair of cross-sections where cs1 is the downstream section and cs2 is the upstream section. This function returns the upstream depth (Y2) relative to the upstream channel invert and a dict with solver diagnostics.

Parameters:
  • Q (float) – Discharge (same units as cross-sections).

  • cs1 (CrossSection) – Downstream CrossSection instance.

  • Y1 (float) – Downstream depth (ft) above the downstream invert.

  • cs2 (CrossSection) – Upstream CrossSection instance.

  • tol – Convergence tolerance (default 0.01).

  • max_iter – Maximum number of iterations.

  • verbose – If True, print progress messages.

  • solver_method – ‘secant’ (default, HEC-RAS standard with step-limiting) or ‘brent’ (hybrid Brent’s method, constrained to subcritical region). The secant method is conservative and matches HEC-RAS behavior. The Brent method is faster but requires well-posed bracketing.

Returns:

A tuple (Y2, info) where Y2 is the upstream depth and info is a dictionary containing at least 'converged', 'method', and 'iters'. Critical depth fallback is applied if Fr > 0.92 (HEC-RAS standard for supercritical).

pyhnhtools.std_step_1d.solve_reach_standard_step(Q, cs1, Y1, cs2, tol=0.01, max_iter=20, verbose=True, solver_method='secant')[source]

Deprecated alias for solve_subreach_energy().

The old name remains for compatibility; prefer solve_subreach_energy().

Parameters:
class pyhnhtools.std_step_1d.Reach(cross_sections, fixed_wse=None)[source]

Bases: object

A simple container representing a reach (ordered cross-sections).

The reach stores a list of CrossSection objects ordered from downstream (index 0) to upstream (last index). The march method performs a downstream->upstream march solving each adjacent sub-reach and returns upstream depths and diagnostics.

Parameters:
cross_sections: List[CrossSection]
fixed_wse: float | None = None
classmethod from_parsed(parsed)[source]

Create a Reach from the parsed JSON model structure returned by load_model.

The parsed structure is expected to contain a top-level 'cross_sections' list with records compatible with the existing CrossSection factory code.

Return type:

Reach

Parameters:

parsed (dict)

march(Q, Y0=None, tol=0.01, max_iter=20, verbose=False, solver_method='secant')[source]

March downstream->upstream across the reach solving each adjacent sub-reach.

Parameters:
  • Q (float) – Discharge.

  • Y0 (Optional[float]) – Optional starting downstream depth. If not provided and fixed_wse is present, it will be used to compute the downstream depth relative to the downstream invert.

  • tol – Convergence tolerance (default 0.01).

  • max_iter – Maximum iterations for secant method.

  • verbose – If True, print solver progress.

  • solver_method – ‘secant’ (default, HEC-RAS standard) or ‘brent’ (faster, constrained to subcritical region).

Returns:

A tuple (Y_list, info_list) where Y_list is a list of depths for each cross-section (same order as cross_sections) and info_list is a list of per-subreach diagnostics including solver method and convergence info.

Parsers Module

Parsers for HEC-RAS and other hydraulics file formats.

class pyhnhtools.parsers.G01Parser(filepath)[source]

Bases: object

Parser for HEC-RAS .g01 geometry files.

Initialize parser with g01 file path.

Parameters:

filepath (str)

__init__(filepath)[source]

Initialize parser with g01 file path.

Parameters:

filepath (str)

parse()[source]

Parse .g01 file and return cross-sections in std_step_1d format.

Return type:

List[Dict]

Returns:

List of cross-section dictionaries with geometry, manning values, and critical subreach lengths.

to_json(output_path=None)[source]

Convert parsed geometry to JSON format compatible with std_step_1d.

Parameters:

output_path (Optional[str]) – Optional path to write JSON to file

Return type:

str

Returns:

JSON string representation

pyhnhtools.parsers.load_from_ras_hdf(hdf_path)[source]

Load cross-section data from HEC-RAS HDF geometry file using ras-commander.

Parameters:

hdf_path (str) – Path to .g##.hdf geometry file

Return type:

Dict

Returns:

Dict in pyhnhtools format with cross_sections

pyhnhtools.parsers.convert_g01_to_model_using_hdf(hdf_path, output_json=None)[source]

Parse HEC-RAS geometry using HDF (via ras-commander) and output JSON.

Parameters:
  • hdf_path (str) – Path to .g##.hdf file

  • output_json (Optional[str]) – Optional path to write JSON

Return type:

str

Returns:

JSON string

Culverts Module

Project: EPA SWMM5 Version: 5.1 Date: 03/20/14 (Build 5.1.001) Author: L. Rossman

Culvert equations for SWMM5

Computes flow reduction in a culvert-type conduit due to inlet control using equations from the FHWA HEC-5 circular.

Python translation & headwater solver: - Preserves all data contained in the original culvert.c (incl. comments). - Adds:

  • Simple geometry classes for circular & rectangular sections.

  • A Ridder root finder (pure stdlib).

  • A function to solve headwater depth h for a given flow Q.

  • An optional CLI.

Units: feet, seconds, cfs (consistent with the original code).

IMPORTANT: - Where the original C referenced SWMM objects (Link, Conduit, Node, TXsect)

this module provides a minimal substitute: a “Xsect” object with required attributes/methods.


class pyhnhtools.culverts.Culvert(yFull, scf, dQdH, qc, kk, mm, ad, hPlus, xsect)[source]

Bases: object

Parameters:
yFull: float
scf: float
dQdH: float
qc: float
kk: float
mm: float
ad: float
hPlus: float
xsect: Xsect
class pyhnhtools.culverts.CulvertConfig(code, slope, shape, diam_ft=None, width_ft=None, height_ft=None, inlet_elev=0.0)[source]

Bases: object

User-facing culvert configuration.

Notes: units are feet/seconds/cfs to match the underlying implementation.

Parameters:
code: int
slope: float
shape: str
diam_ft: float | None = None
width_ft: float | None = None
height_ft: float | None = None
inlet_elev: float = 0.0
class pyhnhtools.culverts.HeadwaterResult(headwater_wse, h_above_invert, q, condition, yratio, converged, iters, notes)[source]

Bases: NamedTuple

Create new instance of HeadwaterResult(headwater_wse, h_above_invert, q, condition, yratio, converged, iters, notes)

Parameters:
headwater_wse: float

Alias for field number 0

h_above_invert: float

Alias for field number 1

q: float

Alias for field number 2

condition: int

Alias for field number 3

yratio: float

Alias for field number 4

converged: bool

Alias for field number 5

iters: int

Alias for field number 6

notes: str | None

Alias for field number 7

class pyhnhtools.culverts.Xsect(y_full, a_full, culvert_code)[source]

Bases: object

Parameters:
area(y)[source]
Return type:

float

Parameters:

y (float)

top_width(y)[source]
Return type:

float

Parameters:

y (float)

class pyhnhtools.culverts.CircularXsect(diameter_ft, culvert_code)[source]

Bases: Xsect

Circular conduit (diameter = yFull).

Parameters:
  • diameter_ft (float)

  • culvert_code (int)

area(y)[source]
Return type:

float

Parameters:

y (float)

top_width(y)[source]
Return type:

float

Parameters:

y (float)

class pyhnhtools.culverts.RectangularXsect(width_ft, height_ft, culvert_code)[source]

Bases: Xsect

Rectangular box B x H (yFull = H).

Parameters:
area(y)[source]
Return type:

float

Parameters:

y (float)

top_width(y)[source]
Return type:

float

Parameters:

y (float)

pyhnhtools.culverts.ridder(f, a, b, tol=1e-06, max_iter=100)[source]

Ridder’s method: requires a bracket [a,b] with opposite-signed f(a), f(b).

Return type:

float

Parameters:
pyhnhtools.culverts.getUnsubmergedFlow(code, h, culvert)[source]

// Input: code = culvert type code number // h = inlet water depth above culvert invert // culvert = pointer to a culvert data structure // Output: returns flow rate; // computes value of variable Dqdh // Purpose: computes flow rate and its derivative for unsubmerged // culvert inlet.

Return type:

float

Parameters:
pyhnhtools.culverts.getSubmergedFlow(code, h, culvert)[source]

// Input: code = culvert type code number // h = inlet head (ft) // culvert = pointer to a culvert data structure // Output: returns flow rate; // computes value of Dqdh // Purpose: computes flow rate and its derivative for submerged // culvert inlet.

Return type:

float

Parameters:
pyhnhtools.culverts.getTransitionFlow(code, h, h1, h2, culvert)[source]

// Input: code = culvert type code number // h = inlet water depth above culvert invert (ft) // h1 = head limit for unsubmerged condition (ft) // h2 = head limit for submerged condition (ft) // culvert = pointer to a culvert data structure // Output: returns flow rate (cfs); // computes value of Dqdh (cfs/ft) // Purpose: computes flow rate and its derivative for inlet-controlled flow // when inlet water depth lies in the transition range between // submerged and unsubmerged conditions.

Return type:

float

Parameters:
pyhnhtools.culverts.form1Eqn(yc, culvert)[source]

// Input: yc = critical depth // Output: returns residual error // Purpose: evaluates the error in satisfying FHWA culvert Equation Form1: // // h/yFull + 0.5*s = yc/yFull + yh/2/yFull + K[ac/aFull*sqrt(g*yh/yFull)]^M // // for a given value of critical depth yc where: // h = inlet depth above culvert invert // s = culvert slope // yFull = full depth of culvert // yh = hydraulic depth at critical depth // ac = flow area at critical depth // g = accel. of gravity // K and M = coefficients

Return type:

float

Parameters:
pyhnhtools.culverts.getForm1Flow(h, culvert)[source]

// Input: h = inlet water depth above culvert invert // culvert = pointer to a culvert data structure // Output: returns inlet controlled flow rate // Purpose: computes inlet-controlled flow rate for unsubmerged culvert // using FHWA Equation Form1. // // See pages 195-196 of FHWA HEC-5 (2001) for details.

Return type:

float

Parameters:
pyhnhtools.culverts.inlet_controlled_flow(xsect, slope, h)[source]

Returns (q, dQdH, condition, yRatio) for a given inlet head h (ft) using the same logic as culvert_getInflow() in the original C.

condition: 0 = transition, 1 = unsubmerged, 2 = submerged yRatio = h / yFull

Return type:

tuple[float, float, int, float]

Parameters:
pyhnhtools.culverts.solve_headwater_depth_for_Q(xsect, slope, Q_target, h_min=0.0, h_max=None, tol_h=1e-05, tol_q=1e-06, max_iter=120)[source]

Solve for headwater depth h (ft above invert) so that inlet-controlled Q(h) = Q_target.

Returns (h, q, condition, yRatio).

Return type:

tuple[float, float, int, float]

Parameters:
pyhnhtools.culverts.report_CulvertControl(link_id, q0, q, condition, yRatio)[source]
Return type:

None

// Used for debugging only // // static char* conditionTxt[] = {“transition”, “unsubmerged”, “submerged”}; // fprintf(Frpt.file, // “

Parameters:
%11s: %8s Culvert %s flow reduced from %.3f to %.3f cfs for %s flow (%.2f).”,

// theDate, theTime, Link[j].ID, q0, q, conditionTxt[condition], yRatio);

pyhnhtools.culverts.compute_headwater(code, slope, Q, shape, diam_ft=None, width_ft=None, height_ft=None, h_max=None, verbose=True)[source]

Programmatic equivalent of the CLI invocation.

Parameters match the CLI: code, slope, Q, and shape (“circular” or “rect”). For circular, provide diam_ft; for rect, provide width_ft and height_ft.

Returns the tuple (h, q, condition, yRatio) and prints the same report as the CLI when verbose=True.

Return type:

tuple[float, float, int, float]

Parameters:
pyhnhtools.culverts.compute_headwater_api(cfg, Q, h_max=None, *, verbose=False)[source]

Compute headwater using an easy-to-call config object.

Returns a HeadwaterResult. This wrapper delegates to the module’s compute_headwater function and converts outputs into a typed result.

Return type:

HeadwaterResult

Parameters:
pyhnhtools.culverts.launch_gui()[source]