From ece93e611069137f178e99dfaf004f741d0f22c1 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Sun, 21 Apr 2024 12:37:07 -0400 Subject: [PATCH 01/17] update sphinx version --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 517aa93..6c0de02 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -3,7 +3,7 @@ Jinja2<3.1 m2r mistune==0.8.4 recommonmark==0.6.0 -Sphinx==3.2.1 +Sphinx>=3.4 sphinx-rtd-theme==0.5.0 sphinxcontrib-applehelp==1.0.2 sphinxcontrib-devhelp==1.0.2 From 7b1670d673f020416e22d5a6a02d530852f38509 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Mon, 22 Apr 2024 14:46:32 -0400 Subject: [PATCH 02/17] revert sphinx version, decrease alabaster version --- docs/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 6c0de02..578eab7 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -3,7 +3,8 @@ Jinja2<3.1 m2r mistune==0.8.4 recommonmark==0.6.0 -Sphinx>=3.4 +Sphinx==3.2.1 +alabaster<0.7.14 sphinx-rtd-theme==0.5.0 sphinxcontrib-applehelp==1.0.2 sphinxcontrib-devhelp==1.0.2 From 13569de4c91a4b142a66c803edf18a661b77bc33 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Thu, 27 Jun 2024 13:40:11 -0500 Subject: [PATCH 03/17] update docs/conf with myst parser plugin --- docs/conf.py | 44 +++++++++++--------------------------------- 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index e98e6bd..a6d3fcb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,8 +12,8 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # -from recommonmark.transform import AutoStructify -from m2r import MdInclude +# from recommonmark.transform import AutoStructify +# from m2r import MdInclude import os import sys import swmmio @@ -23,11 +23,11 @@ # -- Project information ----------------------------------------------------- project = 'swmmio' -copyright = '2022, Adam Erispaha' +copyright = '2024, Adam Erispaha' author = 'Adam Erispaha' # The short X.Y version -version = '' +version = swmmio.__version__ # The full version, including alpha/beta/rc tags release = swmmio.__version__ @@ -46,7 +46,7 @@ 'sphinx.ext.coverage', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', - 'recommonmark', + 'myst_parser', ] # Add any paths that contain templates here, relative to this directory. @@ -55,8 +55,10 @@ # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # -source_suffix = ['.rst', '.md'] -# source_suffix = '.rst' +source_suffix = { + '.rst': 'restructuredtext', + '.md': 'markdown', +} # The master toctree document. master_doc = 'index' @@ -66,7 +68,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -83,7 +85,7 @@ # a list of builtin themes. # # html_theme = 'alabaster' -html_theme = "sphinx_rtd_theme" +html_theme = "pydata_sphinx_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -181,27 +183,3 @@ # A list of files that should not be packed into the epub file. epub_exclude_files = ['search.html'] - -# -- Extension configuration ------------------------------------------------- -def setup(app): - config = { - # 'url_resolver': lambda url: github_doc_root + url, - 'auto_toc_tree_section': 'Contents', - 'enable_eval_rst': True, - } - app.add_config_value('recommonmark_config', config, True) - app.add_transform(AutoStructify) - - # from m2r to make `mdinclude` work - app.add_config_value('no_underscore_emphasis', False, 'env') - app.add_config_value('m2r_parse_relative_links', False, 'env') - app.add_config_value('m2r_anonymous_references', False, 'env') - app.add_config_value('m2r_disable_inline_math', False, 'env') - app.add_directive('mdinclude', MdInclude) - - -# custom logic -from shutil import copytree -import os -os.makedirs('_build/html/docs', exist_ok=True) -copytree('img', '_build/html/docs/img') From b0cc13036c614c3721185d3fe4ad84ae34edc620 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Thu, 27 Jun 2024 13:48:43 -0500 Subject: [PATCH 04/17] moved static docs files, refactor conf similar to pyswmm docs conf --- docs/{ => _static}/img/default_draw.png | Bin docs/{ => _static}/img/flooded_anno_example.png | Bin docs/{ => _static}/img/impact_of_option.png | Bin docs/conf.py | 4 ++-- 4 files changed, 2 insertions(+), 2 deletions(-) rename docs/{ => _static}/img/default_draw.png (100%) rename docs/{ => _static}/img/flooded_anno_example.png (100%) rename docs/{ => _static}/img/impact_of_option.png (100%) diff --git a/docs/img/default_draw.png b/docs/_static/img/default_draw.png similarity index 100% rename from docs/img/default_draw.png rename to docs/_static/img/default_draw.png diff --git a/docs/img/flooded_anno_example.png b/docs/_static/img/flooded_anno_example.png similarity index 100% rename from docs/img/flooded_anno_example.png rename to docs/_static/img/flooded_anno_example.png diff --git a/docs/img/impact_of_option.png b/docs/_static/img/impact_of_option.png similarity index 100% rename from docs/img/impact_of_option.png rename to docs/_static/img/impact_of_option.png diff --git a/docs/conf.py b/docs/conf.py index a6d3fcb..80c5a75 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -73,7 +73,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' @@ -96,7 +96,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['.'] +html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. From 56b5d9e5d081f2022aa8863e2005f43d53ff12c7 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Thu, 27 Jun 2024 16:45:52 -0500 Subject: [PATCH 05/17] change ref to mdinclude --- docs/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 5518444..dc26a9a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,4 +1,5 @@ -.. mdinclude:: ../README.md +.. include:: ../README.md + :parser: myst_parser.sphinx_ .. swmmio documentation master file, created by From 8eb9cce2da6b3d10ba430decdbd0908aaebd5084 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Thu, 27 Jun 2024 16:55:01 -0500 Subject: [PATCH 06/17] update deploy-pages gh action to v4 --- .github/workflows/documentation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 2160f1e..dad3c0d 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -53,4 +53,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@v4 From bd3ebd62124b6796e5c1cb6bd8122faf5f4f2896 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Thu, 27 Jun 2024 19:44:41 -0500 Subject: [PATCH 07/17] temporarily drop deploy on tag condition, add permissions --- .github/workflows/documentation.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index dad3c0d..822b5b8 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -44,12 +44,15 @@ jobs: path: './docs/build' deploy: - if: startsWith(github.event.ref, 'refs/tags/v') + # if: startsWith(github.event.ref, 'refs/tags/v') environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build + permissions: + pages: write + id-token: write steps: - name: Deploy to GitHub Pages id: deployment From 33d1a1105315be07fff1f3899f3bf8f63cf8695d Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Thu, 27 Jun 2024 19:50:35 -0500 Subject: [PATCH 08/17] add configure-pages action before deploy-pages --- .github/workflows/documentation.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 822b5b8..70a49f0 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -54,6 +54,8 @@ jobs: pages: write id-token: write steps: + - name: Setup Pages + uses: actions/configure-pages@v3 - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 From 2bd1fbf4c9cdae2073f0c0a038490209392adfb1 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Thu, 27 Jun 2024 19:56:29 -0500 Subject: [PATCH 09/17] revert to deploy-pages v2 --- .github/workflows/documentation.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 70a49f0..212a8d9 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -50,12 +50,7 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build - permissions: - pages: write - id-token: write steps: - - name: Setup Pages - uses: actions/configure-pages@v3 - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@v2 From 1ab086b74e1c2821607584ac5f1a8917453f3208 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Fri, 28 Jun 2024 12:58:54 -0500 Subject: [PATCH 10/17] refactoring docs organization --- docs/conf.py | 1 + docs/index.rst | 28 +++-- docs/installing.md | 8 ++ docs/{swmmio.rst => reference/core.rst} | 2 +- docs/{ => reference}/elements.rst | 0 docs/{ => reference}/graphics.rst | 0 docs/reference/index.rst | 20 +++ docs/{ => reference}/utils.rst | 0 docs/{ => reference}/version_control.rst | 0 docs/usage.md | 153 +++++++++++++++++++++++ 10 files changed, 204 insertions(+), 8 deletions(-) create mode 100644 docs/installing.md rename docs/{swmmio.rst => reference/core.rst} (83%) rename docs/{ => reference}/elements.rst (100%) rename docs/{ => reference}/graphics.rst (100%) create mode 100644 docs/reference/index.rst rename docs/{ => reference}/utils.rst (100%) rename docs/{ => reference}/version_control.rst (100%) create mode 100644 docs/usage.md diff --git a/docs/conf.py b/docs/conf.py index 80c5a75..04dc1cf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -46,6 +46,7 @@ 'sphinx.ext.coverage', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', + 'sphinx.ext.autosummary', 'myst_parser', ] diff --git a/docs/index.rst b/docs/index.rst index dc26a9a..499a5fb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,5 +1,20 @@ -.. include:: ../README.md - :parser: myst_parser.sphinx_ +swmmio +======================== + +.. image:: _static/img/impact_of_option.png + :alt: Impact of Option + + +`swmmio` provides a Pythonic interface to the EPA Stormwater Management Model (SWMM) +allowing engineers to programmatically create, modify, and +analyze SWMM models. + +With `swmmio`, model parameters encoded in the `.inp` file can be +retrieved conveniently as Pandas dataframes making it possible to make +automate your hydraulics and hydologic modeling workflow. After simulations are +completed, results in the `.rpt` file can also be retrieved as Pandas dataframes, +making post-processing automation trivial. + .. swmmio documentation master file, created by @@ -11,11 +26,10 @@ :maxdepth: 2 :caption: Contents: - swmmio - elements - version_control - utils - graphics + reference/index + installing + usage + Indices and tables ================== diff --git a/docs/installing.md b/docs/installing.md new file mode 100644 index 0000000..e5202dc --- /dev/null +++ b/docs/installing.md @@ -0,0 +1,8 @@ +### Installation +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: + +```console +pip install swmmio +``` diff --git a/docs/swmmio.rst b/docs/reference/core.rst similarity index 83% rename from docs/swmmio.rst rename to docs/reference/core.rst index a257436..37ef94e 100644 --- a/docs/swmmio.rst +++ b/docs/reference/core.rst @@ -1,4 +1,4 @@ -`swmmio` Core Objects +`swmmio` core objects ======================== .. automodule:: swmmio.core diff --git a/docs/elements.rst b/docs/reference/elements.rst similarity index 100% rename from docs/elements.rst rename to docs/reference/elements.rst diff --git a/docs/graphics.rst b/docs/reference/graphics.rst similarity index 100% rename from docs/graphics.rst rename to docs/reference/graphics.rst diff --git a/docs/reference/index.rst b/docs/reference/index.rst new file mode 100644 index 0000000..eeb7c94 --- /dev/null +++ b/docs/reference/index.rst @@ -0,0 +1,20 @@ +.. -*- coding: utf-8 -*- + +Reference +********* +.. only:: html + + :Release: |release| + :Date: |today| + + +.. toctree:: + :maxdepth: 2 + + core + elements + utils + graphics + version_control + +.. only:: html \ No newline at end of file diff --git a/docs/utils.rst b/docs/reference/utils.rst similarity index 100% rename from docs/utils.rst rename to docs/reference/utils.rst diff --git a/docs/version_control.rst b/docs/reference/version_control.rst similarity index 100% rename from docs/version_control.rst rename to docs/reference/version_control.rst diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000..186a43e --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,153 @@ +# Usage +The `swmmio.Model()` class provides the basic endpoint for interfacing with SWMM models. To get started, save a SWMM5 +model (.inp) in a directory with its report file (.rpt). A few examples: + +```python +import swmmio + +# instantiate a swmmio model object +mymodel = swmmio.Model('/path/to/directory with swmm files') + +# dataframe with useful data related to model nodes, conduits, and subcatchments +nodes = mymodel.nodes.dataframe +links = mymodel.links.dataframe +subs = mymodel.subcatchments.dataframe + +# enjoy all the Pandas functions +nodes.head() + +# write to a csv +nodes.to_csv('/path/mynodes.csv') + +# calculate average and weighted average impervious +avg_imperviousness = subs.PercImperv.mean() +weighted_avg_imp = (subs.Area * subs.PercImperv).sum() / len(subs) +``` + +# Nodes and Links Objects +Specific sections of data from the inp and rpt can be extracted with `Nodes` and `Links` objects. +Although these are the same object-type of the `swmmio.Model.nodes` and `swmmio.Model.links`, +accessing them directly allows for custom control over what sections of data are retrieved. + +```python +from swmmio import Model, Nodes +m = Model("coolest-model.inp") + +# pass custom init arguments into the Nodes object instead of using default settings referenced by m.nodes() +nodes = Nodes( + model=m, + inp_sections=['junctions', 'storages', 'outfalls'], + rpt_sections=['Node Depth Summary', 'Node Inflow Summary'], + columns=[ 'InvertElev', 'MaxDepth', 'InitDepth', 'SurchargeDepth', 'MaxTotalInflow', 'coords'] +) + +# access data +nodes.dataframe +``` + +# Generating Graphics +Create an image (.png) visualization of the model. By default, pipe stress and node flood duration is +visualized if your model includes output data (a .rpt file should accompany the .inp). + +```python +swmmio.draw_model(mymodel) +``` + +![Default Draw Output](_static/img/default_draw.png "Sewer Stress, Node Flooding") + +Use pandas to calculate some interesting stats, and generate a image to highlight +what's interesting or important for your project: + +```python +#isolate nodes that have flooded for more than 30 minutes +flooded_series = nodes.loc[nodes.HoursFlooded>0.5, 'TotalFloodVol'] +flood_vol = sum(flooded_series) #total flood volume (million gallons) +flooded_count = len(flooded_series) #count of flooded nodes + +#highlight these nodes in a graphic +nodes['draw_color'] = '#787882' #grey, default node color +nodes.loc[nodes.HoursFlooded>0.5, 'draw_color'] = '#751167' #purple, flooded nodes + +#set the radius of flooded nodes as a function of HoursFlooded +nodes.loc[nodes.HoursFlooded>1, 'draw_size'] = nodes.loc[nodes.HoursFlooded>1, 'HoursFlooded'] * 12 + +#make the conduits grey, sized as function of their geometry +conds['draw_color'] = '#787882' +conds['draw_size'] = conds.Geom1 + +#add an informative annotation, and draw: +annotation = 'Flooded Volume: {}MG\nFlooded Nodes:{}'.format(round(flood_vol), flooded_count) +swmmio.draw_model(mymodel, annotation=annotation, file_path='flooded_anno_example.png') +``` +![Flooded highlight](_static/img/flooded_anno_example.png "Node Flooding with annotation") + +# Building Variations of Models +Starting with a base SWMM model, other models can be created by inserting altered data into a new inp file. Useful for sensitivity analysis or varying boundary conditions, models can be created using a fairly simple loop, leveraging the `modify_model` package. + +For example, climate change impacts can be investigated by creating a set of models with varying outfall Fixed Stage elevations: + +```python +import os +import swmmio + +# initialize a baseline model object +baseline = swmmio.Model(r'path\to\baseline.inp') +rise = 0.0 #set the starting sea level rise condition + +# create models up to 5ft of sea level rise. +while rise <= 5: + + # create a dataframe of the model's outfalls + outfalls = baseline.inp.outfalls + + # create the Pandas logic to access the StageOrTimeseries column of FIXED outfalls + slice_condition = outfalls.OutfallType == 'FIXED', 'StageOrTimeseries' + + # add the current rise to the outfalls' stage elevation + outfalls.loc[slice_condition] = pd.to_numeric(outfalls.loc[slice_condition]) + rise + baseline.inp.outfalls = outfalls + + # copy the base model into a new directory + newdir = os.path.join(baseline.inp.dir, str(rise)) + os.mkdir(newdir) + newfilepath = os.path.join(newdir, baseline.inp.name + "_" + str(rise) + '_SLR.inp') + + # Overwrite the OUTFALLS section of the new model with the adjusted data + baseline.inp.save(newfilepath) + + # increase sea level rise for the next loop + rise += 0.25 + +``` + +# Access Model Network +The `swmmio.Model` class returns a Networkx MultiDiGraph representation of the model via that `network` parameter: +```python + +# access the model as a Networkx MutliDiGraph +G = model.network + +# iterate through links +for u, v, key, data in model.network.edges(data=True, keys=True): + + print (key, data['Geom1']) + # do stuff with the network +``` + +# Running Models +Using the command line tool, individual SWMM5 models can be run by invoking the swmmio module in your shell as such: +```shell +python -m swmmio --run path/to/mymodel.inp +``` +If you have many models to run and would like to take advantage of your machine's cores, you can start a pool of simulations with the `--start_pool` (or `-sp`) command. After pointing `-sp` to one or more directories, swmmio will search for SWMM .inp files and add all them to a multiprocessing pool. By default, `-sp` leaves 4 of your machine's cores unused. This can be changed via the `-cores_left` argument. +```shell +# run all models in models in directories Model_Dir1 Model_Dir2 +python -m swmmio -sp Model_Dir1 Model_Dir2 + +# leave 1 core unused +python -m swmmio -sp Model_Dir1 Model_Dir2 -cores_left=1 +``` +
+

Warning

+

Using all cores for simultaneous model runs can put your machine's CPU usage at 100% for extended periods of time. This probably puts stress on your hardware. Use at your own risk.

+
From 8c1481994707da35c88a419e1be3f70908a5c047 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Fri, 28 Jun 2024 13:08:44 -0500 Subject: [PATCH 11/17] add Content section header --- docs/index.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 499a5fb..c5f07f8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,9 +22,12 @@ making post-processing automation trivial. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. + +Contents +================== + .. toctree:: :maxdepth: 2 - :caption: Contents: reference/index installing From 0a66168be2425267d596e19db66a4db1589c8b31 Mon Sep 17 00:00:00 2001 From: David Irwin Date: Fri, 6 Sep 2024 13:54:10 +0100 Subject: [PATCH 12/17] Passing single label to .loc rather than list of labels. Changed depreciated delim_whitespace=True to sep=r'\s+'. Changed '\s+' to r'\s+' --- swmmio/graphics/profiler.py | 60 +++++++++++++++++------------------ swmmio/tests/test_graphics.py | 2 +- swmmio/utils/dataframes.py | 6 ++-- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/swmmio/graphics/profiler.py b/swmmio/graphics/profiler.py index fd9552b..269efe5 100644 --- a/swmmio/graphics/profiler.py +++ b/swmmio/graphics/profiler.py @@ -32,7 +32,7 @@ def build_profile_plot(ax, model, path_selection): us_node, ds_node, link_id = link_set # Plot first Node if ind == 0: - invert_el = float(nodes.loc[[us_node]].InvertElev) + invert_el = float(nodes.loc[us_node].InvertElev) profile_config['nodes'].append({"id_name": us_node, "rolling_x_pos": rolling_x_pos, "invert_el": invert_el}) @@ -43,18 +43,18 @@ def build_profile_plot(ax, model, path_selection): # Add next link length to offset old_rolling_x_pos = rolling_x_pos # check link type - if links.loc[[link_id]].Type[0] == "CONDUIT": - rolling_x_pos += float(links.loc[[link_id]].Length) - elif links.loc[[link_id]].Type[0] == "WEIR": + if links.loc[link_id].Type == "CONDUIT": + rolling_x_pos += float(links.loc[link_id].Length) + elif links.loc[link_id].Type == "WEIR": rolling_x_pos += DEFAULT_WEIR_LENGTH - elif links.loc[[link_id]].Type[0] == "ORIFICE": + elif links.loc[link_id].Type == "ORIFICE": rolling_x_pos += DEFAULT_ORIFICE_LENGTH - elif links.loc[[link_id]].Type[0] == "PUMP": + elif links.loc[link_id].Type == "PUMP": rolling_x_pos += DEFAULT_PUMP_LENGTH - elif links.loc[[link_id]].Type[0] == "OUTLET": + elif links.loc[link_id].Type == "OUTLET": rolling_x_pos += DEFAULT_OUTLET_LENGTH # Plot DS node - invert_el = float(nodes.loc[[ds_node]].InvertElev) + invert_el = float(nodes.loc[ds_node].InvertElev) profile_config['nodes'].append({"id_name": ds_node, "rolling_x_pos": rolling_x_pos, "invert_el": invert_el}) @@ -87,17 +87,17 @@ def _add_node_plot(ax, x, model, node_name, link_set, surcharge_depth=0, width=M nodes = model.nodes.dataframe links = model.links.dataframe - invert_el = float(nodes.loc[[node_name]].InvertElev) + invert_el = float(nodes.loc[node_name].InvertElev) # Node Type checker if hasattr(model.inp, "junctions"): if node_name in model.inp.junctions.index: - depth = float(nodes.loc[[node_name]].MaxDepth) + depth = float(nodes.loc[node_name].MaxDepth) if hasattr(model.inp, "outfalls"): if node_name in model.inp.outfalls.index: - depth = float(links.loc[[link_id]].Geom1) + depth = float(links.loc[link_id].Geom1) if hasattr(model.inp, "storage"): if node_name in model.inp.storage.index: - depth = float(nodes.loc[[node_name]].MaxD) + depth = float(nodes.loc[node_name].MaxD) # Plotting Configuration ll_x, ll_y = x - width, invert_el @@ -136,17 +136,17 @@ def _add_link_plot(ax, us_x_position, ds_x_position, model, link_set, width=0, g if model.inp.options.loc['LINK_OFFSETS','Value'] == "ELEVATION": us_node_el, ds_node_el = 0.0, 0.0 else: - us_node_el = float(nodes.loc[[us_node]].InvertElev) - ds_node_el = float(nodes.loc[[ds_node]].InvertElev) + us_node_el = float(nodes.loc[us_node].InvertElev) + ds_node_el = float(nodes.loc[ds_node].InvertElev) - link_type = links.loc[[link_id]].Type[0] + link_type = links.loc[link_id].Type mid_x = [] mid_y = [] # check link type if link_type == "CONDUIT": - depth = float(links.loc[[link_id]].Geom1) - us_link_offset = float(links.loc[[link_id]].InOffset) - ds_link_offset = float(links.loc[[link_id]].OutOffset) + depth = float(links.loc[link_id].Geom1) + us_link_offset = float(links.loc[link_id].InOffset) + ds_link_offset = float(links.loc[link_id].OutOffset) # us_bot_x, us_bot_y = us_x_position + width, us_node_el + us_link_offset ds_bot_x, ds_bot_y = ds_x_position - width, ds_node_el + ds_link_offset @@ -158,10 +158,10 @@ def _add_link_plot(ax, us_x_position, ds_x_position, model, link_set, width=0, g lw=0.75, zorder=0) elif link_type == "ORIFICE": - depth = float(links.loc[[link_id]].Geom1) - us_link_offset = float(links.loc[[link_id]].CrestHeight) - ds_node_el = float(nodes.loc[[us_node]].InvertElev) # Plot it flat - ds_link_offset = float(links.loc[[link_id]].CrestHeight) + depth = float(links.loc[link_id].Geom1) + us_link_offset = float(links.loc[link_id].CrestHeight) + ds_node_el = float(nodes.loc[us_node].InvertElev) # Plot it flat + ds_link_offset = float(links.loc[link_id].CrestHeight) us_bot_x, us_bot_y = us_x_position + width, us_node_el + us_link_offset ds_bot_x, ds_bot_y = ds_x_position - width, ds_node_el + ds_link_offset @@ -186,8 +186,8 @@ def _add_link_plot(ax, us_x_position, ds_x_position, model, link_set, width=0, g lw=0.75, zorder=0) elif link_type == "WEIR": - depth = float(links.loc[[link_id]].Geom1) - us_link_offset = float(links.loc[[link_id]].CrestHeight) + depth = float(links.loc[link_id].Geom1) + us_link_offset = float(links.loc[link_id].CrestHeight) ds_link_offset = 0.0 us_bot_x, us_bot_y = us_x_position + width, us_node_el + us_link_offset @@ -274,17 +274,17 @@ def add_node_labels_plot(ax, model, profile_config, font_size=8, label_y_max = 0 for val in profile_config['nodes']: name = val['id_name'] - invert_el = float(nodes.loc[[name]].InvertElev) + invert_el = float(nodes.loc[name].InvertElev) # Node Type checker if hasattr(model.inp, "junctions"): if name in model.inp.junctions.index: - depth = float(nodes.loc[[name]].MaxDepth) + depth = float(nodes.loc[name].MaxDepth) if hasattr(model.inp, "outfalls"): if name in model.inp.outfalls.index: depth = 0 if hasattr(model.inp, "storage"): if name in model.inp.storage.index: - depth = float(nodes.loc[[name]].MaxD) + depth = float(nodes.loc[name].MaxD) calc = invert_el + depth if calc > label_y_max: @@ -298,17 +298,17 @@ def add_node_labels_plot(ax, model, profile_config, font_size=8, stagger_value = 4 name = val['id_name'] x_offset = val['rolling_x_pos'] - invert_el = float(nodes.loc[[name]].InvertElev) + invert_el = float(nodes.loc[name].InvertElev) # Node Type checker if hasattr(model.inp, "junctions"): if name in model.inp.junctions.index: - depth = float(nodes.loc[[name]].MaxDepth) + depth = float(nodes.loc[name].MaxDepth) if hasattr(model.inp, "outfalls"): if name in model.inp.outfalls.index: depth = 0 if hasattr(model.inp, "storage"): if name in model.inp.storage.index: - depth = float(nodes.loc[[name]].MaxD) + depth = float(nodes.loc[name].MaxD) pos_y = invert_el + depth label = ax.annotate(name, xy=(x_offset, pos_y), xytext=(x_offset, label_y_max + label_offset + stagger_value), diff --git a/swmmio/tests/test_graphics.py b/swmmio/tests/test_graphics.py index 83ff7e8..734a941 100644 --- a/swmmio/tests/test_graphics.py +++ b/swmmio/tests/test_graphics.py @@ -83,7 +83,7 @@ def test_change_crs(): J4-001.1 -70.959423 43.730452 J2-095.1 -70.951378 43.767796 """ - v2_test = pd.read_csv(StringIO(s), index_col=0, delim_whitespace=True, skiprows=[0]) + v2_test = pd.read_csv(StringIO(s), index_col=0, sep=r'\s+', skiprows=[0]) assert v2['X'].values == pytest.approx(v2_test['X'].values, rel=1e-3) assert v2['Y'].values == pytest.approx(v2_test['Y'].values, rel=1e-3) diff --git a/swmmio/utils/dataframes.py b/swmmio/utils/dataframes.py index 95507fb..b5ad1a3 100644 --- a/swmmio/utils/dataframes.py +++ b/swmmio/utils/dataframes.py @@ -104,7 +104,7 @@ def dataframe_from_rpt(rpt_path, section, element_id=None): # extract the string and read into a dataframe s = extract_section_of_file(rpt_path, start_strings, end_strings) - df = pd.read_csv(StringIO(s), header=None, sep='\s+', skiprows=[0], + df = pd.read_csv(StringIO(s), header=None, sep=r'\s+', skiprows=[0], index_col=0, names=cols) # confirm index name is string @@ -164,7 +164,7 @@ def dataframe_from_inp(inp_path, section, additional_cols=None, quote_replace=' return pd.read_csv(StringIO(s), delim_whitespace=False) else: try: - df = pd.read_csv(StringIO(s), header=None, sep='\s+', + df = pd.read_csv(StringIO(s), header=None, sep=r'\s+', skiprows=[0], index_col=0, names=cols) except: raise IndexError(f'failed to parse {section} with cols: {cols}. head:\n{s[:500]}') @@ -225,7 +225,7 @@ def get_inp_options_df(inp_path): ops_tag = '[OPTIONS]' ops_cols = INP_OBJECTS['OPTIONS']['columns'] ops_string = extract_section_of_file(inp_path, ops_tag, INP_SECTION_TAGS, comment=';') - ops_df = pd.read_csv(StringIO(ops_string), header=None, delim_whitespace=True, skiprows=[0], + ops_df = pd.read_csv(StringIO(ops_string), header=None, sep=r'\s+', skiprows=[0], index_col=0, names=ops_cols) return ops_df From 7546f970a0796cf93897b6e90f64be183744c400 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Fri, 27 Sep 2024 14:18:02 -0400 Subject: [PATCH 13/17] fix storage(s) typo in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5759179..3d89f0f 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ m = Model("coolest-model.inp") # pass custom init arguments into the Nodes object instead of using default settings referenced by m.nodes() nodes = Nodes( model=m, - inp_sections=['junctions', 'storages', 'outfalls'], + inp_sections=['junctions', 'storage', 'outfalls'], rpt_sections=['Node Depth Summary', 'Node Inflow Summary'], columns=[ 'InvertElev', 'MaxDepth', 'InitDepth', 'SurchargeDepth', 'MaxTotalInflow', 'coords'] ) From 1a80e7b67671cc37a182cc3311d7cf7761e81bdd Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Wed, 27 Nov 2024 10:28:03 -0500 Subject: [PATCH 14/17] add dirwin5 to AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index e48e09a..f9c82a9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,6 +6,7 @@ Assela Pathirana Bruce Rindahl Bryant E. McDonnell BuczynskiRafal +David Irwin Jackie Fortin-Flefil Jenn Wu Stijn Van Hoey From f9c7212dfb254985d249fac1347473a78bb1d4d1 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Wed, 27 Nov 2024 10:36:05 -0500 Subject: [PATCH 15/17] fix typo in usage docs: --- docs/usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage.md b/docs/usage.md index 186a43e..78eecb7 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -36,7 +36,7 @@ m = Model("coolest-model.inp") # pass custom init arguments into the Nodes object instead of using default settings referenced by m.nodes() nodes = Nodes( model=m, - inp_sections=['junctions', 'storages', 'outfalls'], + inp_sections=['junctions', 'storage', 'outfalls'], rpt_sections=['Node Depth Summary', 'Node Inflow Summary'], columns=[ 'InvertElev', 'MaxDepth', 'InitDepth', 'SurchargeDepth', 'MaxTotalInflow', 'coords'] ) From b4a9269690304fcee9571949f5e042f7cd730001 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Wed, 27 Nov 2024 10:41:07 -0500 Subject: [PATCH 16/17] make copyright dynamic (who cares?) ignore docs artifacts --- .gitignore | 6 +++++- docs/conf.py | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 2e38097..08a3a0a 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,8 @@ _build/ *.thm # env -venv/ \ No newline at end of file +venv/ + +# docs artifacts +docs/_build/ +docs/site/ \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 04dc1cf..778b388 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,6 +14,7 @@ # # from recommonmark.transform import AutoStructify # from m2r import MdInclude +from datetime import datetime import os import sys import swmmio @@ -23,7 +24,7 @@ # -- Project information ----------------------------------------------------- project = 'swmmio' -copyright = '2024, Adam Erispaha' +copyright = f'{datetime.now().year}, Adam Erispaha' author = 'Adam Erispaha' # The short X.Y version From 342e77c2377e6c7474195269ae8161f125f66e94 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Wed, 27 Nov 2024 11:01:48 -0500 Subject: [PATCH 17/17] Set release version --- CHANGELOG.md | 8 ++++++++ README.md | 2 +- swmmio/__init__.py | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70b0528..13d2f61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## Version 0.7.2 (2024/11/27) + +### What's Changed +* Handle several Pandas FutureWarnings, provided by @dirwin5 [PR224](https://github.com/pyswmm/swmmio/pull/224) +* Fix docs build process and update docs layout and theme [PR220](https://github.com/pyswmm/swmmio/pull/220) +* Fixed typos in the README [226](https://github.com/pyswmm/swmmio/pull/226) + + ## Version 0.7.1 (2024/08/19) ### What's Changed diff --git a/README.md b/README.md index 5b14174..0d82aa4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # swmmio -*v0.7.1 (2024/08/19)* +*v0.7.2 (2024/11/27)* [![Build status](https://ci.appveyor.com/api/projects/status/qywujm5w2wm0y2tv/branch/master?svg=true)](https://ci.appveyor.com/project/aerispaha/swmmio/branch/master) ![example workflow](https://github.com/aerispaha/swmmio/actions/workflows/python-app.yml/badge.svg) diff --git a/swmmio/__init__.py b/swmmio/__init__.py index 2f668d0..ab2f912 100644 --- a/swmmio/__init__.py +++ b/swmmio/__init__.py @@ -11,7 +11,7 @@ '''Python SWMM Input/Output Tools''' -VERSION_INFO = (0, 7, 2, 'dev0') +VERSION_INFO = (0, 7, 2) __version__ = '.'.join(map(str, VERSION_INFO)) __author__ = 'Adam Erispaha' __copyright__ = 'Copyright (c) 2024'