Water distribution: catalogue¶
Pressurised water networks: pipes, pumps, valves, tanks and demand (EPANET .inp reader). How the pieces fit together: Water distribution.
Every application is set up the same way; see Using noodl.
Import from noodl.apps.water. The full reference, with every parameter, is in the API reference.
Set-up¶
Build the model and its starting state and inputs.
| Name | What it does | How to call it |
|---|---|---|
build_model |
Assemble the water model and return (model, state, drivers). |
build_model(net, *, headloss=None, pda=None, p_min=None, p_req=None, exponent=None, quality=None, coupling='pingpong', dt=None, friction='composite', pipe_form=None, tank_mode='explicit') |
initial_drivers |
build_model's driver template (copied), then values by name (see noodl.refs.drivers_from), then demand: {junction: m3/s withdrawn}, positive, stored as the negative nodal source the head solve takes. |
initial_drivers(model, *, values=None, demand=None) |
initial_state |
All-zero state, dispatching on each layer's quantity (the app convention), tank levels from the network file; then values by node, tank or pump name (see noodl.refs.state_from): initial_state(model, values={"water.tank_level": {"T1": 4.0}}). |
initial_state(model, *, values=None) |
Network components¶
Descriptions of the physical objects a network is built from.
| Name | What it does | How to call it |
|---|---|---|
Control |
One LINK <id> OPEN\|CLOSED IF NODE <tank> BELOW\|ABOVE <level> line. |
Control(link, status, node, test, level) |
Junction |
A junction: elevation (m) and base demand (m3/s, withdrawn), optionally scaled by a time pattern. |
Junction(name, elevation, demand=0.0, pattern=None) |
Pump |
A pump from u to v on a head-flow curve (by name), at relative speed. |
Pump(name, u, v, curve, power=None, speed=1.0) |
Reservoir |
A fixed-head node: total head (m), optionally varied by a time pattern. |
Reservoir(name, head, pattern=None) |
Tank |
A cylindrical tank: bottom elevation, initial, minimum and maximum water levels and diameter (all m); its level is carried across steps by TankLevels. |
Tank(name, elevation, init_level, min_level, max_level, diameter) |
Valve |
A valve from u to v: diameter (m), EPANET kind (for example TCV) and its setting (TCV: a loss coefficient; FCV: a flow, m3/s; PBV: a head drop, m), with a minor-loss coefficient. A GPV's setting is its head-loss curve (a curves key). |
Valve(name, u, v, diameter, kind, setting, minor_loss=0.0, curve=None) |
WaterNetwork |
A pressurised distribution network, in SI, with everything the builder needs. | WaterNetwork(junctions, reservoirs=(), tanks=(), pipes=(), pumps=(), valves=(), curves=<factory>, patterns=<factory>, controls=(), demand_pattern=None, pattern_timestep=3600.0, hydraulic_timestep=3600.0, report_timestep=3600.0, duration=0.0, headloss='H-W', options=<factory>, notes=<factory>) |
WaterOptions |
[OPTIONS] keys that change the physics, with EPANET 2.2's own defaults. |
WaterOptions(demand_model='DDA', minimum_pressure=0.0, required_pressure=0.1, pressure_exponent=0.5, specific_gravity=1.0, viscosity=1.0, flow_units=None) |
WaterPipe |
A pipe from u to v: length and diameter (m), roughness (in the network's head-loss formula's units), a minor-loss coefficient and its status. |
WaterPipe(name, u, v, length, diameter, roughness, minor_loss=0.0, status='OPEN') |
Constitutive laws¶
The relation between the flow through an edge and the potential difference across it.
| Name | What it does | How to call it |
|---|---|---|
BreakerValve |
A pressure breaker valve (PBV): EPANET 2.2's pbvcoeff (hydcoeffs.c). |
BreakerValve(setting, minor, *, kind='pbv') |
CompositeDarcyWeisbachalso EpanetDarcyWeisbach |
Composite Darcy-Weisbach pipe: Hagen-Poiseuille, Dunlop's cubic, then Swamee-Jain. | CompositeDarcyWeisbach(length, diameter, roughness, *, minor_loss=0.0, nu=1.02193344e-06, cfs_per_m3s=None, scale=1.0, rtol=1e-15, max_iter=100, kind='pipe', learnable=False) |
FlowControlledPipe |
A pipe in its resistance form, dp = scale h(q), with the flow an unknown of the layer (build_model's pipe_form="flow"): pipe is the pipe's potential-form law (HazenWilliams or CompositeDarcyWeisbach), whose head_loss gives h. |
FlowControlledPipe(pipe, *, gradient_floor=0.0, kind='pipe') |
FlowControlledPump |
A pump in its head-gain form, phi_discharge - phi_suction = gain(q), with the flow an unknown of the layer, as EPANET's and wntr's own solvers write it. pump is the pump's PumpCurve, whose head_gain gives the gain (with gradient_floor, EPANET's RQtol, and closed_slope, its CBIG, both in the layer's potential per m^3/s). build_model writes every pump in this form, whatever the pipe_form. |
FlowControlledPump(pump, *, gradient_floor, closed_slope, kind='pump') |
GeneralPurposeValve |
A general purpose valve (GPV): EPANET 2.2's gpvcoeff (hydcoeffs.c). |
GeneralPurposeValve(flows, heads, n_points, *, kind='gpv') |
HazenWilliams |
h_L = K q^1.852 + m q^2 with K = 10.666829500036 C^-1.852 d^-4.871 L. |
HazenWilliams(length, diameter, roughness, *, minor_loss=0.0, dp_transition=1e-09, kind='pipe', learnable=False) |
MinorLoss |
h = m q \|q\| with m = K / (2 g A^2): a throttle control valve (TCV) or any pure minor-loss link. Inverted in closed form, q = sign(h) sqrt(\|h\| / m), with the same laminar blend and both-branch safe substitution as HazenWilliams. |
MinorLoss(setting, diameter, *, dp_transition=1e-09, kind='valve', learnable=False) |
PumpCurve |
Constant-speed pump on its own edge kind: h_gain = w^2 (h0 - r (q/w)^n). |
PumpCurve(h0, r, n=2.0, *, speed=1.0, dp_transition=1e-06, status_key=None, kind='pump', learnable=False) |
TankStorage |
A cylindrical tank as storage (build_model(tank_mode="storage")): an edge from the tank's node to a datum at head 0, so that dp is the tank's head times scale and the edge's flow is the net inflow into the tank. The volume above the datum changes by A dH, so in a step of dt. |
TankStorage(area, head0, *, scale=1.0, kind='tank') |
Closures¶
Functions of the state that compute drivers each step (densities, flows, levels).
| Name | What it does | How to call it |
|---|---|---|
TankLevels |
Tank levels, simple controls and the boundary heads they prescribe. | TankLevels(net, tanks, controls, pump_names, *, dt, reservoir_heads, tank_first_index, head_scale=1.0) |
Sources¶
Nodal sources and withdrawals.
| Name | What it does | How to call it |
|---|---|---|
PressureDrivenDemand |
The Wagner demand function as a NodeSource (withdrawal, positive OUT). |
PressureDrivenDemand(nodes, q_required, elevation, *, p_min=0.0, p_req=0.0, exponent=0.5, learnable=False) |
Files¶
Readers and writers of other tools' file formats.
| Name | What it does | How to call it |
|---|---|---|
read_epanet_inp |
Read the documented subset of an EPANET 2.2 .inp into a WaterNetwork, in SI. |
read_epanet_inp(path) |
Functions¶
Calculations and helpers.
| Name | What it does | How to call it |
|---|---|---|
link_table |
One row per link: flow (m3/s), head loss (m) and velocity (m/s); optionally to CSV. | link_table(model, state, names=None, *, path=None) |
pressure_head |
Pressure head (m) at every node: the solved head minus the node's elevation. | pressure_head(model, state, elevations=None) |
composite_friction_factoralso epanet_friction_factor |
Composite friction factor for Re > 2000: (f, df/dq). |
composite_friction_factor(q, e, s) |
tank_inflow |
Net inflow (m3/s) at every tank node, from the layer's solved branch flows. | tank_inflow(model, state) |
tank_levels |
Every tank's level (m above its bottom) in state, in either tank_mode. |
tank_levels(model, state) |
three_point_curve |
EPANET's single-point pump-curve fit: (h0, r, n) for h = h0 - r q^n. |
three_point_curve(q_design, h_design) |
to_kilopascal |
Metres of head -> kPa, at rho = 998.2 kg/m3 and g = 9.80665 m/s2. |
to_kilopascal(head) |
twoloop |
The committed hand-made SI fixture (tests/data/water/twoloop_si.inp). |
twoloop() |
water_step |
One step of dt (s) of a model built with tank_mode="storage": Model.step with water_steady's Newton defaults and pump check, the tank levels stepped implicitly (TankStorage, integration "backward_euler" or "trapezoidal"; trapezoidal needs a step-start state whose tank flows are solved, not the build's zeros). The level controls act on the step-start levels, as EPANET's do. |
water_step(model, state, drivers, dt, *, integration='backward_euler', **solve_kwargs) |
water_steady |
The quasi-steady state: one Model.steady with tight Newton tolerances. |
water_steady(model, state, drivers, **solve_kwargs) |
Constants and tables¶
Named values and option tables.
| Name | Value |
|---|---|
DW_SI |
0.0826 |
EPANET_QCF |
table of 10 entries: CFS, GPM, MGD, IMGD, AFD, LPS, LPM, MLD, ... |
FLOW_UNITS |
table of 10 entries: CFS, GPM, MGD, IMGD, AFD, LPS, LPM, MLD, ... |
G |
9.80665 |
HW_SI |
10.666829500036 |