Below is an extended summary of the code that describes how it constructs a SWMM model profile plot in Python, focusing on node/link geometry, profile configuration, and plot labeling:
Overview
This code supplies a set of matplotlib-based utilities for generating a profile plot (a side-view cut) of a SWMM model network, including nodes (manholes), links (conduits, weirs, orifices, pumps, outlets), ground elevation, and an optional hydraulic grade line (HGL). The profile is built from a path (a sequential chain of upstream-to-downstream elements) and rendered onto a given matplotlib axis (ax
).
Core functionalities:
- Profile Building
build_profile_plot(ax, model, path_selection)
– the central function that orchestrates retrieving geometry from a SWMM model, placing each node/link at the correct horizontal position, and returning a config dictionary (profile_config
) for subsequent use.
- Node & Link Drawing
_add_node_plot(...)
and_add_link_plot(...)
– low-level routines to plot rectangles/trapezoids for manholes or link cross-sections (differentiating between conduits, weirs, orifices, pumps, etc.).
- Ground Line & HGL
_add_ground_plot(...)
– draws the ground-level profile (brown dashed line) across the entire path.add_hgl_plot(...)
– overlays a line that represents the computed or observed water surface elevation at each node (or between nodes).
- Labeling
add_node_labels_plot(...)
– attaches text labels/arrows for each node in the profile.add_link_labels_plot(...)
– attaches text labels/arrows for each link in the profile.
The net result is a layered side-view diagram of how nodes, links, ground line, and HGL align along a chosen path in a SWMM model.
Key Components
1. build_profile_plot(ax, model, path_selection)
Purpose:
- Assembles the entire profile by iterating over a list of
(us_node, ds_node, link_name)
tuples, effectively describing a chain from upstream to downstream. - Produces a dictionary with details on each node/link’s placement, enabling further annotation or plotting.
Process:
-
Initialization
- Retrieves
nodes = model.nodes.dataframe
andlinks = model.links.dataframe
. - Declares
profile_config
with empty lists for “nodes” and “links,” plus “path_selection.” - Sets up arrays for
ground_levels['x']
&ground_levels['level']
.
- Retrieves
-
Iterating over Path
- For each tuple
(us_node, ds_node, link_id)
inpath_selection
:- Plots the first node if
ind == 0
, calling_add_node_plot(...)
and storing the node geometry inprofile_config["nodes"]
. - Accumulates a “rolling x-position” (
rolling_x_pos
) that simulates the horizontal distance for each link, dependent on link length or a default link length (if it’s a weir, orifice, pump, outlet). - Calls
_add_node_plot(...)
again for the downstream node and_add_link_plot(...)
for the link geometry between them.- Each node gets appended to
profile_config['nodes']
, each link toprofile_config['links']
.
- Each node gets appended to
- Plots the first node if
- After finishing the loop,
_add_ground_plot(...)
is used to draw a dashed line indicating ground elevation.
- For each tuple
-
Return
- A
profile_config
dictionary with:nodes
: A list of dicts containing node IDs, rolling x-positions, invert elevations.links
: A list of dicts with link IDs, midpoints, link type.path_selection
: Echo of the input path for reference.
- A
2. _add_node_plot(ax, x, model, node_name, link_set, ... )
Purpose:
- Draws a rectangular manhole (or node structure) at position
x
on the x-axis, with the correct invert elevation and max depth.
Details:
- Extracts
invert_el
fromnodes.loc[node_name]
. - Determines the node’s depth from model’s input data (
model.inp.junctions
,model.inp.outfalls
,model.inp.storage
), defaulting toMaxDepth
. - Plots a rectangle with corners
[(x−width, invert_el), (x+width, invert_el+depth), ...]
in black lines. - Optionally draws a gradient fill on the sides for a 3D effect.
Returns:
- A dictionary of
{'x': [ul_x, ur_x], 'level': [ul_y, ur_y]}
, used by_add_ground_plot
to incorporate node’s top edge as part of ground level, if needed.
3. _add_link_plot(ax, us_x_position, ds_x_position, model, link_set, ...)
Purpose:
- Draws a link cross-section between the upstream node at
us_x_position
and downstream node atds_x_position
, considering the link type (conduit, weir, orifice, pump, outlet).
Process:
- Determine link type from
links.loc[link_id].Type
. - For CONDUIT:
- Use
links.loc[link_id].Length
(already accounted for in the x offset) plus geometry fields likeGeom1
for diameter/height,InOffset
,OutOffset
for vertical offsets.
- Use
- For ORIFICE, WEIR, PUMP, OUTLET:
- Uses specialized default lengths (like
DEFAULT_WEIR_LENGTH
) or a single crest height for orifices/weirs. - Draw polygons or lines to represent the side profile.
- Uses specialized default lengths (like
- Returns a dict with
{'x': [...], 'bottom': [...], 'link_type': link_type, 'mid_x': [...], 'mid_y': [...]}
, enabling the main function or labeling routines to know how to position text or the HGL line.
4. _add_ground_plot(ax, ground_levels)
Purpose:
- Joins the ground-level points computed from each node or link in a dashed brown line (
'--'
,'brown'
). - The
ground_levels['x']
andground_levels['level']
data are accumulated during node draws inbuild_profile_plot
.
5. add_hgl_plot(ax, profile_config, hgl=None, depth=None, color='b', label="HGL")
Purpose:
- Overlays a line representing the hydraulic grade line (HGL) or water surface.
- Two usage patterns:
hgl
– a dictionary/Series mapping node IDs to HGL elevations, ordepth
– a dictionary/Series mapping node IDs to water depth, which is then added to the node invert.
- The function loops through each node in
profile_config['nodes']
, builds an array of HGL values, and does a singleax.plot(...)
.
Weir Link Special Handling:
- If a link is type “WEIR,” it tries to insert a midpoint to reflect any possible “step” between upstream and downstream side. This ensures the HGL transitions properly if weirs create abrupt changes.
6. add_node_labels_plot(ax, model, profile_config, ...)
and add_link_labels_plot(ax, model, profile_config, ...)
Purpose:
- Adds textual labels for each node or link above/below the structure.
- Each label is anchored with an arrow (
arrowprops=dict(...)
) from the label text down to the structure. - Offers optional stagger so that labels alternate to avoid collisions.
Implementation details:
- For nodes:
- Extract invert + depth = top of node.
- Place an annotation arrow from the node top to a label above the highest node in the plot.
- For links:
- Use the link’s midpoint or bottom to place the arrow.
- Place the text below the entire group if needed (to avoid crowding).
Typical Usage Flow
- Call
build_profile_plot(ax, model, path_selection)
.- Returns
profile_config
with node/link geometry. - Draws the profile lines for manholes, conduits, ground, etc.
- Returns
- Optionally overlay:
add_hgl_plot
to show the water surface profile.add_node_labels_plot
oradd_link_labels_plot
to label items.
- Render or save the figure:
import matplotlib.pyplot as plt fig, ax = plt.subplots() pcfg = build_profile_plot(ax, my_model, my_path) add_hgl_plot(ax, pcfg, hgl=node_water_surface_dict) add_node_labels_plot(ax, my_model, pcfg) add_link_labels_plot(ax, my_model, pcfg) plt.show()
Constants and Defaults
MH_WIDTH
= 10: Horizontal half-width for manholes when drawing a node profile.DEFAULT_ORIFICE_LENGTH
,DEFAULT_PUMP_LENGTH
,DEFAULT_WEIR_LENGTH
,DEFAULT_OUTLET_LENGTH
: The “visual” length used for these special link types if the model doesn’t have a length (or if a simplified approach is desired).
Error Handling
error.InvalidDataTypes
– raised ifadd_hgl_plot(...)
sees neitherhgl
nordepth
in the correct form.- The code also uses
model.inp
references (likemodel.inp.junctions
) to check how to interpret node depth or offset. If data is missing, it might cause an exception or result in an incomplete profile.
Conclusion
This code forms a profile-plot toolkit for SWMM or SWMM-like hydraulic models:
build_profile_plot
systematically places nodes and links horizontally, respecting lengths and offsets.- Node/Link subroutines handle the geometry difference among CONDUIT, WEIR, ORIFICE, PUMP, OUTLET.
- Ground line and HGL lines add topographical and hydraulic context.
- Labeling routines annotate each node/link, making the final plot self-explanatory.
Together, these help engineers or researchers visualize how water flows and see the relative elevations of nodes, the shape/length of links, and changes in water surface (HGL) across a chosen path in the SWMM network.
No comments:
Post a Comment