Refer to my notebook for more information on the swmm5 culvert theory.
In this notebook I will use DG 1.3.1 from HDS5 to see which parameters will impact the SWMM5 results.
A SWMM5 model is created to compare the performance curve.
Model: ./data/swmm5/dg131.inp
SWMM5 gives an answer of 7.93 ft for headwater depth, within 10% to HY8 result of 8.61ft.
A few things should be noted,
As shown in the figure below, SWMM5 matches the HY8 results faily well, for most places they are within 10%. I am not too concerned for the area > 250 cfs, for practical purposes, a bigger culvert should be designed to handle that kind of flow.
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import os
ws = r'C:\Users\Mel.Meng\Documents\GitHub\SewerAnalysis\references\culvert\data'
# add the base scenario
swmm_inp = os.path.join(ws, 'swmm5/dg131.inp')
swmm_out = os.path.join(ws, 'swmm5/dg131.out')
run(swmm_inp)
df_swmm5 = extract_node(swmm_out, node_name='4')
f = os.path.join(ws, "hy8/dg131_performance_curve.csv")
df = pd.read_csv(f)
fig = go.Figure()
fig.add_trace(go.Scatter(x=df_swmm5["q"], y=df_swmm5["swmm5"]*0.9, name='-10% SWMM5', line=dict(color='grey', dash='dot')))
fig.add_trace(go.Scatter(x=df_swmm5["q"], y=df_swmm5["swmm5"]*1.1, name='+10% SWMM5', fill='tonexty',fillcolor='rgba(66, 173, 245, 0.1)',line=dict(color='grey', dash='dot') ))
fig.add_trace(go.Scatter(x=df_swmm5["q"], y=df_swmm5["swmm5"], name='SWMM5', mode='lines+markers',
line=dict(color='firebrick', width=4)))
fig.add_trace(go.Scatter(x=df["q"], y=df["inlet"], name='Inlet'))
fig.add_trace(go.Scatter(x=df["q"], y=df["outlet"], name='Outlet'))
fig.update_layout(title='Culvert Performance Curve', xaxis_title="Dicharge (cfs)", yaxis_title="Headwater (ft)",)
fig.show()
... SWMM Version 5.3.0.dev0 ... Run Complete4
SWMM5 uses a unsteady state simulation, so the upstream/downstream condition can play more important role since it can introduce stability issues. Also I don't quite understand how the outlet control situation is handled since SWMM5 doesn't use FWHA equations at all.
e02x0 means entrance=0.2, exit=0, and ex0x1 means entrance=0, exit=0.2, so we are comparing the following entrance/exit loss factors,
You need to update the path to each file in the code block below. Run the code blocks at the end of this notebook before this one.
import os
ws = r"C:\Users\Mel.Meng\Documents\GitHub\SewerAnalysis\references\culvert\data"
results = {}
scenarios = ['e02x0', 'e05x0', 'e1x0', 'e0x05', 'e0x1', 'e0x2', 'e02x1']
# scenarios = ['loss1', 'loss2', 'loss3']
for sc in scenarios:
swmm_inp = os.path.join(ws, 'swmm5/dg131_%s.inp' % sc)
swmm_out = os.path.join(ws, 'swmm5/dg131_%s.out' % sc)
run(swmm_inp)
results[sc] = extract_node(swmm_out, node_name='4')
print(sc)
print(results[sc])
# add the base scenario
swmm_inp = os.path.join(ws, 'swmm5/dg131.inp')
swmm_out = os.path.join(ws, 'swmm5/dg131.out')
run(swmm_inp)
results['base'] = extract_node(swmm_out, node_name='4')
plot_results(results, scenarios)
... SWMM Version 5.3.0.dev0 ... Run Complete4 e02x0 swmm5 q 2020-05-28 00:00:00 12.853357 287.562897 2020-05-28 00:15:00 12.041612 275.064728 2020-05-28 00:30:00 11.265922 262.566406 2020-05-28 00:45:00 10.526278 250.067749 2020-05-28 01:00:00 9.822718 237.569382 2020-05-28 01:15:00 9.154978 225.069427 2020-05-28 01:30:00 8.523647 212.569427 2020-05-28 01:45:00 7.928207 200.069427 2020-05-28 02:00:00 7.368853 187.569427 2020-05-28 02:15:00 6.845573 175.069427 2020-05-28 02:30:00 6.358367 162.569427 2020-05-28 02:45:00 5.907237 150.069427 2020-05-28 03:00:00 5.492122 137.569427 2020-05-28 03:15:00 5.106722 125.069427 2020-05-28 03:30:00 4.722830 112.569427 2020-05-28 03:45:00 4.342566 100.069427 2020-05-28 04:00:00 3.967034 87.569427 2020-05-28 04:15:00 3.599984 75.069427 2020-05-28 04:30:00 3.237018 62.569431 2020-05-28 04:45:00 2.842197 50.069431 2020-05-28 05:00:00 2.417089 37.569431 2020-05-28 05:15:00 1.881210 25.069431 2020-05-28 05:30:00 1.453305 12.569430 2020-05-28 05:45:00 1.496687 0.015722 ... SWMM Version 5.3.0.dev0 ... Run Complete4 e05x0 swmm5 q 2020-05-28 00:00:00 12.853356 287.562897 2020-05-28 00:15:00 12.041612 275.064728 2020-05-28 00:30:00 11.265921 262.566376 2020-05-28 00:45:00 10.526275 250.067688 2020-05-28 01:00:00 9.822720 237.569427 2020-05-28 01:15:00 9.154427 225.069427 2020-05-28 01:30:00 8.523648 212.569427 2020-05-28 01:45:00 7.928207 200.069427 2020-05-28 02:00:00 7.368853 187.569427 2020-05-28 02:15:00 6.845573 175.069427 2020-05-28 02:30:00 6.358367 162.569427 2020-05-28 02:45:00 5.907237 150.069427 2020-05-28 03:00:00 5.491825 137.569427 2020-05-28 03:15:00 5.106688 125.069427 2020-05-28 03:30:00 4.723106 112.569427 2020-05-28 03:45:00 4.342567 100.069427 2020-05-28 04:00:00 3.967029 87.569427 2020-05-28 04:15:00 3.599972 75.069427 2020-05-28 04:30:00 3.237005 62.569431 2020-05-28 04:45:00 2.842184 50.069431 2020-05-28 05:00:00 2.417078 37.569431 2020-05-28 05:15:00 1.884455 25.069431 2020-05-28 05:30:00 1.488798 12.569430 2020-05-28 05:45:00 1.505859 0.010472 ... SWMM Version 5.3.0.dev0 ... Run Complete4 e1x0 swmm5 q 2020-05-28 00:00:00 12.853357 287.562897 2020-05-28 00:15:00 12.041612 275.064728 2020-05-28 00:30:00 11.265922 262.566406 2020-05-28 00:45:00 10.526274 250.067673 2020-05-28 01:00:00 9.822720 237.569427 2020-05-28 01:15:00 9.154517 225.069427 2020-05-28 01:30:00 8.523637 212.569427 2020-05-28 01:45:00 7.928207 200.069427 2020-05-28 02:00:00 7.368853 187.569427 2020-05-28 02:15:00 6.845573 175.069427 2020-05-28 02:30:00 6.358367 162.569427 2020-05-28 02:45:00 5.907237 150.069427 2020-05-28 03:00:00 5.491818 137.569427 2020-05-28 03:15:00 5.106687 125.069427 2020-05-28 03:30:00 4.723111 112.569427 2020-05-28 03:45:00 4.342567 100.069427 2020-05-28 04:00:00 3.967028 87.569427 2020-05-28 04:15:00 3.599972 75.069427 2020-05-28 04:30:00 3.237006 62.569431 2020-05-28 04:45:00 2.842187 50.069431 2020-05-28 05:00:00 2.417080 37.569431 2020-05-28 05:15:00 1.891198 25.069431 2020-05-28 05:30:00 1.519655 12.569430 2020-05-28 05:45:00 1.501804 0.009236 ... SWMM Version 5.3.0.dev0 ... Run Complete4 e0x05 swmm5 q 2020-05-28 00:00:00 12.853357 287.562897 2020-05-28 00:15:00 12.041612 275.064728 2020-05-28 00:30:00 11.265922 262.566406 2020-05-28 00:45:00 10.526276 250.067703 2020-05-28 01:00:00 9.822720 237.569427 2020-05-28 01:15:00 9.154510 225.069427 2020-05-28 01:30:00 8.523647 212.569427 2020-05-28 01:45:00 7.928207 200.069427 2020-05-28 02:00:00 7.368853 187.569427 2020-05-28 02:15:00 6.845573 175.069427 2020-05-28 02:30:00 6.358367 162.569427 2020-05-28 02:45:00 5.907237 150.069427 2020-05-28 03:00:00 5.491687 137.569427 2020-05-28 03:15:00 5.106721 125.069427 2020-05-28 03:30:00 4.723084 112.569427 2020-05-28 03:45:00 4.342587 100.069427 2020-05-28 04:00:00 3.967037 87.569427 2020-05-28 04:15:00 3.599980 75.069427 2020-05-28 04:30:00 3.237008 62.569431 2020-05-28 04:45:00 2.842186 50.069431 2020-05-28 05:00:00 2.417083 37.569431 2020-05-28 05:15:00 1.881540 25.069431 2020-05-28 05:30:00 1.475575 12.569430 2020-05-28 05:45:00 1.516206 0.017208 ... SWMM Version 5.3.0.dev0 ... Run Complete4 e0x1 swmm5 q 2020-05-28 00:00:00 12.853357 287.562897 2020-05-28 00:15:00 12.041612 275.064728 2020-05-28 00:30:00 11.265922 262.566406 2020-05-28 00:45:00 10.526276 250.067703 2020-05-28 01:00:00 9.822720 237.569427 2020-05-28 01:15:00 9.154510 225.069427 2020-05-28 01:30:00 8.523647 212.569427 2020-05-28 01:45:00 7.928207 200.069427 2020-05-28 02:00:00 7.368853 187.569427 2020-05-28 02:15:00 6.845573 175.069427 2020-05-28 02:30:00 6.358367 162.569427 2020-05-28 02:45:00 5.907237 150.069427 2020-05-28 03:00:00 5.491687 137.569427 2020-05-28 03:15:00 5.106721 125.069427 2020-05-28 03:30:00 4.723084 112.569427 2020-05-28 03:45:00 4.342587 100.069427 2020-05-28 04:00:00 3.967037 87.569427 2020-05-28 04:15:00 3.599980 75.069427 2020-05-28 04:30:00 3.237008 62.569431 2020-05-28 04:45:00 2.842186 50.069431 2020-05-28 05:00:00 2.417083 37.569431 2020-05-28 05:15:00 1.881540 25.069431 2020-05-28 05:30:00 1.475575 12.569430 2020-05-28 05:45:00 1.516206 0.017208 ... SWMM Version 5.3.0.dev0 ... Run Complete4 e0x2 swmm5 q 2020-05-28 00:00:00 19.277079 287.562988 2020-05-28 00:15:00 17.741648 275.064667 2020-05-28 00:30:00 16.289640 262.566437 2020-05-28 00:45:00 14.911016 250.068283 2020-05-28 01:00:00 13.601906 237.569427 2020-05-28 01:15:00 12.364367 225.069427 2020-05-28 01:30:00 11.193624 212.569427 2020-05-28 01:45:00 10.084257 200.069427 2020-05-28 02:00:00 9.096618 187.569427 2020-05-28 02:15:00 8.224137 175.069427 2020-05-28 02:30:00 7.397915 162.569427 2020-05-28 02:45:00 6.602960 150.069427 2020-05-28 03:00:00 5.854236 137.569427 2020-05-28 03:15:00 5.154073 125.069427 2020-05-28 03:30:00 4.722998 112.569427 2020-05-28 03:45:00 4.342470 100.069427 2020-05-28 04:00:00 3.967005 87.569427 2020-05-28 04:15:00 3.599960 75.069427 2020-05-28 04:30:00 3.237006 62.569431 2020-05-28 04:45:00 2.842195 50.069431 2020-05-28 05:00:00 2.417094 37.569431 2020-05-28 05:15:00 1.891177 25.069431 2020-05-28 05:30:00 1.527910 12.569430 2020-05-28 05:45:00 1.493522 0.068153 ... SWMM Version 5.3.0.dev0 ... Run Complete4 e02x1 swmm5 q 2020-05-28 00:00:00 12.853357 287.562897 2020-05-28 00:15:00 12.041611 275.064697 2020-05-28 00:30:00 11.265923 262.566406 2020-05-28 00:45:00 10.526279 250.067764 2020-05-28 01:00:00 9.822720 237.569427 2020-05-28 01:15:00 9.154560 225.069427 2020-05-28 01:30:00 8.523515 212.569427 2020-05-28 01:45:00 7.928207 200.069427 2020-05-28 02:00:00 7.368853 187.569427 2020-05-28 02:15:00 6.845573 175.069427 2020-05-28 02:30:00 6.358367 162.569427 2020-05-28 02:45:00 5.907237 150.069427 2020-05-28 03:00:00 5.491747 137.569427 2020-05-28 03:15:00 5.106671 125.069427 2020-05-28 03:30:00 4.723064 112.569427 2020-05-28 03:45:00 4.342622 100.069427 2020-05-28 04:00:00 3.967034 87.569427 2020-05-28 04:15:00 3.599982 75.069427 2020-05-28 04:30:00 3.237015 62.569431 2020-05-28 04:45:00 2.842191 50.069431 2020-05-28 05:00:00 2.417081 37.569431 2020-05-28 05:15:00 1.888615 25.069431 2020-05-28 05:30:00 1.483350 12.569430 2020-05-28 05:45:00 1.504546 0.055903 ... SWMM Version 5.3.0.dev0 ... Run Complete4
FigureWidget({ 'data': [{'name': 'base', 'type': 'scatter', 'uid': '39d3e0ac-0…
It looks that only when exit loss = 2 will push the curve upward significantly, all other settings seems to produce the same results. However, an exit loss of 2 is too high for most applications.
Since we already know most of the time it is inlet control, it confirmed my understanding for inlet control culvert, the losses are not playing an important role in deciding the headwater.
Since the headwater is calculated as the water depth of the inlet node of the culvert, I would like to see what will impact its depth.
storage1k and storage10k are two scenarios with different storage size.
import os
ws = r"C:\Users\Mel.Meng\Documents\GitHub\SewerAnalysis\references\culvert\data"
results = {}
scenarios = ['storage1k', 'storage10k']
# scenarios = ['loss1', 'loss2', 'loss3']
for sc in scenarios:
swmm_inp = os.path.join(ws, 'swmm5/dg131_%s.inp' % sc)
swmm_out = os.path.join(ws, 'swmm5/dg131_%s.out' % sc)
run(swmm_inp)
results[sc] = extract_node(swmm_out, node_name='4')
print(sc)
print(results[sc])
# add the base scenario
swmm_inp = os.path.join(ws, 'swmm5/dg131.inp')
swmm_out = os.path.join(ws, 'swmm5/dg131.out')
run(swmm_inp)
results['base'] = extract_node(swmm_out, node_name='4')
plot_results(results, scenarios)
... SWMM Version 5.3.0.dev0 ... Run Complete4 storage1k swmm5 q 2020-05-28 00:00:00 12.967530 287.562653 2020-05-28 00:15:00 12.166387 275.064423 2020-05-28 00:30:00 11.379475 262.566162 2020-05-28 00:45:00 10.629086 250.067520 2020-05-28 01:00:00 9.915277 237.569138 2020-05-28 01:15:00 9.238091 225.069427 2020-05-28 01:30:00 8.597565 212.569427 2020-05-28 01:45:00 7.993590 200.069427 2020-05-28 02:00:00 7.426223 187.569427 2020-05-28 02:15:00 6.895414 175.069427 2020-05-28 02:30:00 6.401205 162.569427 2020-05-28 02:45:00 5.943610 150.069427 2020-05-28 03:00:00 5.522667 137.569427 2020-05-28 03:15:00 5.134791 125.069427 2020-05-28 03:30:00 4.751618 112.569427 2020-05-28 03:45:00 4.368518 100.069427 2020-05-28 04:00:00 3.982565 87.569427 2020-05-28 04:15:00 3.618818 75.069427 2020-05-28 04:30:00 3.263344 62.569431 2020-05-28 04:45:00 2.871217 50.069431 2020-05-28 05:00:00 2.439167 37.569431 2020-05-28 05:15:00 1.975241 25.069431 2020-05-28 05:30:00 1.456903 12.569430 2020-05-28 05:45:00 1.475245 0.015111 ... SWMM Version 5.3.0.dev0 ... Run Complete4 storage10k swmm5 q 2020-05-28 00:00:00 12.967530 287.562653 2020-05-28 00:15:00 12.166387 275.064423 2020-05-28 00:30:00 11.379475 262.566162 2020-05-28 00:45:00 10.629086 250.067520 2020-05-28 01:00:00 9.915277 237.569138 2020-05-28 01:15:00 9.238091 225.069427 2020-05-28 01:30:00 8.597565 212.569427 2020-05-28 01:45:00 7.993590 200.069427 2020-05-28 02:00:00 7.426223 187.569427 2020-05-28 02:15:00 6.895414 175.069427 2020-05-28 02:30:00 6.401205 162.569427 2020-05-28 02:45:00 5.943610 150.069427 2020-05-28 03:00:00 5.522667 137.569427 2020-05-28 03:15:00 5.134791 125.069427 2020-05-28 03:30:00 4.751618 112.569427 2020-05-28 03:45:00 4.368518 100.069427 2020-05-28 04:00:00 3.982565 87.569427 2020-05-28 04:15:00 3.618818 75.069427 2020-05-28 04:30:00 3.263344 62.569431 2020-05-28 04:45:00 2.871217 50.069431 2020-05-28 05:00:00 2.439167 37.569431 2020-05-28 05:15:00 1.975241 25.069431 2020-05-28 05:30:00 1.456903 12.569430 2020-05-28 05:45:00 1.475245 0.015111 ... SWMM Version 5.3.0.dev0 ... Run Complete4
FigureWidget({ 'data': [{'name': 'base', 'type': 'scatter', 'uid': '25c499ea-6…
Looks like storage has very little impact on the results, SWMM5 is able to use the culvert calculation to set the head at the storage node.
Instead of loading directly at the culvert inlet (4), I loaded flow at a box channel at node 5, I adjusted the width of the inlet channel to see if it will make any differences.
channel10 is 10ft wide box, and channel200 is 200ft wide box.
import os
ws = r"C:\Users\Mel.Meng\Documents\GitHub\SewerAnalysis\references\culvert\data"
results = {}
scenarios = ['channel10', 'channel50', 'channel200']
# scenarios = ['loss1', 'loss2', 'loss3']
for sc in scenarios:
swmm_inp = os.path.join(ws, 'swmm5/dg131_%s.inp' % sc)
swmm_out = os.path.join(ws, 'swmm5/dg131_%s.out' % sc)
run(swmm_inp)
results[sc] = extract_node(swmm_out, node_name='4')
print(sc)
print(results[sc])
# add the base scenario
swmm_inp = os.path.join(ws, 'swmm5/dg131.inp')
swmm_out = os.path.join(ws, 'swmm5/dg131.out')
run(swmm_inp)
results['base'] = extract_node(swmm_out, node_name='4')
plot_results(results, scenarios)
... SWMM Version 5.3.0.dev0 ... Run Complete4 channel10 swmm5 q 2020-05-28 00:00:00 11.535628 266.977112 2020-05-28 00:15:00 11.535628 266.977112 2020-05-28 00:30:00 11.266804 262.590790 2020-05-28 00:45:00 10.526217 250.092560 2020-05-28 01:00:00 9.822950 237.593582 2020-05-28 01:15:00 9.155277 225.095398 2020-05-28 01:30:00 8.523691 212.594193 2020-05-28 01:45:00 7.928186 200.092957 2020-05-28 02:00:00 7.369232 187.595673 2020-05-28 02:15:00 6.845858 175.094193 2020-05-28 02:30:00 6.358565 162.592667 2020-05-28 02:45:00 5.907356 150.091095 2020-05-28 03:00:00 5.492721 137.589355 2020-05-28 03:15:00 5.114943 125.293953 2020-05-28 03:30:00 4.735682 112.784294 2020-05-28 03:45:00 4.374789 100.278885 2020-05-28 04:00:00 3.985945 87.755775 2020-05-28 04:15:00 3.622932 75.258575 2020-05-28 04:30:00 3.269477 62.769089 2020-05-28 04:45:00 2.876002 50.210346 2020-05-28 05:00:00 2.445149 37.726799 2020-05-28 05:15:00 1.980284 25.253378 2020-05-28 05:30:00 1.498037 12.809066 2020-05-28 05:45:00 1.488438 5.610490 ... SWMM Version 5.3.0.dev0 ... Run Complete4 channel50 swmm5 q 2020-05-28 00:00:00 12.858349 287.625031 2020-05-28 00:15:00 12.046683 275.131165 2020-05-28 00:30:00 11.270866 262.634644 2020-05-28 00:45:00 10.530994 250.136642 2020-05-28 01:00:00 9.827081 237.637009 2020-05-28 01:15:00 9.159005 225.133652 2020-05-28 01:30:00 8.647728 215.079422 2020-05-28 01:45:00 8.041781 202.493576 2020-05-28 02:00:00 7.419215 188.728119 2020-05-28 02:15:00 6.879539 175.912506 2020-05-28 02:30:00 6.384958 163.283783 2020-05-28 02:45:00 5.929777 150.727386 2020-05-28 03:00:00 5.498808 137.740707 2020-05-28 03:15:00 5.118883 125.249420 2020-05-28 03:30:00 4.752882 112.757286 2020-05-28 03:45:00 4.441974 100.265930 2020-05-28 04:00:00 4.078932 87.775826 2020-05-28 04:15:00 3.714163 75.290047 2020-05-28 04:30:00 3.360462 62.806305 2020-05-28 04:45:00 2.989280 50.328773 2020-05-28 05:00:00 2.575306 37.860649 2020-05-28 05:15:00 2.126410 25.411537 2020-05-28 05:30:00 1.503148 13.015451 2020-05-28 05:45:00 1.527797 1.076657 ... SWMM Version 5.3.0.dev0 ... Run Complete4 channel200 swmm5 q 2020-05-28 00:00:00 12.858349 287.625031 2020-05-28 00:15:00 12.046683 275.131165 2020-05-28 00:30:00 11.270866 262.634644 2020-05-28 00:45:00 10.530994 250.136642 2020-05-28 01:00:00 9.827081 237.637009 2020-05-28 01:15:00 9.159005 225.133652 2020-05-28 01:30:00 8.647728 215.079422 2020-05-28 01:45:00 8.041781 202.493576 2020-05-28 02:00:00 7.419215 188.728119 2020-05-28 02:15:00 6.879539 175.912506 2020-05-28 02:30:00 6.384958 163.283783 2020-05-28 02:45:00 5.929777 150.727386 2020-05-28 03:00:00 5.498808 137.740707 2020-05-28 03:15:00 5.118883 125.249420 2020-05-28 03:30:00 4.752882 112.757286 2020-05-28 03:45:00 4.441974 100.265930 2020-05-28 04:00:00 4.078932 87.775826 2020-05-28 04:15:00 3.714163 75.290047 2020-05-28 04:30:00 3.360462 62.806305 2020-05-28 04:45:00 2.989280 50.328773 2020-05-28 05:00:00 2.575306 37.860649 2020-05-28 05:15:00 2.126410 25.411537 2020-05-28 05:30:00 1.503148 13.015451 2020-05-28 05:45:00 1.527797 1.076657 ... SWMM Version 5.3.0.dev0 ... Run Complete4
FigureWidget({ 'data': [{'name': 'base', 'type': 'scatter', 'uid': '919dd66a-4…
For different channel widths, they produce very similar results as the base scenario. At low flow region channel200 and channel50 produced slightly higher headwater. And I think that is most likely a result of unsteady state simulation, for bigger channels at low flow conditions, it takes some time to reach steady state level. When I run a constant flow, the level is much closer to the base scenario.
As shown in this post, it is not that hard to conduct sensitivity analysis. I think the important lesson from this exercise is that rather than focus on finding general statements such as "SWMM5 can accurately model culvert using FHWA HDS5 methods or not.", just do some sensitivity analysis, I don't think anyone who wrote the software should be responsible for my modeling results. For the kind of complex system we are modeling everyday, nobody can promise everything will work as intended. So let's set out how things should be, test it and work with the issues!
from swmm.output import output as smo
import pandas as pd
import datetime
from pyswmm import Simulation, Subcatchments
import matplotlib.pyplot as plt
def run(inp_path):
sim = Simulation(inp_path)
sim.execute()
def swmm_dt(days):
# convert swmm dates number to date
# https://www.openswmm.org/Topic/4343/output-file-start-date-and-time-of-the-simulation
t0 = pd.to_datetime('12/31/1899 00:00')
t1 = t0 + datetime.timedelta(days=(days-1)) # I don't understand why I need to -1, hey it works.
return t1
def extract_node(out_path, node_name):
# extract the rainfall results from *.out file
handle = smo.init()
smo.open(handle, out_path)
node_index = 0
while True:
if smo.getelementname(handle, smo.ElementType.NODE, node_index) == node_name:
break
node_index += 1
# swmm out file report time using its only integer format, it needs to be converted to datetime
report_start_date_time = smo.getstartdate(handle)
start_dt = swmm_dt(report_start_date_time)
# to build the timestamps, we'll need the number of reported steps, and the step length in seconds
num_steps = smo.gettimes(handle, smo.Time.NUM_PERIODS)
report_step = smo.gettimes(handle, smo.Time.REPORT_STEP)
# build the date range
timestep = pd.date_range(start=start_dt, periods=num_steps, freq='%smin' % (report_step/60.0))
# Just want to confirm the subcatchments index
print(smo.getelementname(handle, smo.ElementType.NODE, node_index))
# get the time sereis from the out file
depth = smo.getnodeseries(handle, node_index, smo.NodeAttribute.INVERT_DEPTH, 0, num_steps)
q = smo.getnodeseries(handle, node_index, smo.NodeAttribute.TOTAL_INFLOW, 0, num_steps)
df = pd.DataFrame({'swmm5': depth, 'q': q}, index=timestep)
return df
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
def compare_performance_curve(hy8_curve_csv, swmm5_out, xpswmm_csv, node_name):
df = pd.read_csv(hy8_curve_csv)
df_swmm = extract_node(swmm5_out, node_name)
df_xp = pd.read_csv(xpswmm_csv)
ax = df.plot(x='q', y='inlet', label='Inlet', style='x-', figsize=(10,10))
ax = df.plot(x='q', y='outlet', label='Outlet', style='.-', ax=ax)
ax = df_swmm.plot(x='q', y='swmm5', label='SWMM5', style='o-', ax=ax)
ax.fill_between(df_swmm['q'], df_swmm['swmm5']*0.9, df_swmm['swmm5']*1.1, alpha=0.2)
ax = df_xp.plot(x='q', y='xpswmm', label='XPSWMM', style='o-', ax=ax)
plt.xlabel('Discharge(cfs)')
plt.ylabel('Headwater(ft)')
plt.title('SWMM5 culvert vs HY8')
plt.grid(True)
plt.show()
import plotly.graph_objects as go
def plot_results(results, scenarios):
fig = go.FigureWidget()
for sc in ['base'] + scenarios:
df = results[sc]
if sc == 'e02x1':
fig.add_trace(go.Scatter(
x=df['q'], y=df['swmm5'],
name = sc,
line=dict(color='light blue', width=4, dash='dot')
))
else:
fig.add_trace(go.Scatter(
x=df['q'], y=df['swmm5'],
name = sc
))
return fig