Model editing (deletion + type conversion)#
Note
Engine: OpenSWMM 6 — refactored. Documents
openswmm.engine.ModelEditor. This is unique to the v6
engine — there is no SWMM 5 equivalent.
The ModelEditor mutates an already-parsed model in place:
delete objects, convert object types, and analyse the cascading
impact those operations would have on the rest of the network.
Use it for:
Cleaning up auto-generated networks (drop orphan nodes, dangling conduits).
Converting nodes between types (junction → storage, junction → outfall).
Pre-flighting a destructive change (“show me what would break if I delete this conduit”).
Reference: openswmm_edit.h.
Class signature#
class ModelEditor:
def __init__(self, engine: object) -> None: ...
engine— pass the liveSolver(or its underlying engine handle).
The editor must be applied to a Solver in the OPENED state, so
that the model is parsed and addressable but routing has not yet
started.
Helper return types#
ImpactEntry— one row in the report of “what this change would affect”: kind, id, description.ConversionResult— outcome of a type conversion: success, warnings, fields that had to be defaulted.
Both are plain data classes with __repr__ so they display well
during interactive exploration.
Key methods#
Counts (read-only properties — no parentheses)#
Property |
Returns |
|---|---|
|
Number of objects of each kind currently in the model. Access
as attributes — e.g. |
Time control (typed datetime properties)#
Property |
Value |
|---|---|
|
Simulation start as |
|
Simulation end as |
|
Report start as |
Impact analysis (read-only — no mutation)#
Method |
Returns |
|---|---|
|
List of |
|
Same, for a link. |
|
Same, for a subcatchment. |
|
Same, for a rain gage. |
|
Same, for a table / curve. |
|
Same, for a transect. |
Deletion#
Method |
Returns |
|---|---|
|
List of |
|
Same, for a link. |
|
Same, for a subcatchment. |
|
Same, for a rain gage. |
|
Same, for a table / curve. |
|
Same, for a transect. |
Type conversion#
Method |
Returns |
|---|---|
|
|
|
Same, for a link. |
End-to-end example#
from openswmm.engine import Solver, ModelEditor, NodeType
s = Solver("model.inp", "edited.rpt", "edited.out")
s.create()
s.open() # state == OPENED
editor = ModelEditor(s)
print(f"before: {editor.node_count} nodes, {editor.link_count} links")
# Pre-flight: what would happen if we deleted node X?
impacts = editor.analyze_node_impact("X")
for entry in impacts:
print(f" would affect {entry}")
# Actually delete:
actual = editor.delete_node("X")
print(f"deleted {len(actual)} dependent items")
# Convert J5 from a junction to a storage node:
result = editor.convert_node("J5", NodeType.STORAGE)
print("conversion:", result)
from openswmm.engine import EngineState
s.initialize()
s.start()
while s.state == EngineState.RUNNING:
if s.step() != 0:
break
s.end()
s.report()
s.close()
s.destroy()
Common recipes#
Pre-flight a deletion before committing#
impacts = editor.analyze_node_impact("STORM_INLET_42")
if any(e.kind == "outlet" for e in impacts):
print("Refusing to delete — node is the outlet for a subcatchment")
else:
editor.delete_node("STORM_INLET_42")
Bulk-delete every dangling node#
from openswmm.engine import Nodes, Links
nodes = Nodes(s)
links = Links(s)
referenced = set()
for i in range(links.count()):
referenced.add(links.get_from_node(i))
referenced.add(links.get_to_node(i))
dangling = [
nodes.get_id(i) for i in range(nodes.count())
if i not in referenced
]
for nid in dangling:
editor.delete_node(nid)
print(f"deleted {len(dangling)} dangling nodes")
Convert a junction to a storage node#
from openswmm.engine import NodeType
result = editor.convert_node("J5", NodeType.STORAGE)
if result.warnings:
print("warnings:", result.warnings)
# Storage parameters default to placeholder values — set them now:
nodes = Nodes(s)
nodes.set_storage_functional("J5", a=10.0, b=0.0, c=0.0)
Save the edited model#
# ModelEditor mutates the in-memory model; the on-disk .inp is
# unchanged. Persist via Solver.model_write:
s.model_write("model_edited.inp")
EngineState requirements & exceptions#
Method group |
Required state |
Notes |
|---|---|---|
all editor methods |
solver in |
The editor refuses to mutate a running solver. |
|
any state |
Read-only; safe to call at any time. |
Common EngineError codes:
NOT_FOUND— object id not in the model.INVALID_INDEX— integer index out of range.INVALID_TYPE—convert_node()to / from an unsupported combination (e.g. converting a divider to an outfall when the topology forbids it).
See also#
Programmatic model construction — build a model from scratch.
Running a simulation — Solver —
Solver.model_write()to persist your edits back to.inp.Nodes, Links — populate the new objects’ parameters after conversion.