HY8 is the "offical" implementation of the FWHA culvert calculation.
The model is saved to : ./data/hy8/negative_slope.hy8
The curve data is copy and pasted to this file, TODO UPDATE IT: ./data/hy8/negative_slope_performance_curve.csv
I think HY8 has a bug when I am using meters instead of feet, it doesn't display the outlet curve in its UI shown below.
HECRAS claims that it can handle negatively sloped culvert better than FWHA method.
The file is at: ./data/hecras/negative_slope.prj
The results are copy and pasted into a csv file: ./data/hecras/negative_slope.csv
A swmm5 model is created: ./data/swmm5/adverse_slope.inp
Since it is outlet control, the losses are playing an important role in the headwater calculation.
As shown below, a combination of entrance and exit losses were compared,
They are
I would use en=0.2 and ex=1, since that is the default values for culvert used in the HECRAS model.
import os
import pandas as pd
import matplotlib.pyplot as plt
import sys
lib_path = r'C:\Users\Mel.Meng\Documents\GitHub\SewerAnalysis\source'
if lib_path not in sys.path:
sys.path.append(lib_path)
sys.path
import swmm_tools as st
ws = r'C:\Users\Mel.Meng\Documents\GitHub\SewerAnalysis\references\culvert\data'
# run different combinations of the swmm5 losses
tmp_folder = os.path.join(ws, 'swmm5/template')
tmp_name = 'adverse_slope_loss.inp'
results = {}
for kentry in [0, 0.2, 0.5]:
for kexit in [0.5, 1, 2]:
data = {'kentry': kentry, 'kexit': kexit}
swmm5_inp = os.path.join(ws, 'swmm5/tmp/loss_en%s_ex%s.inp' % (kentry, kexit))
st.render_input(tmp_folder, tmp_name, data, swmm5_inp)
swmm5_out = os.path.join(ws, 'swmm5/tmp/loss_en%s_ex%s.out' % (kentry, kexit))
st.run(swmm5_inp)
results['en=%s ex=%s' % (kentry, kexit)] = st.extract_node(swmm5_out, '1')
... SWMM Version 5.3.0.dev0 ... Run Complete1 ... SWMM Version 5.3.0.dev0 ... Run Complete1 ... SWMM Version 5.3.0.dev0 ... Run Complete1 ... SWMM Version 5.3.0.dev0 ... Run Complete1 ... SWMM Version 5.3.0.dev0 ... Run Complete1 ... SWMM Version 5.3.0.dev0 ... Run Complete1 ... SWMM Version 5.3.0.dev0 ... Run Complete1 ... SWMM Version 5.3.0.dev0 ... Run Complete1 ... SWMM Version 5.3.0.dev0 ... Run Complete1
# plot the results in one chart
hy8_curve_csv = os.path.join(ws, 'hy8/negative_slope_performance_curve.csv')
hec_ras_csv = os.path.join(ws, 'hecras/negative_slope.csv')
swmm5_inp = os.path.join(ws, 'swmm5/adverse_slope.inp')
st.run(swmm5_inp)
swmm5_out = os.path.join(ws, 'swmm5/adverse_slope.out')
df_swmm = st.extract_node(swmm5_out, '1')
swmm5_inp = os.path.join(ws, 'swmm5/adverse_slope_loss.inp')
st.run(swmm5_inp)
swmm5_out = os.path.join(ws, 'swmm5/adverse_slope_loss.out')
df_swmm_loss = st.extract_node(swmm5_out, '1')
df = pd.read_csv(hy8_curve_csv)
df_ras = pd.read_csv(hec_ras_csv)
invert = 63
df_ras['base_depth'] = df_ras['BASE'] - invert
ax = df.plot(x='q', y='inlet', label='Inlet', style='x-', figsize=(10,10))
df.plot(x='q', y='outlet', label='Outlet', style='.-', ax=ax)
df_ras.plot(x='q', y='base_depth', label='hecras', ax=ax)
for k in results:
if k in ['en=0.2 ex=1', 'en=0.5 ex=0.5']:
results[k].plot(x='total_flow', y='depth', style='o-', label=k, ax=ax)
else:
results[k].plot(x='total_flow', y='depth', style='--', label=k, ax=ax)
plt.show()
... SWMM Version 5.3.0.dev0 ... Run Complete1 ... SWMM Version 5.3.0.dev0 ... Run Complete1
Import the xpx file into XPSWMM and run the model. Similarly, XPSWMM is sensitive to the entrance/exit losses.
Model:./data/xpswmm/adverse_slope.zip
Results: ./data/xpswmm/adverse_slope.csv
As shown below,
hy8_curve_csv = os.path.join(ws, 'hy8/negative_slope_performance_curve.csv')
xpswmm_csv = os.path.join(ws, 'xpswmm/adverse_slope.csv')
df = pd.read_csv(hy8_curve_csv)
df_xp = pd.read_csv(xpswmm_csv)
invert = 63
scenarios = ['NOLOSS', 'EN02EX1', 'EN02EX05']
for sc in scenarios:
df_xp[sc] = df_xp[sc] - invert
ax = df.plot(x='q', y='inlet', label='Inlet', style='o-', figsize=(10,10))
df.plot(x='q', y='outlet', label='Outlet', style='o-', ax=ax)
for sc in scenarios:
df_xp.plot(x='q', y=sc, label=sc, style='--', ax=ax)
plt.show()
For this example, HECRAS and HY8 give very similar results using default settings. For SWMM5 and XPSWMM, the entrance/exit losses need to be adjusted to match the HY8 curves.
As shown in the figure below,
ws = r'C:\Users\Mel.Meng\Documents\GitHub\SewerAnalysis\references\culvert\data'
hy8_curve_csv = os.path.join(ws, 'hy8/negative_slope_performance_curve.csv')
hec_ras_csv = os.path.join(ws, 'hecras/negative_slope.csv')
xpswmm_csv = os.path.join(ws, 'xpswmm/adverse_slope.csv')
invert = 63
swmm5_inp = os.path.join(ws, 'swmm5/adverse_slope_en02ex1.inp')
st.run(swmm5_inp)
swmm5_out = os.path.join(ws, 'swmm5/adverse_slope_en02ex1.out')
df_swmm_loss = st.extract_node(swmm5_out, '1')
df = pd.read_csv(hy8_curve_csv)
df_ras = pd.read_csv(hec_ras_csv)
df_xp = pd.read_csv(xpswmm_csv)
df_xp['depth'] = df_xp['EN02EX1'] - invert
df_ras['base_depth'] = df_ras['BASE'] - invert
# ax = df.plot(x='q', y='inlet', label='Inlet', style='x-', figsize=(10,10))
ax = df.plot(x='q', y='outlet', label='Outlet', style='--', figsize=(10,10))
df_ras.plot(x='q', y='base_depth', label='HECRAS', style='x-', ax=ax)
df_xp.plot(x='q', y='depth', label='XPSWMM', style='o-', ax=ax)
df_swmm_loss.plot(x='total_flow', y='depth', style='.-', label='SWMM', ax=ax)
plt.show()
... SWMM Version 5.3.0.dev0 ... Run Complete1