Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates to support read/write of additional INP/RPT sections #219

Merged
merged 12 commits into from
Apr 21, 2024
Merged
98 changes: 97 additions & 1 deletion swmmio/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,8 @@ def __init__(self, file_path):
self._streets_df = None
self._inlets_df = None
self._inlet_usage_df = None
self._patterns_df = None
self._controls_df = None

SWMMIOFile.__init__(self, file_path) # run the superclass init

Expand Down Expand Up @@ -644,6 +646,8 @@ def __init__(self, file_path):
'[STREETS]',
'[INLETS]',
'[INLET_USAGE]',
'[PATTERNS]',
'[CONTROLS]',
]

def save(self, target_path=None):
Expand Down Expand Up @@ -1452,7 +1456,7 @@ def inflows(self):
if self._inflows_df is not None:
return self._inflows_df
inf = dataframe_from_inp(self.path, 'INFLOWS', quote_replace='_!!!!_')
self._inflows_df = inf.replace('_!!!!_', np.nan)
self._inflows_df = inf.replace('_!!!!_', '""') # revert quote replace
return self._inflows_df

@inflows.setter
Expand Down Expand Up @@ -1508,6 +1512,98 @@ def timeseries(self, df):
"""Set inp.timeseries DataFrame."""
self._timeseries_df = df

@property
def patterns(self):
"""
Get/set patterns section of the model

:return: dataframe of patterns

>>> from swmmio.examples import pump_control
>>> # NOTE, only the first 5 columns are shown in the following example
>>> pump_control.inp.patterns.iloc[:,0:5] #doctest: +NORMALIZE_WHITESPACE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love this - thanks for following our documentation pattern.

Type Factor1 Factor2 Factor3 Factor4
Name
DWF HOURLY 0.0151 0.01373 0.01812 0.01098
"""

if self._patterns_df is not None:
return self._patterns_df
self._patterns_df = dataframe_from_inp(self.path, '[PATTERNS]')

if self._patterns_df.shape[0] > 0:
# reformat, 1 row per pattern
pattern_entry_list = []
for name, pattern in self._patterns_df.groupby('Name'):
pattern_entry = {}
pattern_entry['Name'] = name
pattern_entry['Type'] = pattern['Type'].iloc[0]
if pattern.shape[0] > 1:
# shift pattern values to the right
pattern.iloc[1::, 1::] = pattern.iloc[1::, 0:-1].values
pattern['Factors'] = pattern['Factors'].astype(float)
values = pattern.iloc[:, 1:].values.flatten()
for i in range(len(values)):
pattern_entry['Factor'+str(i+1)] = values[i]
pattern_entry_list.append(pattern_entry)

self._patterns_df = pd.DataFrame(pattern_entry_list)
self._patterns_df.set_index('Name', inplace=True)

return self._patterns_df

@patterns.setter
def patterns(self, df):
"""Set inp.patterns DataFrame."""
self._patterns_df = df

@property
def controls(self):
"""
Get/set controls section of the model

:return: dataframe of controls

>>> from swmmio.examples import pump_control
>>> pump_control.inp.controls #doctest: +NORMALIZE_WHITESPACE
Control
Name
RULE PUMP1A IF NODE SU1 DEPTH >= 4 THEN PUMP PUMP1 status = ON PRIORITY 1
RULE PUMP1B IF NODE SU1 DEPTH < 1 THEN PUMP PUMP1 status = OFF PRIORITY 1
"""

if self._controls_df is None:
self._controls_df = dataframe_from_inp(self.path, "[CONTROLS]")

if self._controls_df.shape[0] > 0:
# reformat, 1 row per control
control_entry_list = []
control_entry = {}
controls = self._controls_df['[CONTROLS]']
# make sure the first entry starts with RULE
assert controls[0][0:5] == "RULE "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would best to raise an exception here if this assertion fails. But I'm fine with capturing that in a future PR.

for row in controls:
if row[0:5] == 'RULE ': # new control
if len(control_entry) > 0: # add control to the list
control_entry_list.append(control_entry)
control_entry = {}
control_entry['Name'] = row.rstrip() # remove white space
control_entry['Control'] = ''
else:
control_entry['Control'] = control_entry['Control'] + row + ' '
if len(control_entry) > 0: # add last control to the list
control_entry_list.append(control_entry)

self._controls_df = pd.DataFrame(control_entry_list)
self._controls_df.set_index('Name', inplace=True)

return self._controls_df

@controls.setter
def controls(self, df):
"""Set inp.controls DataFrame."""
self._controls_df = df

@property
def tags(self):
"""
Expand Down
4 changes: 2 additions & 2 deletions swmmio/defs/inp_sections.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ inp_file_objects:
STREETS: [Name, Tcrown, Hcurb, Sx, nRoad, a, W, Sides, Tback, Sback, nBack]
INLETS: [Name, Type, Param1, Param2, Param3, Param4, Param5]
INLET_USAGE: [Link, Inlet, Node, Number, "%Clogged", Qmax, aLocal, wLocal, Placement]


PATTERNS: [Name, Type, Factors]
CONTROLS: [blob]

inp_section_tags:
['[TITLE', '[OPTION', '[FILE', '[RAINGAGES', '[TEMPERATURE', '[EVAP',
Expand Down
10 changes: 10 additions & 0 deletions swmmio/defs/section_headers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,16 @@ rpt_sections:
- SlopePerc
- RainGage
- Outlet
Pumping Summary:
- PercentUtilized
- NumberOfStartUps
- MinFlowCFS
- AvgFlowCFS
- MaxFlowCFS
- TotalVolume(MG)
- PowerUsage(kW-hr)
- PercentTimeOffPumpCurveLow
- PercentTimeOffPumpCurveHigh

swmm5_version:
1.13:
Expand Down
4 changes: 3 additions & 1 deletion swmmio/examples.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from swmmio import Model
from swmmio.tests.data import (MODEL_A_PATH, MODEL_EX_1, MODEL_FULL_FEATURES_XY,
MODEL_FULL_FEATURES__NET_PATH, MODEL_FULL_FEATURES_XY_B,
MODEL_GREEN_AMPT, MODEL_TEST_INLET_DRAINS, MODEL_GROUNDWATER)
MODEL_GREEN_AMPT, MODEL_TEST_INLET_DRAINS, MODEL_GROUNDWATER,
MODEL_PUMP_CONTROL)

# example models
philly = Model(MODEL_A_PATH, crs="+init=EPSG:2817")
Expand All @@ -12,3 +13,4 @@
green = Model(MODEL_GREEN_AMPT)
streets = Model(MODEL_TEST_INLET_DRAINS)
groundwater = Model(MODEL_GROUNDWATER)
pump_control = Model(MODEL_PUMP_CONTROL)
Loading
Loading