Skip to content

Commit 0320700

Browse files
authored
Merge pull request #37 from SWMM-Project/dev
Merge OWA/swmm-python <- SWMM-Project/swmm-python
2 parents 3bbec7a + 28ac3d9 commit 0320700

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+3695
-1322
lines changed

.gitignore

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,24 @@
22
# .gitignore for swmm-python repo
33
#
44

5+
56
.*
67
!.gitignore
8+
!.gitmodules
9+
.DS_Store
710

8-
*.py[ocd]
11+
*.pyc
912

10-
*.dll
11-
*.lib
12-
*.exp
13-
*.so
14-
*.h
15-
buildlib/
13+
_skbuild/
14+
_cmake_test_compile
1615

17-
build/
1816
dist/
17+
MANIFEST
1918
.pytest_cache/
19+
__pycache__/
2020
*.egg-info/
2121

22-
output.py
23-
output_wrap.c
24-
25-
toolkit.py
26-
toolkit_wrap.c
22+
swmm-toolkit/docs/_build
2723

28-
swmm_python/toolkit/tests/data/test.*
24+
swmm-toolkit/tests/data/*
25+
!test_*.*

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "swmm-toolkit/swmm-solver"]
2+
path = swmm-toolkit/swmm-solver
3+
url = https://github.com/SWMM-Project/swmm-solver.git

README.md

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,7 @@
11
# swmm-python
22

33

4-
## Build Status
5-
[![Build status](https://ci.appveyor.com/api/projects/status/g13vapirwhinmtob/branch/dev?svg=true)](https://ci.appveyor.com/project/michaeltryby/swmm-python/branch/dev)
6-
7-
[![Coverage Status](https://coveralls.io/repos/github/michaeltryby/swmm-python/badge.svg)](https://coveralls.io/github/michaeltryby/swmm-python)
8-
9-
104
## Contents
11-
* swmm-python - SWIG based wrappers for the SWMM Toolkit and Output libraries.
5+
* nrtest-swmm - Plugin for performing numerical regression testing on swmm-solver.
6+
* swmm-toolkit - SWIG based wrappers for the swmm-solver and swmm-output libraries.
127
* ...
13-
14-
15-
## Build Notes
16-
Note that swmm-python wraps the feature-wrapper branch of SWMM v5.1.12.

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ artifacts:
3737
cache:
3838
- C:\ProgramData\chocolatey\bin -> appveyor.yml
3939
- C:\ProgramData\chocolatey\lib -> appveyor.yml
40-
- C:\projects\swmm-python\.tox -> tox.ini
40+
# - C:\projects\swmm-python\.tox -> tox.ini

before_build.bat

Lines changed: 0 additions & 60 deletions
This file was deleted.

nrtest-swmm/main.py

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# -*- coding: utf-8 -*-
2+
3+
#
4+
# main.py
5+
#
6+
# Author: Michael E. Tryby
7+
# US EPA - ORD/NRMRL
8+
#
9+
'''
10+
Provides entry point main. Useful for development and testing purposes.
11+
'''
12+
13+
import cStringIO
14+
15+
import time
16+
17+
import header_detail_footer as hdf
18+
import numpy as np
19+
20+
import nrtest_swmm.output_reader as ordr
21+
22+
def result_compare(path_test, path_ref, comp_args):
23+
24+
isclose = True
25+
close = 0
26+
notclose = 0
27+
equal = 0
28+
total = 0
29+
output = cStringIO.StringIO()
30+
eps = np.finfo(float).eps
31+
32+
start = time.time()
33+
34+
test_reader = ordr.output_generator(path_test)
35+
ref_reader = ordr.output_generator(path_ref)
36+
37+
for test, ref in _zip(test_reader, ref_reader):
38+
total += 1
39+
if total%100000 == 0:
40+
print(total)
41+
42+
if len(test) != len(ref):
43+
raise ValueError('Inconsistent lengths')
44+
45+
# Skip results if they are zero or equal
46+
if np.array_equal(test, ref):
47+
equal += 1
48+
continue
49+
else:
50+
try:
51+
np.testing.assert_allclose(test, ref, comp_args[0], comp_args[1])
52+
close += 1
53+
54+
except AssertionError as ae:
55+
notclose += 1
56+
output.write(str(ae))
57+
output.write('\n\n')
58+
continue
59+
60+
stop = time.time()
61+
62+
print(output.getvalue())
63+
output.close()
64+
65+
print('equal: %d close: %d notclose: %d total: %d in %f (sec)\n' %
66+
(equal, close, notclose, total, (stop - start)))
67+
68+
if notclose > 0:
69+
print('%d differences found\n' % notclose)
70+
isclose = False
71+
72+
return isclose
73+
74+
def array_zero(test, ref):
75+
if not test.any() and not ref.any():
76+
return True
77+
return False
78+
79+
def report_compare(path_test, path_ref, (comp_args)):
80+
'''
81+
Compares results in two report files ignoring contents of header and footer.
82+
'''
83+
with open(path_test ,'r') as ftest, open(path_ref, 'r') as fref:
84+
for (test_line, ref_line) in zip(hdf.parse(ftest, 4, 4)[1],
85+
hdf.parse(fref, 4, 4)[1]):
86+
if test_line != ref_line:
87+
return False
88+
89+
return True
90+
91+
92+
import logging
93+
from os import listdir
94+
from os.path import exists, isfile, isdir, join
95+
96+
from nrtest.testsuite import TestSuite
97+
from nrtest.compare import compare_testsuite, validate_testsuite
98+
from nrtest.execute import execute_testsuite
99+
100+
def nrtest_compare(path_test, path_ref, rtol, atol):
101+
102+
ts_new = TestSuite.read_benchmark(path_test)
103+
ts_old = TestSuite.read_benchmark(path_ref)
104+
105+
if not validate_testsuite(ts_new) or not validate_testsuite(ts_old):
106+
exit(1)
107+
108+
try:
109+
logging.info('Found %i tests' % len(ts_new.tests))
110+
compatible = compare_testsuite(ts_new, ts_old, rtol, atol)
111+
except KeyboardInterrupt:
112+
logging.warning('Process interrupted by user')
113+
compatible = False
114+
else:
115+
logging.info('Finished')
116+
117+
# Non-zero exit code indicates failure
118+
exit(not compatible)
119+
120+
def nrtest_execute(app_path, test_path, output_path):
121+
122+
123+
for p in test_path + [app_path]:
124+
if not exists(p):
125+
logging.error('Could not find path: "%s"' % p)
126+
127+
test_dirs = [p for p in test_path if isdir(p)]
128+
test_files = [p for p in test_path if isfile(p)]
129+
test_files += [join(d, p) for d in test_dirs for p in listdir(d)
130+
if p.endswith('.json')]
131+
132+
test_files = list(set(test_files)) # remove duplicates
133+
134+
ts = TestSuite.read_config(app_path, test_files, output_path)
135+
136+
if not validate_testsuite(ts):
137+
exit(1)
138+
139+
try:
140+
logging.info('Found %i tests' % len(test_files))
141+
success = execute_testsuite(ts)
142+
ts.write_manifest()
143+
except KeyboardInterrupt:
144+
logging.warning('Process interrupted by user')
145+
success = False
146+
else:
147+
logging.info('Finished')
148+
149+
# Non-zero exit code indicates failure
150+
exit(not success)
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# -*- coding: utf-8 -*-
2+
3+
#
4+
# __init__.py - nrtest_swmm module
5+
#
6+
# Author: Michael E. Tryby
7+
# US EPA - ORD/NRMRL
8+
#
9+
10+
'''
11+
Numerical regression testing (nrtest) plugin for comparing SWMM binary results
12+
files and SWMM text based report files.
13+
'''
14+
15+
# third party imports
16+
import header_detail_footer as hdf
17+
import numpy as np
18+
19+
# project imports
20+
import nrtest_swmm.output_reader as ordr
21+
22+
23+
__author__ = "Michael E. Tryby"
24+
__copyright__ = "None"
25+
__credits__ = "Colleen Barr, Maurizio Cingi, Mark Gray, David Hall, Bryant McDonnell"
26+
__license__ = "CC0 1.0 Universal"
27+
28+
__version__ = "0.6.0"
29+
__date__ = "May 8, 2020"
30+
31+
__maintainer__ = "Michael E. Tryby"
32+
__email__ = "[email protected]"
33+
__status = "Development"
34+
35+
36+
def swmm_allclose_compare(path_test, path_ref, rtol, atol):
37+
'''
38+
Compares results in two SWMM binary files. Using the comparison criteria
39+
described in the numpy assert_allclose documentation.
40+
41+
(test_value - ref_value) <= atol + rtol * abs(ref_value)
42+
43+
Returns true if all of the results in the two binary files meet the
44+
comparison criteria; otherwise, an AssertionError is thrown.
45+
46+
Numpy allclose is quite expensive to evaluate. Test and reference results
47+
are checked to see if they are equal before being compared using the
48+
allclose criteria. This reduces comparison times significantly.
49+
50+
Arguments:
51+
path_test - path to result file being tested
52+
path_ref - path to reference result file
53+
rtol - relative tolerance
54+
atol - absolute tolerance
55+
56+
Returns:
57+
True or raises an error
58+
59+
Raises:
60+
ValueError()
61+
AssertionError()
62+
...
63+
'''
64+
65+
for (test, ref) in zip(ordr.output_generator(path_test),
66+
ordr.output_generator(path_ref)):
67+
68+
if len(test[0]) != len(ref[0]):
69+
raise ValueError('Inconsistent lengths')
70+
71+
# Skip over results if they are equal
72+
if (np.array_equal(test[0], ref[0])):
73+
continue
74+
75+
else:
76+
np.testing.assert_allclose(test[0], ref[0], rtol, atol)
77+
78+
return True
79+
80+
#def swmm_better_compare():
81+
# '''
82+
# If for some reason you don't like numpy.testing.assert_allclose() add a
83+
# better function here. Be sure to add the entry point to the setup file so
84+
# nrtest can find it at runtime.
85+
# '''
86+
# pass
87+
88+
def swmm_report_compare(path_test, path_ref, rtol, atol):
89+
'''
90+
Compares results in two report files ignoring contents of header and footer.
91+
92+
Arguments:
93+
path_test - path to result file being tested
94+
path_ref - path to reference result file
95+
rtol - ignored
96+
atol - ignored
97+
98+
Returns:
99+
True or False
100+
101+
Raises:
102+
HeaderError()
103+
FooterError()
104+
RunTimeError()
105+
...
106+
'''
107+
108+
HEADER = 4
109+
FOOTER = 4
110+
111+
with open(path_test ,'r') as ftest, open(path_ref, 'r') as fref:
112+
113+
for (test_line, ref_line) in zip(hdf.parse(ftest, HEADER, FOOTER)[1],
114+
hdf.parse(fref, HEADER, FOOTER)[1]):
115+
116+
if test_line != ref_line:
117+
return False
118+
119+
return True

0 commit comments

Comments
 (0)