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:
objectLegacy cross-section representation for GUI compatibility.
- class pyhnhtools.standard_step_1d_adapter.ModelInput(flow_cfs, flow_change, boundary_condition, boundary_value, sections)[source]
Bases:
objectLegacy model input representation for GUI compatibility.
- Parameters:
- 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:
tupleCreate 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, BCsolver_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:
- 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.
- pyhnhtools.standard_step_1d_adapter.compute_wetted_perimeter(stations, elevations, wse)[source]
Compute wetted perimeter below water surface elevation.
- 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:
- Parameters:
path (str)
- pyhnhtools.standard_step_1d_adapter.load_from_geopackage(path)[source]
Load a ModelInput from a GeoPackage (stub for now).
- Return type:
- 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:
- Parameters:
path (str)
model (ModelInput)
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:
- 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
cs1is the downstream section andcs2is 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) – DownstreamCrossSectioninstance.Y1 (
float) – Downstream depth (ft) above the downstream invert.cs2 (
CrossSection) – UpstreamCrossSectioninstance.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)whereY2is the upstream depth andinfois 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:
Q (float)
cs1 (CrossSection)
Y1 (float)
cs2 (CrossSection)
- class pyhnhtools.std_step_1d.Reach(cross_sections, fixed_wse=None)[source]
Bases:
objectA simple container representing a reach (ordered cross-sections).
The reach stores a list of
CrossSectionobjects ordered from downstream (index 0) to upstream (last index). Themarchmethod 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)
- cross_sections: List[CrossSection]
- 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.
- 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 andfixed_wseis 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)whereY_listis a list of depths for each cross-section (same order ascross_sections) andinfo_listis 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:
objectParser for HEC-RAS .g01 geometry files.
Initialize parser with g01 file path.
- Parameters:
filepath (str)
- pyhnhtools.parsers.load_from_ras_hdf(hdf_path)[source]
Load cross-section data from HEC-RAS HDF geometry file using ras-commander.
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:
- class pyhnhtools.culverts.CulvertConfig(code, slope, shape, diam_ft=None, width_ft=None, height_ft=None, inlet_elev=0.0)[source]
Bases:
objectUser-facing culvert configuration.
Notes: units are feet/seconds/cfs to match the underlying implementation.
- Parameters:
- class pyhnhtools.culverts.HeadwaterResult(headwater_wse, h_above_invert, q, condition, yratio, converged, iters, notes)[source]
Bases:
NamedTupleCreate new instance of HeadwaterResult(headwater_wse, h_above_invert, q, condition, yratio, converged, iters, notes)
- Parameters:
- class pyhnhtools.culverts.CircularXsect(diameter_ft, culvert_code)[source]
Bases:
XsectCircular conduit (diameter = yFull).
- class pyhnhtools.culverts.RectangularXsect(width_ft, height_ft, culvert_code)[source]
Bases:
XsectRectangular box B x H (yFull = H).
- 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).
- 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.
- 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.
- 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.
- 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
- 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.
- 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
- 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).
- pyhnhtools.culverts.report_CulvertControl(link_id, q0, q, condition, yRatio)[source]
- Return type:
-
// 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.
- 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:
- Parameters:
cfg (CulvertConfig)
Q (float)
h_max (float | None)
verbose (bool)