Skip to content

Commit 6c08f7e

Browse files
committed
WIP API and bindings unit testing #204, #162, #163, #184, #180
1 parent 5b87a2b commit 6c08f7e

File tree

10 files changed

+357
-62
lines changed

10 files changed

+357
-62
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: Build for Release
2+
3+
on:
4+
push:
5+
branches: [ master]
6+
# pull_request:
7+
# branches: [ master, develop, release ]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v3
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: Build and Regression Test
2+
3+
on:
4+
push:
5+
branches: [ master]
6+
# pull_request:
7+
# branches: [ master, develop, release ]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v3

.github/workflows/build-and-unit-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Build and Unit Test
22

33
on:
44
push:
5-
branches: [ master, develop, release ]
5+
branches: [ master]
66
# pull_request:
77
# branches: [ master, develop, release ]
88

python/epaswmm/solver/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@
1717
encode_swmm_datetime,
1818
version,
1919
SolverState,
20+
SWMMSolverException,
2021
Solver
2122
)

python/epaswmm/solver/solver.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ cdef extern from "swmm5.h":
147147
swmm_IGNOREGROUNDWATER # Flag indicating whether groundwater is ignored.
148148
swmm_IGNOREROUTING # Flag indicating whether routing is ignored.
149149
swmm_IGNOREQUALITY # Flag indicating whether water quality is ignored.
150+
swmm_ERROR_CODE # The error code.
150151
swmm_RULESTEP # The rule step size.
151152
swmm_SWEEPSTART # The start date of the sweep start.
152153
swmm_SWEEPEND # The end date of the sweep end.

python/epaswmm/solver/solver.pyx

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ from warnings import warn
1010
from typing import List, Tuple, Union, Optional, Dict, Set, Callable
1111
from cpython.datetime cimport datetime, timedelta
1212
from libc.stdlib cimport free, malloc
13+
from functools import partialmethod
1314

1415
# external imports
1516

@@ -105,7 +106,7 @@ class SWMMObjects(Enum):
105106
:type SYSTEM: int
106107
"""
107108
RAIN_GAGE = swmm_Object.swmm_GAGE
108-
SUBCATCH = swmm_Object.swmm_SUBCATCH
109+
SUBCATCHMENT = swmm_Object.swmm_SUBCATCH
109110
NODE = swmm_Object.swmm_NODE
110111
LINK = swmm_Object.swmm_LINK
111112
AQUIFER = swmm_Object.swmm_AQUIFER
@@ -450,6 +451,7 @@ class SWMMSystemProperties(Enum):
450451
IGNORE_GROUNDWATER = swmm_SystemProperty.swmm_IGNOREGROUNDWATER
451452
IGNORE_ROUTING = swmm_SystemProperty.swmm_IGNOREROUTING
452453
IGNORE_QUALITY = swmm_SystemProperty.swmm_IGNOREQUALITY
454+
ERROR_CODE = swmm_SystemProperty.swmm_ERROR_CODE
453455
RULE_STEP = swmm_SystemProperty.swmm_RULESTEP
454456
SWEEP_START = swmm_SystemProperty.swmm_SWEEPSTART
455457
SWEEP_END = swmm_SystemProperty.swmm_SWEEPEND
@@ -712,8 +714,9 @@ cdef class Solver:
712714
cdef clock_t _clock
713715
cdef double _total_duration
714716
cdef object _solver_state
717+
cdef object _partial_step_function
715718

716-
def __cinit__(self, str inp_file, str rpt_file, str out_file, bint save_results=True):
719+
def __cinit__(self, str inp_file, str rpt_file, str out_file, int stride_step = 300, bint save_results=True):
717720
"""
718721
Constructor to create a new SWMM solver.
719722
@@ -725,6 +728,7 @@ cdef class Solver:
725728
self._save_results = save_results
726729
self._inp_file = inp_file
727730
self._progress_callbacks_per_second = 2
731+
self._stride_step = stride_step
728732
self._clock = clock()
729733
global_solver = self
730734

@@ -738,8 +742,6 @@ cdef class Solver:
738742
else:
739743
self._out_file = inp_file.replace('.inp', '.out')
740744

741-
self._stride_step = 0
742-
743745
self._callbacks = {
744746
CallbackType.BEFORE_INITIALIZE: [],
745747
CallbackType.BEFORE_OPEN: [],
@@ -932,6 +934,8 @@ cdef class Solver:
932934
"""
933935
cdef int count = swmm_getCount(object_type.value)
934936

937+
self.__validate_error(count)
938+
935939
return count
936940

937941
def get_object_name(self, object_type: SWMMObjects, index: int) -> str:
@@ -946,8 +950,8 @@ cdef class Solver:
946950
:rtype: str
947951
"""
948952
cdef char* c_object_name = <char*>malloc(1024*sizeof(char))
949-
cdef int error_code = swmm_getName(object_type.value, index, c_object_name, 1024)
950953

954+
cdef int error_code = swmm_getName(object_type.value, index, c_object_name, 1024)
951955
self.__validate_error(error_code)
952956

953957
object_name = c_object_name.decode('utf-8')
@@ -956,6 +960,32 @@ cdef class Solver:
956960

957961
return object_name
958962

963+
def get_object_names(self, object_type: SWMMObjects) -> List[str]:
964+
"""
965+
Get the names of all SWMM objects of a given type.
966+
967+
:param object_type: SWMM object type
968+
:type object_type: SWMMObjects
969+
:return: Object names
970+
:rtype: List[str]
971+
"""
972+
cdef char* c_object_name = <char*>malloc(1024*sizeof(char))
973+
cdef list object_names = []
974+
cdef int count = self.get_object_count(object_type)
975+
976+
for i in range(count):
977+
978+
error_code = swmm_getName(object_type.value, i, c_object_name, 1024)
979+
self.__validate_error(error_code)
980+
981+
object_name = c_object_name.decode('utf-8')
982+
object_names.append(object_name)
983+
984+
985+
free(c_object_name)
986+
987+
return object_names
988+
959989
def get_object_index(self, object_type: SWMMObjects, object_name: str) -> int:
960990
"""
961991
Get the index of a SWMM object.
@@ -971,7 +1001,7 @@ cdef class Solver:
9711001

9721002
return index
9731003

974-
cpdef void set_value(self, int object_type, int property_type, int index, int sub_index, double value):
1004+
cpdef void set_value(self, int object_type, int property_type, int index, double value, int sub_index = -1):
9751005
"""
9761006
Set a SWMM system property value.
9771007
@@ -989,7 +1019,7 @@ cdef class Solver:
9891019
cdef int error_code = swmm_setValueExpanded(object_type, property_type, index, sub_index, value)
9901020
self.__validate_error(error_code)
9911021

992-
cpdef double get_value(self, int object_type, int property_type, int index, int sub_index):
1022+
cpdef double get_value(self, int object_type, int property_type, int index, int sub_index = -1):
9931023
"""
9941024
Get a SWMM system property value.
9951025
@@ -999,6 +1029,8 @@ cdef class Solver:
9991029
:rtype: double
10001030
"""
10011031
cdef double value = swmm_getValueExpanded(object_type, property_type, index, sub_index)
1032+
self.__validate_error(<int>value)
1033+
10021034
return value
10031035

10041036
@property
@@ -1009,7 +1041,7 @@ cdef class Solver:
10091041
:return: Stride step
10101042
:rtype: int
10111043
"""
1012-
pass
1044+
return self._stride_step
10131045

10141046
@stride_step.setter
10151047
def stride_step(self, value: int):
@@ -1019,7 +1051,7 @@ cdef class Solver:
10191051
:param value: Stride step in seconds
10201052
:type value: int
10211053
"""
1022-
pass
1054+
self._stride_step = value
10231055

10241056
@property
10251057
def solver_state(self) -> SolverState:
@@ -1078,18 +1110,11 @@ cdef class Solver:
10781110
self.__validate_error(error_code)
10791111
self._solver_state = SolverState.OPEN
10801112
self.__execute_callbacks(CallbackType.AFTER_OPEN)
1081-
1082-
self.__execute_callbacks(CallbackType.BEFORE_START)
1083-
error_code = swmm_start(self._save_results)
1084-
self.__validate_error(error_code)
1085-
self._solver_state = SolverState.STARTED
1086-
self.__execute_callbacks(CallbackType.AFTER_START)
10871113
else:
10881114
raise SWMMSolverException(f'Initialize failed: Solver is not in a valid state: {self._solver_state}')
10891115

1090-
10911116
self._total_duration = swmm_getValue(SWMMSystemProperties.END_DATE.value, 0) - swmm_getValue(SWMMSystemProperties.START_DATE.value, 0)
1092-
1117+
10931118
cpdef double step(self):
10941119
"""
10951120
Step a SWMM simulation.
@@ -1100,6 +1125,13 @@ cdef class Solver:
11001125
cdef double elapsed_time = 0.0
11011126
cdef double progress = 0.0
11021127

1128+
if self._solver_state == SolverState.OPEN:
1129+
self.__execute_callbacks(CallbackType.BEFORE_START)
1130+
error_code = swmm_start(self._save_results)
1131+
self.__validate_error(error_code)
1132+
self._solver_state = SolverState.STARTED
1133+
self.__execute_callbacks(CallbackType.AFTER_START)
1134+
11031135
if self._stride_step > 0:
11041136
error_code = swmm_stride(self._stride_step, &elapsed_time)
11051137
else:
@@ -1241,8 +1273,13 @@ cdef class Solver:
12411273
:param error_code: Error code to validate
12421274
:type error_code: int
12431275
"""
1244-
if error_code != 0:
1245-
raise SWMMSolverException(f'SWMM failed with message: {self.__get_error()}')
1276+
cdef int internal_error_code = <int>swmm_getValue(SWMMObjects.SYSTEM.value, SWMMSystemProperties.ERROR_CODE.value)
1277+
1278+
if error_code < 0:
1279+
if internal_error_code > 0:
1280+
raise SWMMSolverException(f'SWMM failed with message: {internal_error_code}, {self.__get_error()}')
1281+
else:
1282+
raise SWMMSolverException(f'SWMM failed with message: {error_code}, {get_error_message(error_code)}')
12461283

12471284
cdef str __get_error(self):
12481285
"""

0 commit comments

Comments
 (0)