Below is a detailed overview of dynwave.c
, which implements dynamic wave routing for the entire stormwater network in EPA SWMM5. This file orchestrates Picard iterations (successive approximations) on the full system of links (conduits, pumps, orifices, weirs) and nodes at each time step, using the momentum/continuity equations in an explicit manner.
1. Purpose of dynwave.c
dynwave.c
is the top-level solver for dynamic wave routing in SWMM.- It calls or coordinates lower-level routines—
dwflow.c
for conduits and link_ / node_ functions for other links and nodes—to compute:- Flow through each link (momentum eqn.),
- Depth at each node (continuity eqn.),
- Repeats these updates iteratively until convergence or a max iteration limit.
- The dynamic wave engine supports:
- Surcharged nodes (pressurized conditions),
- Preissmann slot or EXTRAN surcharge handling,
- Variable time stepping based on Courant or user criteria,
- Ponding at nodes if allowed.
2. Key Data & Structures
2.1 Global Variables
VariableStep
- Holds the variable time step if
CourantFactor != 0
, otherwise defaults to the userRouteStep
.
- Holds the variable time step if
Xnode[]
(typeTXnode
)- An extended node structure used only by the dynamic wave solver each iteration, containing:
converged
: boolean if the node’s depth is converged,newSurfArea
,oldSurfArea
: surface area for node,sumdqdh
: sum of partial derivatives from adjacent links,dYdT
: estimated rate of depth change.
- An extended node structure used only by the dynamic wave solver each iteration, containing:
Omega
- Under-relaxation factor (0–1) for flow/depth updates in successive approximations. Typically 0.5.
Steps
- The iteration count in the current Picard loop for the time step.
2.2 Local (Static) Routines
getVariableStep(...)
,getLinkStep(...)
,getNodeStep(...)
- Compute a variable (Courant-based) time step each iteration, limited by max user step or a minimum threshold.
findNodeDepths(...)
,setNodeDepth(...)
- Solve for each node’s new depth using the net flows (inflows - outflows) and partial derivatives.
- Enforce surcharging logic if water level goes above the node’s crown or full depth.
findLinkFlows(...)
- Calls
dwflow_findConduitFlow(...)
(indwflow.c
) for conduits or special routines for pumps/orifices/weirs, then updates inflows/outflows at nodes.
- Calls
3. Main Workflow per Time Step
-
dynwave_execute(tStep)
is called from the overall routing loop:- Initialize iteration variables in
initRoutingStep()
, resettingXnode
data. - Start a Picard iteration loop (up to
MaxTrials
times):initNodeStates()
: sets each node’s surface area, inflow/outflow, etc.findLinkFlows(dt)
:- For each link, solve the momentum eqn. or specialized logic (pump, weir, orifice).
- Update node inflow/outflow for each link.
findNodeDepths(dt)
:- Solve continuity eqn. for each node’s new depth.
- Returns TRUE if all node depth changes are under
HeadTol
.
- If converged, break the iteration loop; otherwise continue.
- If not converged after
MaxTrials
, record a non-convergence event (used by the reporting). findLimitedLinks()
checks if any conduits are capacity-limited.
- Initialize iteration variables in
-
Return the number of iterations used.
Hence, dynwave_execute()
is the principal function that executes dynamic wave for one time step for the entire system, returning how many Picard steps it needed.
4. Important Functions in Detail
4.1 dynwave_init()
- Allocates memory for
Xnode[]
. - Initializes each node’s
crownElev
to the invert plus the highest possible conduit top. - Sets
CrownCutoff
for either SLOT or EXTRAN surcharge method.
4.2 dynwave_close()
- Frees the memory allocated for
Xnode[]
.
4.3 dynwave_validate()
- Adjusts
MinRouteStep
,MinSurfArea
,HeadTol
, andMaxTrials
if they aren’t set by the user.
4.4 dynwave_getRoutingStep(fixedStep)
- If
CourantFactor == 0.0
, returns the user’sfixedStep
. - Else calls
getVariableStep(fixedStep)
:getLinkStep(...)
: checks each conduit’s Courant condition.getNodeStep(...)
: also checks node depth stability.- Takes the minimum of these, ensures it’s
MinRouteStep
.
4.5 dynwave_execute(tStep)
(see main workflow above).
4.6 initRoutingStep()
- Resets each link’s
surfArea1
,surfArea2
= 0, node array items, etc. - For each conduit, moves
Conduit[k].a1
->Conduit[k].a2
.
4.7 initNodeStates()
- For each node:
- If
AllowPonding
, get ponded area fromnode_getPondedArea(...)
. - Else get surface area from
node_getSurfArea(...)
. - Set node inflow/outflow from latflow or previous losses.
- If
4.8 findLinkFlows(dt)
- For each link:
- If it’s a conduit and not flagged as bypassed, calls
dwflow_findConduitFlow(...)
. - Else if it’s a pump/orifice/weir/dummy, calls specialized logic (some in
link_*
routines orfindNonConduitFlow()
). - Then calls
updateNodeFlows()
to add link flows to the upstream/outflow for the relevant nodes.
- If it’s a conduit and not flagged as bypassed, calls
4.9 findNodeDepths(dt)
- For each node (except outfalls), calls
setNodeDepth(...)
. setNodeDepth(...)
uses net flow volume to compute new depth. If surcharged (pressure flow), it uses a different approach. If over the top, sets overflow, etc.- Returns TRUE if all changes in depth are under
HeadTol
, or FALSE otherwise.
4.10 Overflow & Ponding
- If node volume tries to exceed
fullVolume
andAllowPonding
isFALSE
, the excess isnode[i].overflow
. Depth is capped atnode[i].fullDepth + surDepth
. - If ponding is
TRUE
, the node can store water beyond fullDepth in a “ponded area.”
5. Surcharge Methods
EXTRAN
vs.SLOT
:- If
SurchargeMethod == EXTRAN
, node surcharging uses the original EXTRAN approach (cutting off flow at crown, building head, etc.). - If
SurchargeMethod == SLOT
, uses a Preissmann slot in each closed conduit, letting depth exceedyFull
while giving more stable pressurized flow modeling.
- If
6. Time Step Calculation
- Link-based Courant:
scaled by the Froude number and
CourantFactor
. - Node-based stability:
- If a node’s depth changes quickly, reduce time step to keep it from jumping more than 25% of the node’s “crown depth” (or something similar).
Combining these ensures a stable unsteady solution: the time step is not so large that water “teleports” across multiple nodes or that node depths jump uncontrollably.
7. Output & Convergence Tracking
- SWMM tracks each node’s “converged” flag after each iteration. If all nodes are converged (depth changes <
HeadTol
), the iteration loop ends. - If not, it increments
Steps
and tries again up toMaxTrials
. - If still not converged, increments
NonConvergeCount
for reporting.
8. Summary
dynwave.c
is the driver for the dynamic wave routing solution in SWMM, implementing a Picard iteration approach for the system of flow equations. It:
- Initializes the nodes and links each time step,
- Finds conduit flows (using
dwflow.c
), - Finds node depths,
- Checks for convergence,
- Adjusts the time step if
CourantFactor
is used.
Through these steps, SWMM can handle a variety of complex hydraulic phenomena (flooding, pressurization, backwater, surcharging, flow reversals) in a stable and iterative manner.
No comments:
Post a Comment