Skip to content

Commit

Permalink
Merge pull request #33 from aerispaha/py3
Browse files Browse the repository at this point in the history
Python 2/3 Compatibility
  • Loading branch information
aerispaha authored Oct 12, 2018
2 parents fbf93c4 + c6e11b5 commit 28756e9
Show file tree
Hide file tree
Showing 31 changed files with 660 additions and 88 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ private.py
private/
# Setuptools distribution folder.
/dist/
/build/
# Python egg metadata, regenerated from source files by setuptools.
/*.egg-info
notes/
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
language: python
python:
- "2.7"
# - "3.6"
- "3.6"
# - "3.7"
# command to install dependencies
install:
Expand Down
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# SWMMIO

[![Build status](https://ci.appveyor.com/api/projects/status/qywujm5w2wm0y2tv?svg=true)](https://ci.appveyor.com/project/aerispaha/swmmio)

![Kool Picture](docs/img/impact_of_option.png?raw=true "Impact of Option")
SWMMIO is a set of python tools aiming to provide a means for version control and visualizing results from the EPA Stormwater Management Model (SWMM). Command line tools are also provided for running models individually and in parallel via Python's `multiprocessing` module. These tools are being developed specifically for the application of flood risk management, though most functionality is applicable to SWMM modeling in general.

Expand All @@ -8,7 +11,7 @@ SWMMIO functions primarily by interfacing with .inp and .rpt (input and report)


### Dependencies
* [pillow](http://python-pillow.org/): 3.0.0
* [pillow](http://python-pillow.org/)
* [matplotlib](http://matplotlib.org/)
* [numpy](http://www.numpy.org/)
* [pandas](https://github.com/pydata/pandas)
Expand All @@ -19,10 +22,6 @@ SWMMIO functions primarily by interfacing with .inp and .rpt (input and report)
Before installation, it's recommended to first activate a [virtualenv](https://github.com/pypa/virtualenv) to not crowd your system's package library. If you don't use any of the dependencies listed above, this step is less important. SWMMIO can be installed via pip in your command line:

```bash
#on Windows:
python -m pip install swmmio

#on Unix-type systems, i do this:
pip install swmmio
```

Expand Down
38 changes: 38 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#matrix:
# fast_finish: true

#branches:
# only:
# - master
# - /dev-.*/

environment:
matrix:
# For Python versions available on Appveyor, see
# http://www.appveyor.com/docs/installed-software#python
# The list here is complete (excluding Python 2.6, which
# isn't covered by this document) at the time of writing.
- PYTHON: "C:\\Python27"
- PYTHON: "C:\\Python36"

install:
- "%PYTHON%\\python setup.py develop"
- "%PYTHON%\\python.exe -m pip install -r %APPVEYOR_BUILD_FOLDER%\\requirements.txt -q"

build: off

test_script:

- "%PYTHON%\\Scripts\\pytest %APPVEYOR_BUILD_FOLDER%"

# Asserting pep8 formatting checks (using autopep8 tool)
# - ps: |
# $output = C:\\Python36\\Scripts\\autopep8 -d --recursive .
# if($output)
# {
# echo $output;
# $host.SetShouldExit(1)
# Write-Host "autopep8 failed:
# Please this command locally:
# 'autopep8 -i -a -r .'"
# }
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Build dependencies
#python
pytest
pillow==3.0.0
pillow
numpy
pandas
pyshp
Expand Down
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()


VERSION = '0.2.1'
VERSION = '0.3.0'
AUTHOR_NAME = 'Adam Erispaha'
AUTHOR_EMAIL = '[email protected]'

install_requires = [
'pillow==3.0.0',
# 'pillow==3.0.0',
'Pillow',
'numpy',
'pandas',
'pyshp',
Expand Down
16 changes: 8 additions & 8 deletions swmmio/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .run_models.run import run_simple, run_hot_start_sequence
from .run_models import start_pool
from swmmio import Model
from .swmmio import Model
from itertools import chain
import os
import argparse
Expand All @@ -21,23 +21,23 @@
if args.model_to_run is not None:

models_paths = [os.path.join(wd, f) for f in args.model_to_run]
print 'Adding models to queue:\n\t{}'.format('\n\t'.join(models_paths))
print('Adding models to queue:\n\t{}'.format('\n\t'.join(models_paths)))

#run the models in series (one after the other)
map(run_simple, models_paths)
list(map(run_simple, models_paths))
# run_simple(args.model_to_run)

elif args.hotstart_model_to_run is not None:
models_paths = [os.path.join(wd, f) for f in args.hotstart_model_to_run]
print 'hotstart_model_to_run the model: {}'.format(args.hotstart_model_to_run)
print('hotstart_model_to_run the model: {}'.format(args.hotstart_model_to_run))
# m = Model(args.hotstart_model_to_run)
# run_hot_start_sequence(m)#args.hotstart_model_to_run)
map(run_hot_start_sequence, models_paths)
list(map(run_hot_start_sequence, models_paths))

elif args.start_pool is not None:

models_dirs = [os.path.join(wd, f) for f in args.start_pool]
print 'Searching for models in:\n\t{}'.format('\n\t'.join(models_dirs))
print('Searching for models in:\n\t{}'.format('\n\t'.join(models_dirs)))
#combine the segments and options (combinations) into one iterable
inp_paths = []
for root, dirs, files in chain.from_iterable(os.walk(path) for path in models_dirs):
Expand All @@ -50,8 +50,8 @@
#call the main() function in start_pool.py
start_pool.main(inp_paths, args.cores_left)

print "swmmio has completed running {} models".format(len(inp_paths))
print("swmmio has completed running {} models".format(len(inp_paths)))


else:
print 'you need to pass in some args'
print('you need to pass in some args')
2 changes: 2 additions & 0 deletions swmmio/defs/sectionheaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
'[INFILTRATION]':'Subcatchment Suction HydCon IMDmax',
'[Polygons]':'Name X Y',
'[REPORT]':'Param Status',
'[TAGS]':'ElementType Name Tag',
#'[CURVES]':'Name Type X-Value Y-Value',
#'[TIMESERIES]':'Name Date Time Value'
}
Expand All @@ -41,6 +42,7 @@
'Node Flooding Summary':'Name HoursFlooded MaxQ MaxDay MaxHr TotalFloodVol MaximumPondDepth',
'Node Inflow Summary':'Name Type MaxLatInflow MaxTotalInflow MaxDay MaxHr LatInflowV TotalInflowV FlowBalErrorPerc XXX',
'Node Surcharge Summary':'Name Type HourSurcharged MaxHeightAboveCrown MinDepthBelowRim',
'Storage Volume Summary':'Name AvgVolume AvgPctFull EvapPctLoss ExfilPctLoss MaxVolume MaxPctFull MaxDay MaxFullHr MaxOutflow',
'Node Depth Summary':'Name Type AvgDepth MaxNodeDepth MaxHGL MaxDay MaxHr',
'Link Flow Summary':'Name Type MaxQ MaxDay MaxHr MaxV MaxQPerc MaxDPerc',
'Subcatchment Results': 'Date Time PrecipInchPerHour LossesInchPerHr RunoffCFS',
Expand Down
22 changes: 11 additions & 11 deletions swmmio/graphics/animate.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):
"""
#unpack and update the options
ops = du.default_draw_options()
for key, value in kwargs.iteritems():
for key, value in kwargs.items():
ops.update({key:value})
#return ops
width = ops['width']
Expand Down Expand Up @@ -63,8 +63,8 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):
if userStartDT < simStartDT or userEndDT > simEndDT or timeStepMod != 0 or userEndDT < userStartDT:
#user has entered fault date times either by not being within the
#availble data in the rpt or by starting at something that doesn't fit the timestep
print "PROBLEM WITH DATETIME ENTERED. Make sure it fits within data and start time rest on factor of timestep in minutes."
print "userStartDT = ", userStartDT, "\nuserEndDT = ", userEndDT, "\nsimStartDT = ", simStartDT, "\nsimEndDT = ", simEndDT, "\nTIMESTEP = ", rpt.timeStepMin
print("PROBLEM WITH DATETIME ENTERED. Make sure it fits within data and start time rest on factor of timestep in minutes.")
print("userStartDT = ", userStartDT, "\nuserEndDT = ", userEndDT, "\nsimStartDT = ", simStartDT, "\nsimEndDT = ", simEndDT, "\nTIMESTEP = ", rpt.timeStepMin)
return None

currentT = datetime.strptime(startDtime, "%b-%d-%Y %H:%M:%S") #SWMM dtime format needed
Expand All @@ -81,7 +81,7 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):
if not os.path.isfile(byteLocDictionaryFName):

#this is a heavy operation, allow a few minutes
print "generating byte dictionary..."
print("generating byte dictionary...")
#conduitByteLocationDict = rpt.createByteLocDict("Link Results")
rpt.createByteLocDict("Link Results")
rpt.createByteLocDict("Node Results")
Expand All @@ -96,7 +96,7 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):
rpt.elementByteLocations = pickle.load( open(byteLocDictionaryFName, 'r') )
#rpt.byteLocDict = conduitByteLocationDict

print "Started Drawing at " + strftime("%b-%d-%Y %H:%M:%S")
print("Started Drawing at " + strftime("%b-%d-%Y %H:%M:%S"))
log = "Started Drawing at " + strftime("%b-%d-%Y %H:%M:%S") + "\n\nErrors:\n\n"
drawCount = 0
conduitErrorCount = 0
Expand All @@ -116,7 +116,7 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):

#DRAW THE CONDUITS
if ops['conduitSymb']:
for id, conduit in conduitDicts.iteritems():
for id, conduit in conduitDicts.items():
#coordPair = coordPairDict['coordinates']
if conduit.coordinates: #this prevents draws if no flow is supplied (RDII and such)

Expand All @@ -125,11 +125,11 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):

drawCount += 1

if drawCount > 0 and drawCount % 2000 == 0: print str(drawCount) + " pipes drawn - simulation time = " + currentTstr
if drawCount > 0 and drawCount % 2000 == 0: print(str(drawCount) + " pipes drawn - simulation time = " + currentTstr)

#DRAW THE NODES
if ops['nodeSymb']:
for id, node in nodeDicts.iteritems():
for id, node in nodeDicts.items():
if node.coordinates: #this prevents draws if no flow is supplied (RDII and such)
su.drawNode(node, nodeDict, draw, rpt=rpt, dTime=currentTstr, options=ops['nodeSymb'], xplier=xplier)
drawCount += 1
Expand All @@ -153,7 +153,7 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):
imgPath = os.path.join(tempImgDir, image)
frames.append(Image.open(imgPath))

print "building gif with " + str(len(glob.glob1(tempImgDir, "*.png"))) + " frames..."
print("building gif with " + str(len(glob.glob1(tempImgDir, "*.png"))) + " frames...")
if not imgName: imgName = inp.name
gifFile = os.path.join(imgDir, imgName) + ".gif"
frameDuration = 1.0 / float(ops['fps'])
Expand All @@ -165,7 +165,7 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):
with open(os.path.join(imgDir, "log.txt"), 'w') as logFile:
logFile.write(log)

print "Draw Count =" + str(drawCount)
print "Video saved to:\n\t" + gifFile
print("Draw Count =" + str(drawCount))
print("Video saved to:\n\t" + gifFile)

os.startfile(gifFile)#this doesn't seem to work
10 changes: 5 additions & 5 deletions swmmio/graphics/drawing.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def annotate_streets(df, img, text_col):

#confirm font file location
if not os.path.exists(config.font_file):
print 'Error loading defautl font. Check your config.font_file'
print('Error loading defautl font. Check your config.font_file')
return None

unique_sts = df[text_col].unique()
Expand Down Expand Up @@ -244,13 +244,13 @@ def _annotateMap (canvas, model, model2=None, currentTstr = None, options=None,
#Buid the title and files list (handle 1 or two input models)
#this is hideous, or elegant?
files = title = results_string = symbology_string = annotationTxt = ""
files = '\n'.join([m.rpt.path for m in filter(None, [model, model2])])
title = ' to '.join([m.inp.name for m in filter(None, [model, model2])])
symbology_string = ', '.join([s['title'] for s in filter(None, [nodeSymb, conduitSymb, parcelSymb])])
files = '\n'.join([m.rpt.path for m in [_f for _f in [model, model2] if _f]])
title = ' to '.join([m.inp.name for m in [_f for _f in [model, model2] if _f]])
symbology_string = ', '.join([s['title'] for s in [_f for _f in [nodeSymb, conduitSymb, parcelSymb] if _f]])
title += "\n" + symbology_string

#collect results
for result, value in results.iteritems():
for result, value in results.items():
results_string += '\n' + result + ": " + str(value)

#compile the annotation text
Expand Down
8 changes: 4 additions & 4 deletions swmmio/reporting/batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def batch_reports(project_dir, results_file,
if '.inp' in f:
inp_path = os.path.join(path,f)
alt = Model(inp_path)
print 'reporting on {}'.format(alt.name)
print('reporting on {}'.format(alt.name))
#generate the reports
frpt = reporting.FloodReport(alt, parcel_node_join_df)
impact_rpt = reporting.ComparisonReport(baserpt, frpt,
Expand Down Expand Up @@ -97,7 +97,7 @@ def batch_cost_estimates(baseline_dir, segments_dir, options_dir, results_file,
costsdf = functions.estimate_cost_of_new_conduits(baseline, alt,
supplemental_cost_data)
cost_estimate = costsdf.TotalCostEstimate.sum() / math.pow(10, 6)
print '{}: ${}M'.format(alt.name, round(cost_estimate,1))
print('{}: ${}M'.format(alt.name, round(cost_estimate,1)))

model_id = os.path.splitext(f)[0]
with open(results_file, 'a') as res:
Expand Down Expand Up @@ -131,13 +131,13 @@ def batch_post_process(options_dir, baseline_dir, log_dir, bbox=None, overwrite=
current_dir = os.path.join(options_dir, folder)
report_dir = os.path.join(current_dir, REPORT_DIR_NAME)
if not overwrite and os.path.exists(report_dir):
print 'skipping {}'.format(folder)
print('skipping {}'.format(folder))
continue

else:
#generate the report
current_model = Model(current_dir)
print 'Generating report for {}'.format(current_model.inp.name)
print('Generating report for {}'.format(current_model.inp.name))
#reporting.generate_figures(baseline, current_model, bbox=bbox, imgDir=report_dir, verbose=True)
report = reporting.Report(baseline, current_model)
report.write(report_dir)
Expand Down
2 changes: 1 addition & 1 deletion swmmio/reporting/reporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ def generate_figures(self, rpt_dir, parcel_shp_df, bbox=d68d70):

def __str__(self):
"""print friendly"""
catz = filter(None, self.flood_comparison.Category.unique())
catz = [_f for _f in self.flood_comparison.Category.unique() if _f]
a = ['{}: {}'.format(c, self.impact[c]) for c in catz]
files = [self.baseline_report.model.inp.path,
self.alt_report.model.inp.path]
Expand Down
4 changes: 4 additions & 0 deletions swmmio/reporting/serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
from swmmio.utils import spatial
from swmmio.graphics import swmm_graphics as sg
from swmmio.reporting.reporting import FloodReport
<<<<<<< HEAD
from swmmio.definitions import *
=======
from swmmio.defs.config import *
>>>>>>> master
import geojson


Expand Down
2 changes: 1 addition & 1 deletion swmmio/reporting/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def insert_in_file_2(key, string, newfile):

#start writing that thing
key = '{}{}{}'.format('{{', key, '}}') #Django style
print key
print(key)
with open(newfile, 'r') as newmap:
for line in newmap:
if key in line:
Expand Down
2 changes: 1 addition & 1 deletion swmmio/reporting/visualize.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def create_map(model1, model2=None, bbox=None, crs=None, filename=None,

geometries = [] #array of features
#collect the links
for k,v in model2.list_objects('conduit', bbox, subset=subset).items():
for k,v in list(model2.list_objects('conduit', bbox, subset=subset).items()):
props = {
'MaxQPercent':v.maxQpercent,
'id':v.id,
Expand Down
8 changes: 4 additions & 4 deletions swmmio/run_models/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def run_simple(inp_path, swmm_eng=SWMM_ENGINE_PATH):
"""
run a model once as is.
"""
print 'running {} with {}'.format(inp_path, swmm_eng)
print('running {} with {}'.format(inp_path, swmm_eng))
#inp_path = model.inp.path
rpt_path = os.path.splitext(inp_path)[0] + '.rpt'

Expand All @@ -32,7 +32,7 @@ def run_hot_start_sequence(inp_path, swmm_eng=SWMM_ENGINE_PATH):

# if not os.path.exists(hotstart1) and not os.path.exists(hotstart2):
#create new model inp with params to save hotstart1
print 'create new model inp with params to save hotstart1'
print('create new model inp with params to save hotstart1')
s = pd.Series(['SAVE HOTSTART "{}"'.format(hotstart1)])
hot1_df = pd.DataFrame(s, columns=['[FILES]'])
model = replace_inp_section(model.inp.path, '[FILES]', hot1_df)
Expand All @@ -42,15 +42,15 @@ def run_hot_start_sequence(inp_path, swmm_eng=SWMM_ENGINE_PATH):

# if os.path.exists(hotstart1) and not os.path.exists(hotstart2):
#create new model inp with params to use hotstart1 and save hotstart2
print 'with params to use hotstart1 and save hotstart2'
print('with params to use hotstart1 and save hotstart2')
s = pd.Series(['USE HOTSTART "{}"'.format(hotstart1), 'SAVE HOTSTART "{}"'.format(hotstart2)])
hot2_df = pd.DataFrame(s, columns=['[FILES]'])
model = replace_inp_section(model.inp.path, '[FILES]', hot2_df)
subprocess.call([swmm_eng, model.inp.path, rpt_path])

# if os.path.exists(hotstart2):
#create new model inp with params to use hotstart2 and not save anything
print 'params to use hotstart2 and not save anything'
print('params to use hotstart2 and not save anything')
s = pd.Series(['USE HOTSTART "{}"'.format(hotstart2)])
hot3_df = pd.DataFrame(s, columns=['[FILES]'])

Expand Down
Loading

0 comments on commit 28756e9

Please sign in to comment.