├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── feature_request.md │ └── question.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── build_deploy_pages.yml │ ├── build_tests.yml │ └── quick_check.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE.md ├── MANIFEST.in ├── README.md ├── documentation ├── Makefile ├── _static │ ├── comp_leaflet_map.html │ ├── epa_logo.png │ ├── logo.jpg │ ├── snl_logo.png │ ├── tank_head.html │ ├── water_circle.jpg │ ├── water_drop.jpg │ ├── wntr-favicon.svg │ └── wntr.css ├── _templates │ └── autosummary │ │ ├── base.rst │ │ ├── class.rst │ │ ├── exception.rst │ │ └── module.rst ├── acknowledgements.rst ├── acronyms.rst ├── advancedsim.rst ├── attention.rst ├── citations.bib ├── citing_wntr.rst ├── conf.py ├── controls.rst ├── criticality.rst ├── developers.rst ├── disaster_models.rst ├── disclaimer.rst ├── environment.yml ├── examples.rst ├── figures │ ├── cmd_python.png │ ├── connect_lines.png │ ├── damage_state.png │ ├── dataframes.png │ ├── demand_library.png │ ├── demand_library_gaussian.png │ ├── demand_library_resampled.png │ ├── fragility_curve.png │ ├── graph.png │ ├── interactive_network.png │ ├── interactive_timeseries.png │ ├── intersect_demographics.png │ ├── intersect_earthquake.png │ ├── intersect_landslide.png │ ├── leak_demand.png │ ├── network_pga.png │ ├── overview.png │ ├── pipe_split_break.png │ ├── plot_basic_network.png │ ├── plot_folium_network.png │ ├── plot_interactive_timeseries.png │ ├── plot_network.png │ ├── plot_plotly_network.png │ ├── plot_pump_curve.png │ ├── plot_subplot_basic_network.png │ ├── plot_tank_volume_curve.png │ ├── plot_timeseries.png │ ├── plot_valve_segment.png │ ├── plot_valve_segment_attributes.png │ ├── pressure_driven.png │ ├── random_valve_layer.png │ ├── resilience_metrics.png │ ├── sample_elevations.png │ ├── skel_branch.png │ ├── skel_example.png │ ├── skel_hydraulics.png │ ├── skel_parallel.png │ ├── skel_series.png │ ├── snap_lines.png │ ├── snap_points.png │ ├── spyder.png │ ├── state_trans_plot.png │ ├── strategic_valve_layer.png │ ├── use_cases.png │ ├── valve_layer.png │ └── wntr_features.png ├── fragility.rst ├── framework.rst ├── getting_started.rst ├── gis.rst ├── graphics.rst ├── hydraulics.rst ├── index.rst ├── index_latex.rst ├── installation.rst ├── layers.rst ├── libraries.rst ├── license.rst ├── make.bat ├── makedocs.bat ├── makedocs.sh ├── model_io.rst ├── morph.rst ├── networkxgraph.rst ├── options.rst ├── overview.rst ├── reference.rst ├── references.bib ├── resilience.rst ├── resultsobject.rst ├── units.rst ├── userguide.rst ├── users.rst ├── waternetworkmodel.rst ├── waterquality.rst ├── waterquality_msx.rst ├── whatsnew.rst ├── whatsnew │ ├── v0.1.0.rst │ ├── v0.1.1.rst │ ├── v0.1.2.rst │ ├── v0.1.3.rst │ ├── v0.1.4.rst │ ├── v0.1.5.rst │ ├── v0.1.6.rst │ ├── v0.1.7.rst │ ├── v0.2.1.rst │ ├── v0.2.2.1.rst │ ├── v0.2.2.rst │ ├── v0.2.3.rst │ ├── v0.3.0.rst │ ├── v0.3.1.rst │ ├── v0.4.0.rst │ ├── v0.4.1.rst │ ├── v0.4.2.rst │ ├── v0.5.0.rst │ ├── v1.0.0.rst │ ├── v1.1.0.rst │ ├── v1.2.0.rst │ ├── v1.3.0.rst │ ├── v1.3.1.rst │ ├── v1.3.2.rst │ └── v1.4.0.rst └── wntr-api.rst ├── examples ├── basics_tutorial.ipynb ├── data │ ├── Net1_demographic_data.geojson │ ├── Net1_earthquake_data.geojson │ ├── Net1_elevation_data.tif │ ├── Net1_hydrant_data.geojson │ ├── Net1_landslide_data.geojson │ ├── Net1_valve_data.geojson │ ├── Net3_arsenic.msx │ ├── coastal_ky4.inp │ ├── coastal_ky4_storm_surge.tif │ ├── ky10_landslide_data.geojson │ ├── ky4_buildings.geojson │ ├── ky4_disconnected_pipes.geojson │ ├── ky4_disconnected_pumps.geojson │ ├── ky4_elevation.tif │ ├── ky4_junctions.geojson │ ├── ky4_pipes.geojson │ ├── ky4_pumps.geojson │ ├── ky4_reservoirs.geojson │ └── ky4_tanks.geojson ├── earthquake_tutorial.ipynb ├── fire_flow.py ├── fire_flow_tutorial.ipynb ├── getting_started.py ├── getting_started_tutorial.ipynb ├── landslide_tutorial.ipynb ├── model_development_tutorial.ipynb ├── multispecies_tutorial.ipynb ├── networks │ ├── Net1.inp │ ├── Net1.json │ ├── Net2.inp │ ├── Net2.json │ ├── Net3.inp │ ├── Net3.json │ ├── Net6.inp │ ├── Net6.json │ ├── ky10.inp │ └── ky4.inp ├── pipe_break_tutorial.ipynb ├── pipe_criticality.py ├── pipe_segments_tutorial.ipynb ├── salt_water_intrusion_tutorial.ipynb └── stochastic_simulation.py ├── pyproject.toml ├── requirements.txt ├── setup.py └── wntr ├── __init__.py ├── epanet ├── __init__.py ├── exceptions.py ├── io.py ├── libepanet │ ├── __init__.py │ ├── darwin-arm │ │ ├── libepanet2.dylib │ │ └── libepanetmsx.dylib │ ├── darwin-formula │ │ └── libomp.rb │ ├── darwin-x64 │ │ ├── libepanet2.dylib │ │ ├── libepanet20.dylib │ │ ├── libepanet22.dylib │ │ └── libepanetmsx.dylib │ ├── linux-x64 │ │ ├── libepanet2.so │ │ ├── libepanet20.so │ │ ├── libepanet22.so │ │ └── libepanetmsx.so │ └── windows-x64 │ │ ├── epanet2.dll │ │ ├── epanet20.dll │ │ ├── epanet22.dll │ │ └── epanetmsx.dll ├── msx │ ├── __init__.py │ ├── enums.py │ ├── exceptions.py │ ├── io.py │ └── toolkit.py ├── toolkit.py └── util.py ├── gis ├── __init__.py ├── geospatial.py └── network.py ├── graphics ├── __init__.py ├── color.py ├── curve.py ├── layer.py └── network.py ├── library ├── DemandPatternLibrary.json ├── __init__.py ├── demand_library.py └── msx │ ├── __init__.py │ ├── _msxlibrary.py │ ├── arsenic_chloramine.json │ ├── batch_chloramine_decay.json │ ├── lead_ppm.json │ ├── nicotine.json │ └── nicotine_ri.json ├── metrics ├── __init__.py ├── economic.py ├── hydraulic.py ├── misc.py ├── topographic.py └── water_security.py ├── morph ├── __init__.py ├── link.py ├── node.py └── skel.py ├── msx ├── __init__.py ├── base.py ├── elements.py ├── io.py ├── model.py └── options.py ├── network ├── __init__.py ├── base.py ├── controls.py ├── elements.py ├── io.py ├── layer.py ├── model.py └── options.py ├── scenario ├── __init__.py ├── earthquake.py └── fragility_curve.py ├── sim ├── __init__.py ├── aml │ ├── __init__.py │ ├── aml.py │ ├── evaluator.cpp │ ├── evaluator.hpp │ ├── evaluator.i │ ├── evaluator.py │ ├── evaluator_wrap.cpp │ ├── expr.py │ └── numpy.i ├── core.py ├── epanet.py ├── hydraulics.py ├── models │ ├── __init__.py │ ├── constants.py │ ├── constraint.py │ ├── param.py │ ├── utils.py │ └── var.py ├── network_isolation │ ├── __init__.py │ ├── network_isolation.cpp │ ├── network_isolation.hpp │ ├── network_isolation.i │ ├── network_isolation.py │ ├── network_isolation_wrap.cpp │ └── numpy.i ├── results.py └── solvers.py ├── tests ├── __init__.py ├── data_for_testing │ ├── earthquake_people_impacted.csv │ ├── earthquake_people_impacted_wrepair.csv │ ├── fire_flow_junctions_impacted.csv │ ├── fire_flow_people_impacted.csv │ ├── pipe_break_junctions_impacted.csv │ ├── pipe_break_people_impacted.csv │ ├── pump_practice_curves.csv │ ├── segment_break_junctions_impacted.csv │ └── segment_break_people_impacted.csv ├── networks_for_testing │ ├── Anytown.inp │ ├── Anytown_multipointcurves.inp │ ├── Awumah_layout1.inp │ ├── Awumah_layout8.inp │ ├── CCWI17-HermanMahmoud.inp │ ├── Net3.json │ ├── Net6_plus.inp │ ├── Todini_Fig2_optCost_CMH.inp │ ├── Todini_Fig2_optCost_GPM.inp │ ├── Todini_Fig2_solA_CMH.inp │ ├── Todini_Fig2_solA_GPM.inp │ ├── bad_syntax.inp │ ├── bad_times.inp │ ├── bad_values.inp │ ├── conditional_controls_1.inp │ ├── conditional_controls_2.inp │ ├── control_comb.inp │ ├── cv_controls.inp │ ├── epanet_leaks.inp │ ├── fcv_open_no_downstream_sources.inp │ ├── fcv_open_no_upstream_sources.inp │ ├── io.inp │ ├── latin1.inp │ ├── leaks.inp │ ├── link_segments_random.csv │ ├── link_segments_strategic.csv │ ├── msx_example.inp │ ├── msx_example.msx │ ├── node_segments_random.csv │ ├── node_segments_strategic.csv │ ├── prv_closed_no_upstream_sources.inp │ ├── prv_open_no_upstream_sources.inp │ ├── psv_open_no_downstream_sources.inp │ ├── simulator.inp │ ├── skeletonize.inp │ ├── tank_controls_1.inp │ ├── tank_controls_2.inp │ ├── time_controls.inp │ ├── times.inp │ ├── valve_crit_demand.csv │ ├── valve_crit_length.csv │ ├── valve_crit_valve.csv │ ├── valve_layer_random.csv │ ├── valve_layer_stategic_0.csv │ ├── valve_layer_stategic_1.csv │ ├── valve_layer_stategic_2.csv │ ├── valve_layer_stategic_3.csv │ └── valve_layer_stategic_4.csv ├── test_aml.py ├── test_demos.py ├── test_epanet_exceptions.py ├── test_epanet_io.py ├── test_epanet_msx_io.py ├── test_epanet_msx_sim.py ├── test_epanet_msx_tooklit.py ├── test_epanet_toolkit.py ├── test_epanet_units.py ├── test_examples.py ├── test_gis.py ├── test_graphics.py ├── test_library_demand.py ├── test_metrics_demand.py ├── test_metrics_economic.py ├── test_metrics_entropy.py ├── test_metrics_healthimpacts.py ├── test_metrics_population.py ├── test_metrics_pump_cost.py ├── test_metrics_segments.py ├── test_metrics_todini.py ├── test_metrics_valve_criticality.py ├── test_models.py ├── test_morph.py ├── test_msx_elements.py ├── test_multiple_simulations.py ├── test_network.py ├── test_network_controls.py ├── test_network_elements.py ├── test_network_graph.py ├── test_network_layers.py ├── test_network_leaks.py ├── test_network_minor_loss.py ├── test_network_pump_outage.py ├── test_network_valves.py ├── test_sceanrio_earthquake.py ├── test_scenario_fragility_curve.py ├── test_sim_PDD.py ├── test_sim_benchmark.py ├── test_sim_demand_multiplier.py ├── test_sim_performance.py ├── test_sim_reset_conditions.py ├── test_sim_results.py ├── test_sim_waterquality.py └── test_times.py └── utils ├── __init__.py ├── disjoint_mapping.py ├── doc_inheritor.py ├── enumtools.py ├── logger.py ├── ordered_set.py └── polynomial_interpolation.py /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report incorrect behavior 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Summary** 11 | Describe the issue and expected behavior. 12 | 13 | **Example** 14 | Include an example to reproduce the issue. The example can use INP files from the [examples](https://github.com/USEPA/WNTR/tree/main/examples) folder. 15 | 16 | **Environment** 17 | Provide information on your computing environment. 18 | - Operating system: 19 | - Python version: 20 | - WNTR version: 21 | 22 | **Additional context** 23 | [Optional] Add additional context about the issue, including screenshot, figure, or water network model for reproducing the issue. 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a new feature 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Summary** 11 | Describe the feature request, including motivation and potential use cases. 12 | 13 | **Additional context** 14 | [Optional] Add additional context or screenshots about the feature request. 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: General question 3 | about: Ask a question 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Summary** 11 | Describe your question. 12 | 13 | **Example** 14 | [Optional] Include an example. The example can use INP files from the [examples](https://github.com/USEPA/WNTR/tree/main/examples) folder. 15 | 16 | **Environment** 17 | [Optional] Provide information on your computing environment. 18 | - Operating system: 19 | - Python version: 20 | - WNTR version: 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Provide a summary of the proposed changes, describe tests and documentation, and review the acknowledgement below. 2 | 3 | ## Summary 4 | Include issues that are resolved by this pull request. 5 | 6 | ## Tests and documentation 7 | New features require tests and documentation. 8 | 9 | ## Acknowledgement 10 | By contributing to this software project, I acknowledge that I have reviewed the [software quality assurance guidelines](https://usepa.github.io/WNTR/developers.html) and that my contributions are submitted under the [Revised BSD License](https://usepa.github.io/WNTR/license.html). 11 | -------------------------------------------------------------------------------- /.github/workflows/build_deploy_pages.yml: -------------------------------------------------------------------------------- 1 | name: docs 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | name: Build the documentation with Sphinx 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | with: 17 | fetch-depth: 0 18 | - run: git fetch origin main 19 | - name: troubleshooting 20 | run: | 21 | git branch 22 | git remote -v 23 | - uses: actions/setup-python@v2 24 | with: 25 | python-version: '3.11' 26 | - name: Install package 27 | run: | 28 | pip install -e . 29 | pip install -r requirements.txt 30 | - name: Build documentation 31 | run: sphinx-build documentation/ documentation/_build/html 32 | - name: Upload artifact 33 | uses: actions/upload-pages-artifact@v3 34 | with: 35 | path: 'documentation/_build/html' 36 | 37 | deploy: 38 | name: Deploy documentation to GitHub Pages 39 | needs: build 40 | if: github.event_name == 'push' 41 | permissions: 42 | contents: read 43 | pages: write # to deploy to Pages 44 | id-token: write # to verify the deployment originates from an appropriate source 45 | environment: 46 | name: github-pages 47 | url: ${{ steps.deployment.outputs.page_url }} 48 | runs-on: ubuntu-latest 49 | steps: 50 | - name: Setup Pages 51 | uses: actions/configure-pages@v3 52 | - name: Deploy to GitHub Pages 53 | id: deployment 54 | uses: actions/deploy-pages@v4 55 | -------------------------------------------------------------------------------- /.github/workflows/quick_check.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: quick-check 5 | 6 | on: 7 | push: 8 | branches: 9 | - '**' 10 | pull_request: 11 | branches: 12 | - '**' 13 | 14 | jobs: 15 | test: 16 | strategy: 17 | matrix: 18 | python-version: ['3.9', '3.11'] 19 | fail-fast: false 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Set up Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v4 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | - name: Install packages 28 | run: | 29 | python -m pip install --upgrade pip 30 | pip install -r requirements.txt 31 | pip install --upgrade coverage pytest 32 | - name: Install package for development 33 | run: | 34 | python -m pip install -e . 35 | - name: Run tests and coverage (unittests plus doctests) 36 | run: | 37 | coverage run --source=wntr --omit="*/tests/*","*/sim/network_isolation/network_isolation.py","*/sim/aml/evaluator.py" -m pytest -m "not time_consuming" --doctest-modules --doctest-glob="*.rst" wntr 38 | coverage run --source=wntr --omit="*/tests/*","*/sim/network_isolation/network_isolation.py","*/sim/aml/evaluator.py" --append -m pytest --doctest-glob="*.rst" documentation 39 | coverage report --fail-under=70 40 | # coverage run --source=wntr --omit="*/tests/*" --append -m pytest --doctest-glob="*.rst" documentation 41 | 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Developer IDE directories 2 | /.project 3 | 4 | # Spyder project settings 5 | .spyderproject 6 | .spyproject 7 | 8 | # Rope project settings 9 | .ropeproject 10 | 11 | # VS Code project settings 12 | *.code-workspace 13 | /.vscode 14 | 15 | # IPython 16 | profile_default/ 17 | ipython_config.py 18 | 19 | # pyenv 20 | .python-version 21 | 22 | # Environments 23 | .env 24 | .venv 25 | env/ 26 | venv/ 27 | ENV/ 28 | env.bak/ 29 | venv.bak/ 30 | 31 | # Distribution / packaging 32 | .Python 33 | build/ 34 | develop-eggs/ 35 | dist/ 36 | downloads/ 37 | eggs/ 38 | .eggs/ 39 | lib/ 40 | lib64/ 41 | parts/ 42 | sdist/ 43 | var/ 44 | wheels/ 45 | share/python-wheels/ 46 | *.egg-info/ 47 | .installed.cfg 48 | *.egg 49 | docker/ 50 | /.vscode 51 | 52 | # Byte-compiled / optimized / DLL files 53 | __pycache__/ 54 | *.py[cod] 55 | *$py.class 56 | 57 | # Unit test / coverage reports 58 | htmlcov/ 59 | .tox/ 60 | .nox/ 61 | .coverage 62 | .coverage.* 63 | .cache 64 | nosetests.xml 65 | coverage.xml 66 | *.cover 67 | .hypothesis/ 68 | .pytest_cache/ 69 | 70 | # Mac cleanup 71 | **/.DS_Store 72 | 73 | # Other items / test output 74 | temp* 75 | *.pyd 76 | *.pyc 77 | *.egg 78 | *.ipynb 79 | *.html 80 | *.pickle 81 | *.xlsx 82 | 83 | examples/*.inp 84 | examples/*.csv 85 | examples/*.json 86 | examples/*.geojson 87 | wntr/tests/*.png 88 | wntr/tests/*.tif 89 | 90 | # Documentation build files 91 | documentation/_build 92 | documentation/_local 93 | documentation/apidoc 94 | 95 | # WNTR specific 96 | wntr/sim/aml/*.so 97 | wntr/sim/aml/*.dll 98 | wntr/sim/aml/*.dylib 99 | wntr/sim/network_isolation/*.so 100 | wntr/sim/network_isolation/*.dll 101 | wntr/sim/network_isolation/*.dylib 102 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ------------- 3 | Please see the [software quality assurance guidelines](https://usepa.github.io/WNTR/developers.html) for information on how to contribute to WNTR. 4 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include LICENSE.md 3 | include wntr/epanet/libepanet/darwin-arm/* 4 | include wntr/epanet/libepanet/darwin-formula/* 5 | include wntr/epanet/libepanet/darwin-x64/* 6 | include wntr/epanet/libepanet/linux-x64/* 7 | include wntr/epanet/libepanet/windows-x64/* 8 | include wntr/sim/aml/evaluator* 9 | include wntr/sim/aml/numpy.i 10 | include wntr/sim/network_isolation/network_isolation* 11 | include wntr/sim/network_isolation/numpy.i 12 | include wntr/tests/networks_for_testing/*.inp 13 | include wntr/library/msx/*.json 14 | include wntr/library/msx/*.msx 15 | include wntr/library/DemandPatternLibrary.json 16 | -------------------------------------------------------------------------------- /documentation/_static/epa_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/_static/epa_logo.png -------------------------------------------------------------------------------- /documentation/_static/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/_static/logo.jpg -------------------------------------------------------------------------------- /documentation/_static/snl_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/_static/snl_logo.png -------------------------------------------------------------------------------- /documentation/_static/water_circle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/_static/water_circle.jpg -------------------------------------------------------------------------------- /documentation/_static/water_drop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/_static/water_drop.jpg -------------------------------------------------------------------------------- /documentation/_static/wntr.css: -------------------------------------------------------------------------------- 1 | @import url('css/theme.css'); 2 | 3 | /* 4 | .wy-nav-content { 5 | padding: 1.618em 3.236em; 6 | height: 100%; 7 | max-width: 50%; 8 | /* max-width: 800px; */ 9 | /* margin: auto; 10 | } 11 | */ 12 | .wy-table-responsive table td, .wy-table-responsive table th { 13 | white-space: normal; 14 | } 15 | 16 | .wy-table-responsive { 17 | margin-bottom: 24px; 18 | max-width: 100%; 19 | overflow: visible; 20 | } -------------------------------------------------------------------------------- /documentation/_templates/autosummary/base.rst: -------------------------------------------------------------------------------- 1 | {% if objtype == 'property' %} 2 | :orphan: 3 | {% endif %} 4 | 5 | {{ objname | escape | underline}} 6 | 7 | .. rubric:: *module* :mod:`{{ module }}` 8 | 9 | .. currentmodule:: {{ module }} 10 | 11 | {% if objtype == 'property' %} 12 | property 13 | {% endif %} 14 | 15 | .. auto{{ objtype }}:: {{ fullname | replace(module + ".", module + "::") }} 16 | -------------------------------------------------------------------------------- /documentation/_templates/autosummary/class.rst: -------------------------------------------------------------------------------- 1 | {{ objname | escape | underline}} 2 | 3 | .. rubric:: *module* :mod:`{{ module }}` 4 | 5 | .. currentmodule:: {{ module }} 6 | 7 | .. autoclass:: {{ objname }} 8 | 9 | {% block methods %} 10 | {% if methods %} 11 | .. HACK -- the point here is that we don't want this to appear in the output, but the autosummary should still generate the pages. 12 | .. autosummary:: 13 | 14 | {% for item in all_methods %} 15 | {%- if not item.startswith('_') or item in ['__call__'] %} 16 | {{ name }}.{{ item }} 17 | {%- endif -%} 18 | {%- endfor %} 19 | {% endif %} 20 | {% endblock %} 21 | 22 | {% block attributes %} 23 | {% if attributes %} 24 | .. HACK -- the point here is that we don't want this to appear in the output, but the autosummary should still generate the pages. 25 | .. autosummary:: 26 | 27 | {% for item in all_attributes %} 28 | {%- if not item.startswith('_') %} 29 | {{ name }}.{{ item }} 30 | {%- endif -%} 31 | {%- endfor %} 32 | {% endif %} 33 | {% endblock %} 34 | 35 | {% if methods or attributes %} 36 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 37 | {% endif %} 38 | -------------------------------------------------------------------------------- /documentation/_templates/autosummary/exception.rst: -------------------------------------------------------------------------------- 1 | {{ objname | escape | underline}} 2 | 3 | .. rubric:: *module* :mod:`{{ module }}` 4 | 5 | .. currentmodule:: {{ module }} 6 | 7 | .. autoexception:: {{ objname }} 8 | :no-inherited-members: 9 | 10 | {% block methods %} 11 | {% if methods %} 12 | .. HACK -- the point here is that we don't want this to appear in the output, but the autosummary should still generate the pages. 13 | .. autosummary:: 14 | 15 | {% for item in all_methods %} 16 | {%- if not item.startswith('_') or item in ['__call__'] %} 17 | {{ name }}.{{ item }} 18 | {%- endif -%} 19 | {%- endfor %} 20 | {% endif %} 21 | {% endblock %} 22 | 23 | {% block attributes %} 24 | {% if attributes %} 25 | .. HACK -- the point here is that we don't want this to appear in the output, but the autosummary should still generate the pages. 26 | .. autosummary:: 27 | 28 | {% for item in all_attributes %} 29 | {%- if not item.startswith('_') %} 30 | {{ name }}.{{ item }} 31 | {%- endif -%} 32 | {%- endfor %} 33 | {% endif %} 34 | {% endblock %} 35 | -------------------------------------------------------------------------------- /documentation/_templates/autosummary/module.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. automodule:: {{ fullname }} 4 | :exclude-members: {% for item in attributes %}{{ item }}, {% endfor %}{% for item in functions %}{{ item }}, {% endfor %}{% for item in classes %}{{ item }}, {% endfor %}{% for item in exceptions %}{{ item }}, {% endfor %} 5 | 6 | {% block attributes %} 7 | {% if attributes %} 8 | .. rubric:: {{ _('Module Attributes') }} 9 | 10 | .. autosummary:: 11 | :toctree: 12 | :template: autosummary/base.rst 13 | {% for item in attributes %} 14 | {{ item }} 15 | {%- endfor %} 16 | {% endif %} 17 | {% endblock %} 18 | 19 | {% block functions %} 20 | {% if functions %} 21 | .. rubric:: {{ _('Functions') }} 22 | 23 | .. autosummary:: 24 | :nosignatures: 25 | :toctree: 26 | :template: autosummary/base.rst 27 | {% for item in functions %} 28 | {{ item }} 29 | {%- endfor %} 30 | {% endif %} 31 | {% endblock %} 32 | 33 | {% block classes %} 34 | {% if classes %} 35 | .. rubric:: {{ _('Classes') }} 36 | 37 | .. autosummary:: 38 | :nosignatures: 39 | :toctree: 40 | :template: autosummary/class.rst 41 | {% for item in classes %} 42 | {{ item }} 43 | {%- endfor %} 44 | {% endif %} 45 | {% endblock %} 46 | 47 | {% block exceptions %} 48 | {% if exceptions %} 49 | .. rubric:: {{ _('Exceptions') }} 50 | 51 | .. autosummary:: 52 | :nosignatures: 53 | :toctree: 54 | :template: autosummary/exception.rst 55 | {% for item in exceptions %} 56 | {{ item }} 57 | {%- endfor %} 58 | {% endif %} 59 | {% endblock %} 60 | 61 | {% block modules %} 62 | {% if modules %} 63 | .. rubric:: Modules 64 | 65 | .. autosummary:: 66 | :toctree: 67 | :recursive: 68 | :template: autosummary/module.rst 69 | {% for item in modules %} 70 | {{ item }} 71 | {%- endfor %} 72 | {% endif %} 73 | {% endblock %} 74 | -------------------------------------------------------------------------------- /documentation/acknowledgements.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \clearpage 4 | 5 | Acknowledgements 6 | ================ 7 | 8 | WNTR is developed through a collaboration between U.S. Environmental Protection Agency, Sandia National 9 | Laboratories, and the open-source community. The U.S. Environmental Protection Agency acknowledges the 10 | additional contributors to the WNTR tool, which can be found on the WNTR GitHub site at https://github.com/USEPA/WNTR/graphs/contributors. 11 | 12 | The U.S. Environmental Protection Agency acknowledges the technical review of the WNTR software and user manual and/or technical editing provided by the following individuals: 13 | 14 | * Eun Jeong Cha, University of Illinois 15 | * Sudhir Kshirsagar, Global Quality Corp 16 | * Lu Liu, Rice University 17 | * Lina Sela, University of Texas at Austin 18 | * Marti Sinclair, Alion Science and Technology, for Attain 19 | * Riccardo Taormina, Delft University of Technology 20 | 21 | -------------------------------------------------------------------------------- /documentation/acronyms.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \clearpage 4 | \phantomsection 5 | \listoftables 6 | \clearpage 7 | \phantomsection 8 | \listoffigures 9 | \clearpage 10 | 11 | 12 | Abbreviations 13 | ====================================== 14 | 15 | **AML**: algebraic modeling system 16 | 17 | **API**: application programming interface 18 | 19 | **CRS**: coordinate reference system 20 | 21 | **CSV**: comma-separated values 22 | 23 | **DD**: demand-driven `(DDA now the preferred term)` 24 | 25 | **DDA**: demand-driven analysis 26 | 27 | **EPA**: Environmental Protection Agency 28 | 29 | **EPANET**: a water network modeling tool, see :cite:t:`ross00` and :cite:t:`rwts20` 30 | 31 | **GIS**: geographic information system 32 | 33 | **HDF**: Hierarchical Data Format 34 | 35 | **IDE**: integrated development environment 36 | 37 | **INP file**: a text input file for EPANET 38 | 39 | **I/O**: input and output 40 | 41 | **JSON**: JavaScript Object Notation 42 | 43 | **PDA**: pressure-driven analysis 44 | 45 | **PDD**: pressure dependent demand `(PDA now the preferred term)` 46 | 47 | **SCADA**: supervisory control And data acquisition 48 | 49 | **SI**: International System of Units 50 | 51 | **SQL**: Structured Query Language 52 | 53 | **US**: United States 54 | 55 | **UTM**: Universal Transverse Mercator 56 | 57 | **WNTR**: Water Network Tool for Resilience 58 | -------------------------------------------------------------------------------- /documentation/attention.rst: -------------------------------------------------------------------------------- 1 | .. attention:: 2 | Version 1.3.2 is now available. 3 | See `release notes `_ 4 | for more information. 5 | -------------------------------------------------------------------------------- /documentation/citing_wntr.rst: -------------------------------------------------------------------------------- 1 | Citing WNTR 2 | =========== 3 | 4 | To cite WNTR, use one of the following references: 5 | 6 | * Klise, K.A., Hart, D.B., Bynum, M., Hogge, J., Haxton, T., Murray, R., Burkhardt, J. (2020). Water Network Tool for Resilience (WNTR) User Manual: Version 0.2.3. U.S. EPA Office of Research and Development, Washington, DC, EPA/600/R-20/185, 82p. 7 | 8 | * Klise, K.A., Murray, R., Haxton, T. (2018). An overview of the Water Network Tool for Resilience (WNTR), In Proceedings of the 1st International WDSA/CCWI Joint Conference, Kingston, Ontario, Canada, July 23-25, 075, 8p. 9 | 10 | * Klise, K.A., Bynum, M., Moriarty, D., Murray, R. (2017). A software framework for assessing the resilience of drinking water systems to disasters with an example earthquake case study, Environmental Modelling and Software, 95, 420-431, doi: 10.1016/j.envsoft.2017.06.022 11 | 12 | -------------------------------------------------------------------------------- /documentation/criticality.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \clearpage 4 | 5 | .. _criticality: 6 | 7 | Criticality analysis 8 | ================================ 9 | 10 | WNTR can be used for both threat agnostic and threat informed resilience analysis. 11 | The section on :ref:`disaster` describes methods to model threat informed damage to water distribution systems. 12 | In threat agnostic analysis, the cause of the disruption is not modeled directly. 13 | Rather, a series of simulations can be used to perform N-k contingency analysis, where N is the number 14 | of elements and k elements fail. 15 | 16 | In water distribution systems analysis, N-1 contingency analysis is commonly called criticality analysis :cite:p:`wawc06`. 17 | WNTR is commonly used to run criticality analysis, where a series of simulations are run to determine the impact of 18 | individual failures on the system. 19 | This framework can be expanded to include analysis where two or more elements fail at one time or in succession. 20 | Metrics such as water service availability and water pressure are commonly used 21 | to quantify impact. Analysis can include different components, including: 22 | 23 | * Pipe criticality 24 | * Pump criticality 25 | * Segment criticality (based on valve isolation, see :ref:`valvelayer` for more details) 26 | * Fire flow criticality 27 | 28 | In each case, a single element is changed in each simulation. 29 | The pipe, pump, or segment is closed in the case of pipe, pump, and segment criticality. 30 | Demand at hydrants is increased in the case of fire flow criticality. 31 | Summary metrics are collected for each simulation to determine the relative impact of each element. 32 | See :ref:`jupyter_notebooks` for an example on pipe criticality. 33 | 34 | -------------------------------------------------------------------------------- /documentation/disclaimer.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \clearpage 4 | \setcounter{secnumdepth}{0} 5 | 6 | Disclaimer 7 | ====================================== 8 | 9 | .. raw:: latex 10 | 11 | \pagenumbering{roman} 12 | \setcounter{page}{1} 13 | 14 | The United States Environmental Protection Agency through its Office of Research and Development funded and collaborated 15 | in the research described here under an Interagency Agreement # DW8992450201 with the Department of Energy's Sandia National Laboratories. 16 | It has been subjected to the Agency's review and has been approved for publication. Note that approval does not signify that 17 | the contents necessarily reflect the views of the Agency. Mention of trade names products, or services does not convey official 18 | EPA approval, endorsement, or recommendation. The contractor role did not include establishing Agency policy. 19 | 20 | .. raw:: latex 21 | 22 | \vspace{5 mm} 23 | 24 | Sandia National Laboratories is a multimission laboratory managed and operated by National Technology and 25 | Engineering Solutions of Sandia, LLC., a wholly owned subsidiary of Honeywell International, Inc., for the 26 | U.S. Department of Energy's National Nuclear Security Administration under contract DE-NA-0003525. 27 | 28 | -------------------------------------------------------------------------------- /documentation/environment.yml: -------------------------------------------------------------------------------- 1 | name: wntr 2 | dependencies: 3 | - python=3.11 4 | - numpy 5 | - scipy 6 | - networkx 7 | - pandas 8 | - matplotlib 9 | - sphinx 10 | - numpydoc 11 | - docutils<0.17 12 | - sphinx_design 13 | - pydata_sphinx_theme 14 | - sphinxcontrib-bibtex 15 | -------------------------------------------------------------------------------- /documentation/figures/cmd_python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/cmd_python.png -------------------------------------------------------------------------------- /documentation/figures/connect_lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/connect_lines.png -------------------------------------------------------------------------------- /documentation/figures/damage_state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/damage_state.png -------------------------------------------------------------------------------- /documentation/figures/dataframes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/dataframes.png -------------------------------------------------------------------------------- /documentation/figures/demand_library.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/demand_library.png -------------------------------------------------------------------------------- /documentation/figures/demand_library_gaussian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/demand_library_gaussian.png -------------------------------------------------------------------------------- /documentation/figures/demand_library_resampled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/demand_library_resampled.png -------------------------------------------------------------------------------- /documentation/figures/fragility_curve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/fragility_curve.png -------------------------------------------------------------------------------- /documentation/figures/graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/graph.png -------------------------------------------------------------------------------- /documentation/figures/interactive_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/interactive_network.png -------------------------------------------------------------------------------- /documentation/figures/interactive_timeseries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/interactive_timeseries.png -------------------------------------------------------------------------------- /documentation/figures/intersect_demographics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/intersect_demographics.png -------------------------------------------------------------------------------- /documentation/figures/intersect_earthquake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/intersect_earthquake.png -------------------------------------------------------------------------------- /documentation/figures/intersect_landslide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/intersect_landslide.png -------------------------------------------------------------------------------- /documentation/figures/leak_demand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/leak_demand.png -------------------------------------------------------------------------------- /documentation/figures/network_pga.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/network_pga.png -------------------------------------------------------------------------------- /documentation/figures/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/overview.png -------------------------------------------------------------------------------- /documentation/figures/pipe_split_break.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/pipe_split_break.png -------------------------------------------------------------------------------- /documentation/figures/plot_basic_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/plot_basic_network.png -------------------------------------------------------------------------------- /documentation/figures/plot_folium_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/plot_folium_network.png -------------------------------------------------------------------------------- /documentation/figures/plot_interactive_timeseries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/plot_interactive_timeseries.png -------------------------------------------------------------------------------- /documentation/figures/plot_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/plot_network.png -------------------------------------------------------------------------------- /documentation/figures/plot_plotly_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/plot_plotly_network.png -------------------------------------------------------------------------------- /documentation/figures/plot_pump_curve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/plot_pump_curve.png -------------------------------------------------------------------------------- /documentation/figures/plot_subplot_basic_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/plot_subplot_basic_network.png -------------------------------------------------------------------------------- /documentation/figures/plot_tank_volume_curve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/plot_tank_volume_curve.png -------------------------------------------------------------------------------- /documentation/figures/plot_timeseries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/plot_timeseries.png -------------------------------------------------------------------------------- /documentation/figures/plot_valve_segment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/plot_valve_segment.png -------------------------------------------------------------------------------- /documentation/figures/plot_valve_segment_attributes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/plot_valve_segment_attributes.png -------------------------------------------------------------------------------- /documentation/figures/pressure_driven.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/pressure_driven.png -------------------------------------------------------------------------------- /documentation/figures/random_valve_layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/random_valve_layer.png -------------------------------------------------------------------------------- /documentation/figures/resilience_metrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/resilience_metrics.png -------------------------------------------------------------------------------- /documentation/figures/sample_elevations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/sample_elevations.png -------------------------------------------------------------------------------- /documentation/figures/skel_branch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/skel_branch.png -------------------------------------------------------------------------------- /documentation/figures/skel_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/skel_example.png -------------------------------------------------------------------------------- /documentation/figures/skel_hydraulics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/skel_hydraulics.png -------------------------------------------------------------------------------- /documentation/figures/skel_parallel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/skel_parallel.png -------------------------------------------------------------------------------- /documentation/figures/skel_series.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/skel_series.png -------------------------------------------------------------------------------- /documentation/figures/snap_lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/snap_lines.png -------------------------------------------------------------------------------- /documentation/figures/snap_points.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/snap_points.png -------------------------------------------------------------------------------- /documentation/figures/spyder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/spyder.png -------------------------------------------------------------------------------- /documentation/figures/state_trans_plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/state_trans_plot.png -------------------------------------------------------------------------------- /documentation/figures/strategic_valve_layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/strategic_valve_layer.png -------------------------------------------------------------------------------- /documentation/figures/use_cases.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/use_cases.png -------------------------------------------------------------------------------- /documentation/figures/valve_layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/valve_layer.png -------------------------------------------------------------------------------- /documentation/figures/wntr_features.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/documentation/figures/wntr_features.png -------------------------------------------------------------------------------- /documentation/getting_started.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \clearpage 4 | 5 | .. _getting_started: 6 | 7 | Getting started 8 | ====================================== 9 | 10 | To start using WNTR, open a Python console or IDE like Spyder and import the package:: 11 | 12 | import wntr 13 | 14 | WNTR comes with a simple `getting started example `_, 15 | shown below, that uses the `EPANET Example Network 3 (Net3) INP file `_. 16 | 17 | This example demonstrates how to: 18 | 19 | * Import WNTR 20 | * Generate a water network model 21 | * Simulate hydraulics 22 | * Plot simulation results 23 | 24 | .. literalinclude:: ../examples/getting_started.py 25 | 26 | Additional examples of Python code snippets are included throughout the WNTR documentation. The examples provided in the documentation assume 27 | that a user has experience using EPANET (https://www.epa.gov/water-research/epanet) and Python (https://www.python.org/), 28 | including the ability to install and use additional Python packages, such as those listed in :ref:`requirements`. 29 | 30 | See :ref:`examples` for more information on downloading and running examples. 31 | -------------------------------------------------------------------------------- /documentation/index.rst: -------------------------------------------------------------------------------- 1 | .. figure:: _static/logo.jpg 2 | :scale: 10 % 3 | :alt: Logo 4 | 5 | ======================================== 6 | Water Network Tool for Resilience (WNTR) 7 | ======================================== 8 | 9 | The Water Network Tool for Resilience (WNTR) is an EPANET compatible Python package 10 | designed to simulate and analyze resilience of water distribution networks. 11 | 12 | The official WNTR software repository is hosted in the U.S. EPA's GitHub organization 13 | (https://github.com/USEPA/WNTR); releases are available via PyPI and conda-forge 14 | (see :ref:`installation`). 15 | 16 | Key Features in WNTR 17 | ===================== 18 | 19 | .. list-table:: 20 | :widths: 65 35 21 | :header-rows: 0 22 | 23 | * - .. _fig_wntr_features: 24 | .. figure:: figures/wntr_features.png 25 | :width: 750 26 | - .. include:: attention.rst 27 | 28 | .. toctree:: 29 | :maxdepth: 1 30 | :hidden: 31 | 32 | userguide 33 | wntr-api 34 | users 35 | 36 | .. include:: citing_wntr.rst 37 | 38 | US EPA Disclaimer 39 | ================= 40 | 41 | The U.S. Environmental Protection Agency through its Office of Research and Development funded and collaborated 42 | in the research described here under an Interagency Agreement with the Department of Energy's Sandia National Laboratories. 43 | It has been subjected to the Agency's review and has been approved for publication. Note that approval does not signify that 44 | the contents necessarily reflect the views of the Agency. Mention of trade names products, or services does not convey official 45 | EPA approval, endorsement, or recommendation. 46 | 47 | Sandia Funding Statement 48 | ======================== 49 | 50 | Sandia National Laboratories is a multimission laboratory managed and operated by National Technology and 51 | Engineering Solutions of Sandia, LLC., a wholly owned subsidiary of Honeywell International, Inc., for the 52 | U.S. Department of Energy's National Nuclear Security Administration under contract DE-NA-0003525. 53 | 54 | -------------------------------------------------------------------------------- /documentation/index_latex.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | 4 | WNTR documentation 5 | ================================== 6 | 7 | .. toctree:: 8 | :maxdepth: 1 9 | 10 | disclaimer 11 | acronyms 12 | acknowledgements 13 | overview 14 | installation 15 | framework 16 | units 17 | getting_started 18 | examples 19 | waternetworkmodel 20 | model_io 21 | controls 22 | networkxgraph 23 | layers 24 | options 25 | libraries 26 | hydraulics 27 | waterquality 28 | waterquality_msx 29 | resultsobject 30 | disaster_models 31 | criticality 32 | resilience 33 | fragility 34 | morph 35 | graphics 36 | gis 37 | advancedsim 38 | license 39 | users 40 | developers 41 | reference 42 | -------------------------------------------------------------------------------- /documentation/license.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \clearpage 4 | 5 | .. _copyright_license: 6 | 7 | Copyright and license 8 | ================================ 9 | The WNTR Python package is copyright through Sandia National Laboratories. 10 | The software is distributed under the Revised BSD License. 11 | WNTR also leverages a variety of third-party software packages, which 12 | have separate licensing policies. 13 | See `LICENSE.md `_ for 14 | more details. 15 | 16 | Copyright 17 | ------------ 18 | .. code-block:: none 19 | 20 | Copyright 2024 National Technology & Engineering Solutions of Sandia, 21 | LLC (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. 22 | Government retains certain rights in this software. 23 | 24 | Revised BSD license 25 | ------------------------- 26 | .. code-block:: none 27 | 28 | Redistribution and use in source and binary forms, with or without 29 | modification, are permitted provided that the following conditions 30 | are met: 31 | 32 | * Redistributions of source code must retain the above copyright notice, this 33 | list of conditions and the following disclaimer. 34 | * Redistributions in binary form must reproduce the above copyright notice, 35 | this list of conditions and the following disclaimer in the documentation 36 | and/or other materials provided with the distribution. 37 | * Neither the name of Sandia National Laboratories, nor the names of 38 | its contributors may be used to endorse or promote products derived from 39 | this software without specific prior written permission. 40 | 41 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 42 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 43 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 44 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 45 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 46 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 47 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 48 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 49 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 50 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 51 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 52 | -------------------------------------------------------------------------------- /documentation/makedocs.bat: -------------------------------------------------------------------------------- 1 | sphinx-apidoc -f -M --separate -o apidoc ../wntr 2 | make.bat html 3 | -------------------------------------------------------------------------------- /documentation/makedocs.sh: -------------------------------------------------------------------------------- 1 | sphinx-apidoc -f -M --separate -o apidoc ../wntr 2 | pushd apidoc 3 | for file in *.rst 4 | do 5 | sed -e 's/:undoc-members:/:no-undoc-members:/' $file > tmp.txt 6 | mv tmp.txt $file 7 | done 8 | popd 9 | make html 10 | -------------------------------------------------------------------------------- /documentation/options.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \clearpage 4 | 5 | .. _options: 6 | 7 | Options 8 | ================================ 9 | 10 | Water network options are stored in an :class:`~wntr.network.options.Options` 11 | class which divides options into the following sections: 12 | 13 | * :class:`~wntr.network.options.TimeOptions`: Options related to simulation and model timing 14 | * :class:`~wntr.network.options.HydraulicOptions`: Options related to hydraulic modeling 15 | * :class:`~wntr.network.options.QualityOptions`: Options related to water quality modeling 16 | * :class:`~wntr.network.options.ReactionOptions`: Options related to water quality reactions 17 | * :class:`~wntr.network.options.EnergyOptions`: Options related to energy calculations 18 | * :class:`~wntr.network.options.ReportOptions`: Options related to reporting 19 | * :class:`~wntr.network.options.GraphicsOptions`: Options related to graphics 20 | * :class:`~wntr.network.options.UserOptions`: Options defined by the user 21 | 22 | All of these options can be modified in WNTR and then written to an EPANET INP file. 23 | 24 | The options are appended to the WaterNetworkModel. 25 | In the example below, an empty WaterNetworkModel is created and the options 26 | are set to default values. If the WaterNetworkModel is created using an EPANET INP file, 27 | then the options are defined using values from that file. 28 | 29 | .. doctest:: 30 | :hide: 31 | 32 | >>> import wntr 33 | 34 | .. doctest:: 35 | 36 | >>> wn = wntr.network.model.WaterNetworkModel() 37 | >>> wn.options # doctest: +SKIP 38 | 39 | Individual sections are selected as follows. 40 | 41 | .. doctest:: 42 | 43 | >>> wn.options.time # doctest: +SKIP 44 | >>> wn.options.hydraulic # doctest: +SKIP 45 | >>> wn.options.quality # doctest: +SKIP 46 | >>> wn.options.reaction # doctest: +SKIP 47 | >>> wn.options.energy # doctest: +SKIP 48 | >>> wn.options.report # doctest: +SKIP 49 | >>> wn.options.graphics # doctest: +SKIP 50 | >>> wn.options.user # doctest: +SKIP 51 | 52 | Options can be modified, as shown in the example below 53 | (note, duration is in seconds and required pressure is in meters). 54 | 55 | .. doctest:: 56 | 57 | >>> wn.options.time.duration = 86400 58 | >>> wn.options.hydraulic.demand_model = 'PDD' 59 | >>> wn.options.hydraulic.required_pressure = 21.097 # 30 psi = 21.097 m 60 | 61 | Note that EPANET 2.00.12 does not use the demand model, minimum pressure, 62 | required pressure, or pressure exponent from the hydraulic section. 63 | Options that directly apply to hydraulic simulation that are not used in the 64 | WNTRSimulator are described in :ref:`limitations`. 65 | 66 | The easiest way to view options is to print the options as a dictionary. 67 | For example, hydraulic options are shown below. 68 | 69 | .. doctest:: 70 | 71 | >>> print(dict(wn.options.hydraulic)) # doctest: +SKIP 72 | {'accuracy': 0.001, 73 | 'checkfreq': 2, 74 | 'damplimit': 0.0, 75 | 'demand_model': None, 76 | 'demand_multiplier': 1.0, 77 | ... 78 | -------------------------------------------------------------------------------- /documentation/userguide.rst: -------------------------------------------------------------------------------- 1 | .. figure:: _static/logo.jpg 2 | :scale: 10 % 3 | :alt: Logo 4 | 5 | User Guide 6 | ========== 7 | 8 | The Water Network Tool for Resilience (WNTR) is an EPANET compatible Python package 9 | designed to simulate and analyze resilience of water distribution networks. 10 | 11 | US EPA Disclaimer 12 | ----------------- 13 | 14 | The U.S. Environmental Protection Agency through its Office of Research and Development funded and collaborated 15 | in the research described here under an Interagency Agreement with the Department of Energy's Sandia National Laboratories. 16 | It has been subjected to the Agency's review and has been approved for publication. Note that approval does not signify that 17 | the contents necessarily reflect the views of the Agency. Mention of trade names products, or services does not convey official 18 | EPA approval, endorsement, or recommendation. 19 | 20 | Sandia Funding Statement 21 | ------------------------ 22 | 23 | Sandia National Laboratories is a multimission laboratory managed and operated by National Technology and 24 | Engineering Solutions of Sandia, LLC., a wholly owned subsidiary of Honeywell International, Inc., for the 25 | U.S. Department of Energy's National Nuclear Security Administration under contract DE-NA-0003525. 26 | 27 | .. toctree:: 28 | :maxdepth: 1 29 | :hidden: 30 | :caption: Introduction 31 | 32 | overview 33 | installation 34 | framework 35 | units 36 | getting_started 37 | examples 38 | 39 | .. toctree:: 40 | :maxdepth: 1 41 | :hidden: 42 | :caption: Model building 43 | 44 | waternetworkmodel 45 | model_io 46 | controls 47 | networkxgraph 48 | layers 49 | options 50 | libraries 51 | 52 | .. toctree:: 53 | :maxdepth: 1 54 | :hidden: 55 | :caption: Simulation 56 | 57 | hydraulics 58 | waterquality 59 | waterquality_msx 60 | resultsobject 61 | 62 | .. toctree:: 63 | :maxdepth: 1 64 | :hidden: 65 | :caption: Analysis 66 | 67 | disaster_models 68 | criticality 69 | resilience 70 | fragility 71 | morph 72 | graphics 73 | gis 74 | advancedsim 75 | 76 | .. toctree:: 77 | :maxdepth: 1 78 | :hidden: 79 | :caption: Backmatter 80 | 81 | citing_wntr 82 | license 83 | whatsnew 84 | developers 85 | acronyms 86 | reference 87 | -------------------------------------------------------------------------------- /documentation/whatsnew.rst: -------------------------------------------------------------------------------- 1 | Release notes 2 | ================ 3 | 4 | .. _whatsnew_140: 5 | 6 | .. include:: whatsnew/v1.4.0.rst 7 | 8 | .. _whatsnew_132: 9 | 10 | .. include:: whatsnew/v1.3.2.rst 11 | 12 | .. _whatsnew_131: 13 | 14 | .. include:: whatsnew/v1.3.1.rst 15 | 16 | .. _whatsnew_130: 17 | 18 | .. include:: whatsnew/v1.3.0.rst 19 | 20 | .. _whatsnew_120: 21 | 22 | .. include:: whatsnew/v1.2.0.rst 23 | 24 | .. _whatsnew_110: 25 | 26 | .. include:: whatsnew/v1.1.0.rst 27 | 28 | .. _whatsnew_100: 29 | 30 | .. include:: whatsnew/v1.0.0.rst 31 | 32 | .. _whatsnew_050: 33 | 34 | .. include:: whatsnew/v0.5.0.rst 35 | 36 | .. _whatsnew_042: 37 | 38 | .. include:: whatsnew/v0.4.2.rst 39 | 40 | .. _whatsnew_041: 41 | 42 | .. include:: whatsnew/v0.4.1.rst 43 | 44 | .. _whatsnew_040: 45 | 46 | .. include:: whatsnew/v0.4.0.rst 47 | 48 | .. _whatsnew_031: 49 | 50 | .. include:: whatsnew/v0.3.1.rst 51 | 52 | .. _whatsnew_0330: 53 | 54 | .. include:: whatsnew/v0.3.0.rst 55 | 56 | .. _whatsnew_0230: 57 | 58 | .. include:: whatsnew/v0.2.3.rst 59 | 60 | .. _whatsnew_0221: 61 | 62 | .. include:: whatsnew/v0.2.2.1.rst 63 | 64 | .. _whatsnew_0220: 65 | 66 | .. include:: whatsnew/v0.2.2.rst 67 | 68 | .. _whatsnew_0210: 69 | 70 | .. include:: whatsnew/v0.2.1.rst 71 | 72 | .. _whatsnew_0170: 73 | 74 | .. include:: whatsnew/v0.1.7.rst 75 | 76 | .. _whatsnew_0160: 77 | 78 | .. include:: whatsnew/v0.1.6.rst 79 | 80 | .. _whatsnew_0150: 81 | 82 | .. include:: whatsnew/v0.1.5.rst 83 | 84 | .. _whatsnew_0140: 85 | 86 | .. include:: whatsnew/v0.1.4.rst 87 | 88 | .. _whatsnew_0130: 89 | 90 | .. include:: whatsnew/v0.1.3.rst 91 | 92 | .. _whatsnew_0120: 93 | 94 | .. include:: whatsnew/v0.1.2.rst 95 | 96 | .. _whatsnew_0110: 97 | 98 | .. include:: whatsnew/v0.1.1.rst 99 | 100 | .. _whatsnew_0100: 101 | 102 | .. include:: whatsnew/v0.1.0.rst 103 | -------------------------------------------------------------------------------- /documentation/whatsnew/v0.1.0.rst: -------------------------------------------------------------------------------- 1 | v0.1.0 (October 17, 2016) 2 | ------------------------------- 3 | 4 | This is the first official release of WNTR. 5 | Features include basic functionality to: 6 | 7 | * Generate water network models 8 | * Modify network structure and operations 9 | * Add disruptive incident and response/repair strategies 10 | * Simulate network hydraulics using pressure dependent demand or demand-driven hydraulic simulation 11 | * Run probabilistic simulations using fragility curves 12 | * Compute resilience using topographic, hydraulic, water quality/security, and economic metrics 13 | * Analyze results and generate graphics 14 | -------------------------------------------------------------------------------- /documentation/whatsnew/v0.1.1.rst: -------------------------------------------------------------------------------- 1 | v0.1.1 (February 6, 2017) 2 | ------------------------------- 3 | 4 | * Updated package for Python 3.4 and 3.5 compatibility 5 | * Added install requirements to setup.py 6 | * Bug fix in animation example 7 | * Updated documentation -------------------------------------------------------------------------------- /documentation/whatsnew/v0.1.2.rst: -------------------------------------------------------------------------------- 1 | v0.1.2 (May 19, 2017) 2 | --------------------------------------------------- 3 | 4 | * Improved EPANET INP file reader/writer with unit conversions 5 | * Added EPANET binary file reader 6 | * Improved model option handling with the EpanetSimulator 7 | * Added water network compatibility with EPANET INP file SOURCES and RULES 8 | * Restructured code base (API change) 9 | 10 | * Added `epanet` package which contains an epanet toolkit, EPANET INP file reader/writer, and unit conversions. Removed pyepanet package. 11 | * Added `graphics` package which contains functions to plot networks. Renamed draw_graph to plot_network. Added a function to create network graphics using Plotly. 12 | * Reorganized `metrics`, `network`, `scenario`, `sim`, and `utils` packages 13 | * Removed Waterquality class from the scenario package. This functionality has been replaced with Source class in the water network model. 14 | 15 | * Updated documentation -------------------------------------------------------------------------------- /documentation/whatsnew/v0.1.3.rst: -------------------------------------------------------------------------------- 1 | v0.1.3 (October 3, 2017) 2 | --------------------------------------------------- 3 | 4 | * Added method to compute pump energy and cost 5 | * Added methods to plot fragility curves and pump curves 6 | * Bug fix to support 24-hour clocktime format and correct tank volume curve name in EPANET INP files 7 | * Added ability to create network graphics in subplots (API change, see :class:`~wntr.graphics.network.plot_network`) 8 | * Changed argument in the WNTRSimulator specifying demand-driven or pressure dependent demand (API change, see :class:`~wntr.sim.core.WNTRSimulator`) 9 | * Updated use of NetworkX to be compatible v2.0 10 | * Bug fix in method used to split pipes. The updated method modifies the original pipe and retains rules and controls associated with that pipe. (API change, see :class:`~wntr.network.model.WaterNetworkModel.split_pipe`, replaces split_pipe_with_junction) 11 | * Updated documentation 12 | -------------------------------------------------------------------------------- /documentation/whatsnew/v0.1.4.rst: -------------------------------------------------------------------------------- 1 | v0.1.4 (February 23, 2018) 2 | --------------------------------------------------- 3 | 4 | v0.1.4 includes several changes that improve simulation stability and tests to ensure that simulations run using WNTR match EPANET simulations. 5 | In addition to the publicly available software tests on https://travis-ci.org/sandialabs/WNTR, 6 | WNTR is also tested on private servers using several large water utility network models. 7 | 8 | * Added a faster EPANET binary output file reader 9 | * Updated the order in which controls operate to match EPANET 10 | * Updated controls classes to include Control and Rule objects (API change, see :class:`~wntr.network.controls.Control` and :class:`~wntr.network.controls.Rule`) 11 | * Added ability to get the names of all required objects that are queried or acted upon by the control/rule (see :class:`~wntr.network.controls.Control.requires`) 12 | * Modified the structure of the Options object to group options into types (API change, see :class:`~wntr.network.options.Options`) 13 | * Created water network model objects for different types of valves (see 14 | :class:`~wntr.network.elements.PRValve`, 15 | :class:`~wntr.network.elements.PSValve`, 16 | :class:`~wntr.network.elements.PBValve`, 17 | :class:`~wntr.network.elements.FCValve`, 18 | :class:`~wntr.network.elements.TCValve`, and 19 | :class:`~wntr.network.elements.GPValve`) and pumps (see 20 | :class:`~wntr.network.elements.HeadPump` and 21 | :class:`~wntr.network.elements.PowerPump`) 22 | * Created a Pattern object that contains a list of values (see :class:`~wntr.network.elements.Pattern`) 23 | 24 | * A Pattern object can be called to get the pattern value at a specific time 25 | 26 | * Created a TimeSeries object that contains a base value, Pattern object, and category (see :class:`~wntr.network.elements.TimeSeries`) 27 | 28 | * TimeSeries are used to store junction demand, source injection, pricing, pump speed, and reservoir head 29 | * A TimeSeries object can be called to get the timeseries value at a specific time 30 | 31 | * Created a Demands object to store a list of TimeSeries objects (see :class:`~wntr.network.elements.Demands`) 32 | 33 | * Demands are used to store multiple demands at a single junction 34 | * A Demands object can be called to get the total demand at a specific time (does not include the demand multiplier) 35 | * Since a junction can have multiple demands, 'base_demand' is no longer a Junction attribute (API change). The Demands object can be used to extract the base value per demand. 36 | * Expected demand and average daily expected demand can be calculated using new metrics (see :class:`~wntr.metrics.hydraulic.expected_demand` and :class:`~wntr.metrics.hydraulic.average_expected_demand`). 37 | The metric 'average_water_consumed' has been removed. 38 | 39 | * Added support for flow control valves (FCV), multiple demands at a junction, variable reservoir head, and rule timesteps in the WNTRSimulator 40 | * Modified the dependence between the WaterNetworkModel and the NetworkX graph. The graph is now built from scratch when WaterNetworkModel.get_graph() is called. 41 | WaterNetworkModel.get_graph_deep_copy() has been removed (API change, see :class:`~wntr.network.model.WaterNetworkModel.get_graph`). 42 | * Modified the WaterNetworkModel.add_pattern() to no longer accept start_time and end_time options. 43 | Binary patterns can be created using the Patterns object (API change, see :class:`~wntr.network.elements.Pattern.binary_pattern`). 44 | * Added ENsaveinpfile to the EPANET toolkit (see :class:`~wntr.epanet.toolkit.ENepanet.ENsaveinpfile`) 45 | * Updated documentation 46 | -------------------------------------------------------------------------------- /documentation/whatsnew/v0.1.5.rst: -------------------------------------------------------------------------------- 1 | v0.1.5 (May 29, 2018) 2 | --------------------------------------------------- 3 | 4 | * Replaced the use of Pandas Panels with a dictionary of Pandas DataFrames (Pandas is deprecating Panels). 5 | This changes the way users interact with simulation results. 6 | 7 | * Removed 'expected_demand' and 'type' from simulation results. Expected demand can be computed using :class:`~wntr.metrics.hydraulic.expected_demand`. 8 | Node and link type is stored in the WaterNetworkModel and is no longer used to compute metrics. 9 | 10 | * Removed simulation_results example, example code is now embedded in the documentation. 11 | 12 | * Updated metrics to use simulation results in the new format and to clarify names. 13 | 14 | * Input arguments are now more explicit, e.g. pass a DataFrame with junction demands instead of an entire Panel with information that might not be used. 15 | 16 | * Updated the following metric names: changed fdv (fraction of delivered volume) to water_service_availability, 17 | todini to todini_index, cost to annual_network_cost, ghg_emissions to annual_ghg_emissions. 18 | 19 | * Removed the following metrics: fdd (fraction of delivered demand) and fdq (fraction of delivered quality), 20 | these can be computed with simple queries on demand and quality simulation results. 21 | 22 | * Improved error messages when simulation does not converge. 23 | * Updated default options for the WNTRSimulator. 24 | * Bug fix in node registries for the use of patterns. 25 | * Changed default colormap in network graphics from jet to Spectral_r. 26 | * Updated documentation. -------------------------------------------------------------------------------- /documentation/whatsnew/v0.1.6.rst: -------------------------------------------------------------------------------- 1 | v0.1.6 (September 11, 2018) 2 | --------------------------------------------------- 3 | 4 | * Introduced a known discrepancy between the WNTRSimulator and EpanetSimulator 5 | to model pump speed controls. See :ref:`discrepancies`. 6 | 7 | * Pumps have speed settings which are adjustable by controls and/or patterns. 8 | With the EpanetSimulator, controls and patterns adjust the actual speed. 9 | With the WNTRSimulator, pumps have a 'base speed' (similar to junction demand 10 | and reservoir head), controls adjust the base speed, and speed patterns are 11 | a are a multiplier on the base speed. Results from the two simulators 12 | can match by scaling speed patterns and using controls appropriately. 13 | 14 | * Fixed bugs in the EPANET INP file reader/writer that impacted some model files, including 15 | issues with time controls, pump price and pattern, general purpose valves, and 16 | the demand section. 17 | 18 | * Included constant power pumps in annual network cost metric. 19 | 20 | * Updated the way hydraulic and reporting timesteps are handled. If the 21 | reporting timestep is greater than the hydraulic timestep, then it is reset and a 22 | warning message is raised. 23 | 24 | * Restricted software tests to use Plotly version 2.x. Plotly version 3 is not yet 25 | compatible with network graphics. 26 | 27 | * Updated documentation. -------------------------------------------------------------------------------- /documentation/whatsnew/v0.1.7.rst: -------------------------------------------------------------------------------- 1 | v0.1.7 (July 23, 2019) 2 | --------------------------------------------------- 3 | 4 | * Added a module for network morphology (see :class:`~wntr.morph`), which includes methods to 5 | 6 | * Reduce network size through skeletonization (see :class:`~wntr.morph.skel.skeletonize`) 7 | * Scale, translate, and rotate node coordinates (see :class:`~wntr.morph.node.scale_node_coordinates`, 8 | :class:`~wntr.morph.node.translate_node_coordinates`, and :class:`~wntr.morph.node.rotate_node_coordinates`) 9 | * Convert node coordinates between UTM and longitude/latitude (see 10 | :class:`~wntr.morph.node.convert_node_coordinates_UTM_to_longlat` and 11 | :class:`~wntr.morph.node.convert_node_coordinates_longlat_to_UTM`) 12 | * Convert node coordinates to UTM or longitude/latitude (see 13 | :class:`~wntr.morph.node.convert_node_coordinates_to_UTM` and 14 | :class:`~wntr.morph.node.convert_node_coordinates_to_longlat`) 15 | * Split and break pipes (i.e. splits a pipe into two pipes) (see :class:`~wntr.morph.link.split_pipe` and 16 | :class:`~wntr.morph.link.break_pipe`) 17 | * Note that methods to scale node coordinates and split pipes used to reside on the water network model object (API change) 18 | 19 | * Added additional graphics options, including: 20 | 21 | * Interactive leaflet network graphics (see :class:`~wntr.graphics.network.plot_leaflet_network`) 22 | * Network animation (see :class:`~wntr.graphics.network.network_animation`) 23 | 24 | * Fixed bugs in network cost, average expected demand, population, and spectral gap metrics. 25 | * Fixed bug in reading initial water quality from INP files. 26 | * Added a read-only `base_demand` attribute to junctions. Base demand is defined using the first demand in the `demand_timeseries_list`. 27 | * Updated :class:`~wntr.network.model.WaterNetworkModel.query_node_attribute` and :class:`~wntr.network.model.WaterNetworkModel.query_link_attribute` to return a pandas Series instead of a dictionary (API change) 28 | * Added :class:`~wntr.network.model.WaterNetworkModel.describe` to return the number of links, nodes, patterns, etc in a WaterNetworkModel 29 | * Added a pull request template. 30 | * Dropped Travis CI tests for Python 3.4 31 | * Added Travis CI tests for Python 3.7 32 | * Updated tests 33 | * Updated documentation, including installation instructions and a section on network morphology and graphics. 34 | Removed example files and integrated code examples directly into the documentation. -------------------------------------------------------------------------------- /documentation/whatsnew/v0.2.1.rst: -------------------------------------------------------------------------------- 1 | v0.2.1 (Aug 13, 2019) 2 | --------------------------------------------------- 3 | 4 | * Added a c++ extension module for algebraic modeling to facilitate model development and maintenance. This module 5 | 6 | * makes modeling relatively easy but still enables efficient constraint and jacobian evaluations. 7 | * reduces the burden of code maintenance. 8 | * makes the WNTRSimulator more flexible. 9 | 10 | * Added a c++ extension module for efficiently detecting portions of the network that are isolated from tanks and reservoirs. 11 | * Support was added in the WNTRSimulator for 12 | 13 | * PSV valves 14 | * Global demand multipliers 15 | 16 | * Improved the flexibility of controls by adding a ControlManager object. This object tracks changes and ensures that the hydraulic model gets updated appropriately. 17 | * Updated the controls for valves to improve the robustness of the WNTRSimulator. These changes ensure that, for example, when all of the downstream links of a PSV are closed, the PSV gets opened or closed appropriately. 18 | * Fixed a bug in the start_node and end_node properties for links 19 | * Fixed a bug in the controls for PRVs 20 | * Flushed out missing WaterNetworkModel methods (e.g., prv_name_list) 21 | * Dropped support and testing for Python 2 22 | * Updated tests (primarily added new tests for the new c++ extension module for algebraic modeling) 23 | * Added Appveyor testing 24 | * Updated documentation for the new algebraic modeling module 25 | * Added conda-forge distribution mechanism 26 | -------------------------------------------------------------------------------- /documentation/whatsnew/v0.2.2.1.rst: -------------------------------------------------------------------------------- 1 | v0.2.2.1 (June 16, 2020) 2 | --------------------------------------------------- 3 | 4 | * Fixed :class:`~wntr.network.model.WaterNetworkModel.assign_demand`. 5 | The function now reassigns demands using the demand_timeseries_list and uses the demand 6 | multiplier to create a new pattern. 7 | * Fixed issues in WNTRSimulator controls, including 8 | 9 | * Fixed a bug in tank controls that are used when a pipe entering/leaving the tank has a CV 10 | * Fixed a bug in the PSV headloss constraint, which now uses elevation at the start node 11 | * Added a tolerance threshold to ValueCondition and TankLevelCondition 12 | * Added a tolerance threshold to the condition that activates FCV 13 | 14 | * Updated tests 15 | * Updated documentation 16 | 17 | -------------------------------------------------------------------------------- /documentation/whatsnew/v0.2.2.rst: -------------------------------------------------------------------------------- 1 | v0.2.2 (March 23, 2020) 2 | --------------------------------------------------- 3 | 4 | * `WntrMultiDiGraph` class has been removed and WNTR now uses the NetworkX `MultiDiGraph` class directly. 5 | Methods associated with WntrMultiDiGraph have been relocated (API change). 6 | 7 | * :class:`~wntr.network.model.WaterNetworkModel.get_graph` now returns a NetworkX MultiDiGraph. 8 | That method can also be used to return a weighted graph. 9 | The method `weighted_graph` has been removed. 10 | * Topographic metrics that were part of the WntrMultiDiGraph class are now located in the 11 | :class:`~wntr.metrics.topographic` module. 12 | 13 | * Added :class:`~wntr.metrics.topographic.valve_segments` method to groups links and nodes into 14 | segments based on the location of isolation valves. 15 | * Added :class:`~wntr.network.layer.generate_valve_layer` method to generate valve layers 16 | based on random or strategic placement. 17 | * Updated :class:`~wntr.graphics.curve.plot_pump_curve` to include the pump curve based on 18 | head curve coefficients, the optional input argument add_polyfit was removed (API change). 19 | Bug fix in x and y labels. 20 | * Updated :class:`~wntr.graphics.curve.plot_fragility_curve` and :class:`~wntr.graphics.curve.plot_pump_curve` 21 | to use an existing matplotlib axes and return a matplotlib axes so users can customize the graphics. 22 | The optional input argument figsize was removed (API change). 23 | * Added optional input arguments to :class:`~wntr.graphics.network.plot_network` to add labels to node and link colorbars. 24 | * Added optional input argument for detection limit to :class:`~wntr.metrics.water_security.mass_contaminant_consumed` calculation. 25 | The default detection limit for mass consumed, volume consumed, and extent of contamination is 0. 26 | * Efficiency updates for skeletonize and other network morphology functions. 27 | The functions can now make changes to the original water network model or a 28 | deepcopy of the model. 29 | * Added NotImplementedErrors for PBV and GPV valves, when using the WNTRSimualtor 30 | * Updated methods to be compatible with NetworkX 2.4 and Pandas 1.0 31 | * Added required dependencies to setup.py. Required and optional dependencies 32 | are included in requirements.txt 33 | * Dropped testing for Python 3.5 (matplotlib requires Python >= 3.6) 34 | * Updated documentation 35 | -------------------------------------------------------------------------------- /documentation/whatsnew/v0.2.3.rst: -------------------------------------------------------------------------------- 1 | v0.2.3 (September 4, 2020) 2 | --------------------------------------------------- 3 | 4 | * Fixed bug in :class:`~wntr.network.model.WaterNetworkModel.reset_initial_values`. 5 | The method now resets controls and additional network attributes needed to reset the model to initial conditions. 6 | * Fixed bug for valve settings in the EPANET INP file writer, :class:`~wntr.epanet.io.InpFile.write` 7 | * Fixed bug in emitter coefficient unit conversion 8 | * Included conda install instructions 9 | * Added methods to add and remove fire fighting demand to a junction 10 | * Added pipe criticality and fire flow examples 11 | * Minor updates to support NetworkX 2.5 12 | * Added binaries for Python 3.8 13 | * Added testing capabilities through GitHub Actions. This includes a quick check run on Linux using Python 3.8 and a complete build run on Windows, Linux, and MacOS using Python 3.6, 3.7 and 3.8. The GitHub Action tests are initiated after push and pull requests to the master and dev branches. 14 | * Updated tests 15 | * Updated documentation 16 | -------------------------------------------------------------------------------- /documentation/whatsnew/v0.4.0.rst: -------------------------------------------------------------------------------- 1 | v0.4.0 (August 26, 2021) 2 | --------------------------------------------------- 3 | 4 | * Changed the following network component attributes: 5 | 6 | * Pipe ``check_valve_flag`` and ``cv`` attributes were merged and renamed ``check_valve`` 7 | * Pipe, Valve, and Pump ``status`` now refers to the current simulation status and is read-only, the user can set the initial status using ``initial_status`` 8 | * Valve ``setting`` now refers to the current simulation setting and is read-only, the user can set the initial setting using ``initial_setting`` 9 | 10 | * Added slots to water network model options, ``wn.options``, to define available option names. 11 | This update helps eliminate the use of incorrect or deprecated options. 12 | The user can still create custom options under ``wn.options.user``. 13 | 14 | * Added a ``FunctionCondition`` which calls a function to determine if a control needs activated or not. 15 | If the function returns True, then the control is activated. 16 | This class is used internally to check if valves are connected to an upstream or downstream source (reservoir or tank). 17 | The class can also be used directly to define custom controls. 18 | 19 | * Added the ability to use pattern interpolation when running the WNTRSimulator (``wn.options.time.pattern_interpolation``) 20 | Interpolation with a shorter hydraulic timestep can make problems with large changes in patterns (e.g., large changes in demand) easier to solve. 21 | By default, the same step-like behavior from EPANET is used. 22 | 23 | * Removed custom handlers from the EPANET bin filer reader. 24 | 25 | * Added a metric to compute pump energy 26 | 27 | * Added type checking for input into `wn.add_*` methods. 28 | 29 | * Updated the WNTRSimulator link results to include ``setting``. 30 | 31 | * Updated the WNTRSimulator to use ``wn.options.time.start_clocktime``. 32 | 33 | * Updated Net 1, Net 2, and Net 3 network model files to match EPANET versions. 34 | The network files were updated to include a tank overflow entry and 3 digit coordinates. 35 | Hydraulic, water quality, and reporting timestep were also updated in Net 3. 36 | 37 | * Bug fix in io to differentiate between PRESSURE EXPONENT and PRESSURE hydraulic options. 38 | 39 | * Bug fix to enforce EPANET lower limit for required pressure (0.1 in psi or m). 40 | If the user sets a lower limit below 0.1 m, the value of 0.1 m is used in the INP file and a warning is issued. 41 | Note, the lower limit is also the default value in EPANET (and therefore the default for ``wn.options.hydraulic.required_pressure``). 42 | 43 | * Updated documentation example that creates a weighted graph. 44 | 45 | * Updated all tests to use unittest. Removed Travis CI testing framework, all tests are run through GitHub Actions. 46 | -------------------------------------------------------------------------------- /documentation/whatsnew/v0.4.1.rst: -------------------------------------------------------------------------------- 1 | v0.4.1 (March 2, 2022) 2 | --------------------------------------------------- 3 | 4 | * Added a function to compute the modified resilience index, ``wntr.metrics.modified_resilience_index``. 5 | The modified resilience index is a measure of total surplus power. The metric can be computed 6 | as a timeseries for each junction or as a system average timeseries. 7 | `#226 `_ 8 | 9 | * Added a function to compute tank capacity, ``wntr.metrics.tank_capacity``. 10 | Tank capacity is the ratio of water volume to the maximum 11 | water volume for each tank and is reported as a timeseries. 12 | `#226 `_ 13 | 14 | * Added functionality to convert the water network model to a dictionary or JSON formatted file and 15 | create a water network model from a dictionary or JSON formatted file. 16 | The new functionality is located in ``wntr.network.io`` and includes ``to_dict``, ``from_dict``, 17 | ``write_json`` and ``read_json``. These can also be called using methods on the WaterNetworkModel object. 18 | `#233 `_ 19 | 20 | * Updated the WNTRSimulator to use ``wn.options.time.pattern_start``. 21 | `#225 `_ 22 | 23 | * Added the ability to set the random seed when sampling damage states from fragility curves. 24 | `#246 `_ 25 | 26 | * Added methods to update parameters used to define rules and controls. 27 | `#241 `_ 28 | 29 | * Updated ``wntr.morph.split_pipe`` and ``wntr.morph.break_pipe`` to include pipe vertices. 30 | `#248 `_ 31 | 32 | * Updated the EpanetSimulator to be thread safe (only available for EPANET version 2.2). 33 | `#236 `_ 34 | 35 | * Updated rules parsing mechanism for the EPANET INP files. 36 | `#228 `_ 37 | 38 | * Added an assert statement to ensure that the hydraulic, quality, pattern and rule timesteps 39 | are an integer and are not less than 1 second. 40 | `#229 `_ 41 | 42 | * Added the Jupyter Notebook demos into the testing framework. 43 | `#237 `_ 44 | 45 | * Fixed assert statement in add_tank to check for bool, str, or int 46 | `#251 `_ 47 | 48 | * Corrected text in the time series string representation. 49 | `#238 `_ 50 | 51 | * Removed private attribute on pumps associated with power outage controls which is no longer needed. 52 | `#225 `_ 53 | -------------------------------------------------------------------------------- /documentation/whatsnew/v0.4.2.rst: -------------------------------------------------------------------------------- 1 | v0.4.2 (June 23, 2022) 2 | --------------------------------------------------- 3 | 4 | * Bug fix for emitter units `#270 `_ 5 | 6 | * Bug fix for patterns that are all integers `#272 `_ 7 | 8 | * Added plt.show to graphics functions so that the graphics display properly outside Spyder 9 | `#265 `_ 10 | 11 | * Moved sensor placement example to Chama `#270 `_ 12 | 13 | * Added additional demos `#275 `_ 14 | 15 | * Updated documentation and tests `#266 `_, `#267 `_ 16 | -------------------------------------------------------------------------------- /documentation/whatsnew/v0.5.0.rst: -------------------------------------------------------------------------------- 1 | v0.5.0 (November 17, 2022) 2 | --------------------------------------------------- 3 | * Added GIS capabilities in a `wntr.gis` module, which includes the following 4 | `#302 `_, 5 | `#315 `_: 6 | 7 | * Convert between water network models and GIS formatted data (GeoPandas GeoDataFrames) 8 | and GIS formatted files (GeoJSON and Shapefiles) 9 | 10 | * Snap GeoPandas point data to elements in a water network model 11 | 12 | * Find the intersection between GeoPandas points, line or polygons and 13 | elements in a water network model 14 | 15 | * Set and convert GeoDataFrame coordinate reference systems 16 | 17 | * See :ref:`geospatial` section of the user manual for more information. 18 | 19 | * Removed the `read_inpfile`, `write_inpfile`, `read_json`, and `write_json` methods from the WaterNetworkModel. 20 | This functionality is still available using `wntr.network.read_inpfile`, `wntr.network.write_inpfile`, 21 | `wntr.network.read_json` and `wntr.network.write_json` 22 | and is located with other read/write functions `#302 `_. 23 | 24 | * WaterNetworkModel method `get_graph` renamed `to_graph`. Deprecation warning added. 25 | 26 | * Added additional options to the EPANET toolkit, including the ability to set size limits and hydraulic initialization. 27 | Added additional functions, including ENgetnodeid, ENgetnodetype, and ENgetlinktype. 28 | `#298 `_ 29 | 30 | * Added support for Python 3.10, dropped support for Python 3.6. 31 | The build workflow now creates wheel artifacts. 32 | `#287 `_, 33 | `#294 `_ 34 | 35 | * The `_evaluator` and `_network_isolation` binaries are no longer 36 | distributed with the code. The setup.py file now includes an optional argument to build the binaries. 37 | Developer installation instructions have been updated. 38 | `#294 `_, 39 | `#305 `_, 40 | `#311 `_, 41 | `#313 `_, 42 | `#314 `_ 43 | 44 | * Bug fix in pump cost metric `#306 `_ 45 | 46 | * Bug fix in rules when link is active `#301 `_ 47 | 48 | * Updated documentation `#291 `_, 49 | `#292 `_ 50 | -------------------------------------------------------------------------------- /documentation/whatsnew/v1.0.0.rst: -------------------------------------------------------------------------------- 1 | v1.0.0 (March 30, 2023) 2 | --------------------------------------------------- 3 | WNTR version 1.0.0 has undergone extensive testing 4 | with a wide range of water distribution system models 5 | and analysis options. The software has also successfully been 6 | used by external research groups and in analysis that uses large-scale 7 | water distribution system models. See 8 | `User community `_ 9 | for a list of publications and software that uses WNTR. 10 | 11 | * Updated copyright and added EPANET license 12 | `#336 `_. 13 | 14 | * Updated the setup process and documentation 15 | `#335 `_. 16 | 17 | * Bug fix to allow for np.float and np.int in type checking 18 | `#334 `_. 19 | 20 | * Added vertices coordinate transformation functions in :class:`wntr.morph.node` 21 | `#332 `_. 22 | 23 | * Updated the :class:`~wntr.gis.geospatial.intersect` function, results are now sorted 24 | to ensure reproducible tests. Minor updates to documentation 25 | and to address deprecation warnings. 26 | `#328 `_. 27 | 28 | * Bug fix in :class:`~wntr.gis.geospatial.snap` function, previous results could 29 | include false positives 30 | `#327 `_. 31 | 32 | * Efficiency improvements to :class:`~wntr.metrics.topographic.valve_segments` function. 33 | The function now makes use of NetworkX connected components. 34 | `#318 `_. 35 | 36 | * Updated environment variable for CIBW_ENVIRONMENT to build extensions. 37 | `#316 `_. 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /documentation/whatsnew/v1.1.0.rst: -------------------------------------------------------------------------------- 1 | v1.1.0 (November 27, 2023) 2 | --------------------------------------------------- 3 | WNTR version 1.1.0 includes the following updates: 4 | 5 | * Fixed bug in valve test https://github.com/USEPA/WNTR/pull/344 6 | * Updated logo https://github.com/USEPA/WNTR/pull/343 7 | * Updated user manual documentation and a minor change for non-Latin encodings https://github.com/USEPA/WNTR/pull/345 8 | * Updated snap GIS function to use node name as a tie breaker https://github.com/USEPA/WNTR/pull/370 9 | * Ensure variables and parameters keep their values when constraints are removed https://github.com/USEPA/WNTR/pull/360 10 | * Cleaned up Newton Solver https://github.com/USEPA/WNTR/pull/361 11 | * Added GH pages functionality https://github.com/USEPA/WNTR/pull/365 12 | * Documentation updates including column/field names for GeoJSON and Shapefiles https://github.com/USEPA/WNTR/pull/372 13 | * Added link to GitHub pages at https://usepa.github.io/WNTR/ https://github.com/USEPA/WNTR/pull/376 14 | * Added function for reverse links direction https://github.com/USEPA/WNTR/pull/368 15 | * Added vertices from line string geometries when converting GIS object to WN model https://github.com/USEPA/WNTR/pull/388 16 | * Added scheduled testing to workflow https://github.com/USEPA/WNTR/pull/392 17 | * Updated documentation theme https://github.com/USEPA/WNTR/pull/393 18 | -------------------------------------------------------------------------------- /documentation/whatsnew/v1.2.0.rst: -------------------------------------------------------------------------------- 1 | v1.2.0 (June 18, 2024) 2 | --------------------------------------------------- 3 | WNTR version 1.2.0 includes the following updates: 4 | 5 | * Added setuptools and removed readthedocs config https://github.com/USEPA/WNTR/pull/396 6 | * Documentation updates to install WNTR without Anaconda https://github.com/USEPA/WNTR/pull/403 7 | * Added google analytics key https://github.com/USEPA/WNTR/pull/406 8 | * Added EpanetException class and subclasses that allow for cleaner error reporting during IO https://github.com/USEPA/WNTR/pull/381 9 | * Fixed bug caused by units="SI" in a call to write_inp https://github.com/USEPA/WNTR/pull/410 10 | * Fixed bug caused by changes in NetworkX draw function https://github.com/USEPA/WNTR/pull/417 11 | * Added basic and geospatial jupyter notebook demos https://github.com/USEPA/WNTR/pull/419 12 | * Dropped Python 3.7 and 3.8 from testing https://github.com/USEPA/WNTR/pull/419 13 | * Resolved deprecation/future warnings and included GeoPandas in windows build test https://github.com/USEPA/WNTR/pull/423 14 | * Added nodes/pipes to excluded in skeletonization https://github.com/USEPA/WNTR/pull/384 15 | * Fixed bug related to link colormap https://github.com/USEPA/WNTR/pull/429 16 | * Fixed bug in GIS I/O caused by index names https://github.com/USEPA/WNTR/pull/395 17 | * Fixed bug in network_animation https://github.com/USEPA/WNTR/pull/405 18 | * Updated workflow and testing to hold numpy < 2.0 and use macOS-13 https://github.com/USEPA/WNTR/pull/430 19 | -------------------------------------------------------------------------------- /documentation/whatsnew/v1.3.0.rst: -------------------------------------------------------------------------------- 1 | Version 1.3.0 (January 20, 2025) 2 | --------------------------------------------------- 3 | WNTR version 1.3.0 includes the following updates: 4 | 5 | * Removed obsolete EPANET warning by @angusmcb in https://github.com/USEPA/WNTR/pull/436 6 | * Fixed bug caused by GIS files written with column title 'name' by @angusmcb in https://github.com/USEPA/WNTR/pull/435 7 | * Updated workflow actions and forced Fiona<1.10 by @kbonney in https://github.com/USEPA/WNTR/pull/445 8 | * Updated workflows to test documentation by @kbonney in https://github.com/USEPA/WNTR/pull/453 9 | * Updated workflow quick_check to no longer fast-fail by @dbhart in https://github.com/USEPA/WNTR/pull/454 10 | * Added raster sampling function by @kbonney in https://github.com/USEPA/WNTR/pull/446 11 | * Fixed bug in valid GIS names used to create water network models by @kaklise in https://github.com/USEPA/WNTR/pull/452 12 | * Fixed bug in roughness unit conversion when using D-W by @kaklise in https://github.com/USEPA/WNTR/pull/450 13 | * Added base_demand, demand_pattern and demand_category attributes to GIS junction data by @angusmcb in https://github.com/USEPA/WNTR/pull/447 14 | * Fixed bug in documentation by @smaspons in https://github.com/USEPA/WNTR/pull/459 15 | * Fixed bug when using to_gis() with a model that includes a leak by @kbonney in https://github.com/USEPA/WNTR/pull/458 16 | * Added EPANET-MSX support to WNTR by @dbhart in https://github.com/USEPA/WNTR/pull/462 17 | -------------------------------------------------------------------------------- /documentation/whatsnew/v1.3.1.rst: -------------------------------------------------------------------------------- 1 | Version 1.3.1 (January 31, 2025) 2 | --------------------------------------------------- 3 | WNTR version 1.3.1 includes the following updates: 4 | 5 | * Fixed building and testing issues by @kbonney in https://github.com/USEPA/WNTR/pull/467 6 | * Updated documentation by @kaklise in https://github.com/USEPA/WNTR/pull/470 -------------------------------------------------------------------------------- /documentation/whatsnew/v1.3.2.rst: -------------------------------------------------------------------------------- 1 | Version 1.3.2 (March 7, 2025) 2 | --------------------------------------------------- 3 | WNTR version 1.3.2 includes the following updates: 4 | 5 | * Updated API documentation by @wDushanin in https://github.com/USEPA/WNTR/pull/478 and https://github.com/USEPA/WNTR/pull/477 6 | * Fixed release workflow by @kbonney in https://github.com/USEPA/WNTR/pull/481 7 | * Fixed broken links in PULL_REQUEST_TEMPLATE.md by @kbonney in https://github.com/USEPA/WNTR/pull/480 8 | * Fixed check valve syntax by @angusmcb in https://github.com/USEPA/WNTR/pull/482 9 | * Update wheel building to rename linux wheels by @kbonney in https://github.com/USEPA/WNTR/pull/484 10 | -------------------------------------------------------------------------------- /documentation/whatsnew/v1.4.0.rst: -------------------------------------------------------------------------------- 1 | Version 1.4.0 (main) 2 | --------------------------------------------------- 3 | WNTR version 1.4.0 includes the following updates: 4 | 5 | * Updated binaries with the lates msx build 6 | * Added a demand pattern library 7 | * Added the salt water intrusion tutorial 8 | * Added the landslide analysis tutorial 9 | * Minor revisions to Jupyter Notebooks and documentation 10 | -------------------------------------------------------------------------------- /documentation/wntr-api.rst: -------------------------------------------------------------------------------- 1 | .. _api_documentation: 2 | 3 | ================= 4 | API documentation 5 | ================= 6 | 7 | .. automodule:: wntr 8 | :no-members: 9 | :no-undoc-members: 10 | :no-inherited-members: 11 | 12 | .. rubric:: Submodules 13 | 14 | .. autosummary:: 15 | :toctree: apidoc 16 | :recursive: 17 | :template: autosummary/module.rst 18 | 19 | wntr.epanet 20 | wntr.gis 21 | wntr.graphics 22 | wntr.library 23 | wntr.metrics 24 | wntr.morph 25 | wntr.msx 26 | wntr.network 27 | wntr.scenario 28 | wntr.sim 29 | wntr.utils 30 | -------------------------------------------------------------------------------- /examples/data/Net1_earthquake_data.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { "type": "Feature", "properties": { "Pr": 0.5 }, "geometry": { "type": "LineString", "coordinates": [ [ 36.0, 2.0 ], [ 44.0, 44.0 ], [ 85.0, 85.0 ] ] } }, 5 | { "type": "Feature", "properties": { "Pr": 0.75 }, "geometry": { "type": "LineString", "coordinates": [ [ 42.0, 2.0 ], [ 45.0, 27.0 ], [ 38.0, 56.0 ], [ 30.0, 85.0 ] ] } }, 6 | { "type": "Feature", "properties": { "Pr": 0.9 }, "geometry": { "type": "LineString", "coordinates": [ [ 40.0, 2.0 ], [ 50.0, 50.0 ], [ 60.0, 85.0 ] ] } }, 7 | { "type": "Feature", "properties": { "Pr": 0.25 }, "geometry": { "type": "LineString", "coordinates": [ [ 30.0, 2.0 ], [ 35.0, 30.0 ], [ 40.0, 50.0 ], [ 60.0, 80.0 ] ] } } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /examples/data/Net1_elevation_data.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/examples/data/Net1_elevation_data.tif -------------------------------------------------------------------------------- /examples/data/Net1_hydrant_data.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { "type": "Feature", "properties": { "demand": 5000 }, "geometry": { "type": "Point", "coordinates": [ 48.2, 37.2 ] } }, 5 | { "type": "Feature", "properties": { "demand": 1500 }, "geometry": { "type": "Point", "coordinates": [ 71.8, 68.3 ] } }, 6 | { "type": "Feature", "properties": { "demand": 8000 }, "geometry": { "type": "Point", "coordinates": [ 51.2, 71.1 ] } } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /examples/data/Net1_valve_data.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { "type": "Feature", "properties": { }, "geometry": { "type": "Point", "coordinates": [ 56.5, 41.5 ] } }, 5 | { "type": "Feature", "properties": { }, "geometry": { "type": "Point", "coordinates": [ 32.1, 67.6 ] } }, 6 | { "type": "Feature", "properties": { }, "geometry": { "type": "Point", "coordinates": [ 52.7, 86.3 ] } } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /examples/data/Net3_arsenic.msx: -------------------------------------------------------------------------------- 1 | [TITLE] 2 | Arsenic Oxidation/Adsorption Example 3 | 4 | [OPTIONS] 5 | AREA_UNITS M2 ;Surface concentration is mass/m2 6 | RATE_UNITS HR ;Reaction rates are concentration/hour 7 | SOLVER RK5 ;5-th order Runge-Kutta integrator 8 | TIMESTEP 360 ;360 sec (5 min) solution time step 9 | RTOL 0.001 ;Relative concentration tolerance 10 | ATOL 0.0001 ;Absolute concentration tolerance 11 | 12 | [SPECIES] 13 | BULK AS3 UG ;Dissolved arsenite 14 | BULK AS5 UG ;Dissolved arsenate 15 | BULK AStot UG ;Total dissolved arsenic 16 | WALL AS5s UG ;Adsorbed arsenate 17 | BULK NH2CL MG ;Monochloramine 18 | 19 | [COEFFICIENTS] 20 | CONSTANT Ka 10.0 ;Arsenite oxidation rate coefficient 21 | CONSTANT Kb 0.1 ;Monochloramine decay rate coefficient 22 | CONSTANT K1 5.0 ;Arsenate adsorption coefficient 23 | CONSTANT K2 1.0 ;Arsenate desorption coefficient 24 | CONSTANT Smax 50 ;Arsenate adsorption saturation limit 25 | 26 | [TERMS] 27 | Ks K1/K2 ;Equil. adsorption coeff. 28 | 29 | [PIPES] 30 | ;Arsenite oxidation 31 | RATE AS3 -Ka*AS3*NH2CL 32 | ;Arsenate production 33 | RATE AS5 Ka*AS3*NH2CL - Av*(K1*(Smax-AS5s)*AS5 - K2*AS5s) 34 | ;Monochloramine decay 35 | RATE NH2CL -Kb*NH2CL 36 | ;Arsenate adsorption 37 | EQUIL AS5s Ks*Smax*AS5/(1+Ks*AS5) - AS5s 38 | ;Total bulk arsenic 39 | FORMULA AStot AS3 + AS5 40 | 41 | [TANKS] 42 | RATE AS3 -Ka*AS3*NH2CL 43 | RATE AS5 Ka*AS3*NH2CL 44 | RATE NH2CL -Kb*NH2CL 45 | FORMULA AStot AS3 + AS5 46 | 47 | [QUALITY] 48 | ;Initial conditions (= 0 if not specified here) 49 | NODE River AS3 10.0 50 | NODE River NH2CL 2.5 51 | NODE Lake NH2CL 2.5 52 | 53 | [REPORT] 54 | NODES All ;Report results for nodes C and D 55 | LINKS All ;Report results for pipe 5 56 | SPECIES AStot YES ;Report results for each specie 57 | SPECIES AS5 YES 58 | SPECIES AS5s YES 59 | SPECIES NH2CL YES 60 | -------------------------------------------------------------------------------- /examples/data/coastal_ky4_storm_surge.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/examples/data/coastal_ky4_storm_surge.tif -------------------------------------------------------------------------------- /examples/data/ky4_disconnected_pumps.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3547" } }, 4 | "features": [ 5 | { "type": "Feature", "properties": { "name": "~@Pump-1", "initial_status": "Closed", "pump_type": "POWER", "base_speed": 1.0, "power": 111854.9808, "pump_curve_name": null, "speed_pattern_name": null }, "geometry": { "type": "Point", "coordinates": [ 4978752.04, 3915150.0 ] } }, 6 | { "type": "Feature", "properties": { "name": "~@Pump-2", "initial_status": "Open", "pump_type": "POWER", "base_speed": 1.0, "power": 37284.9936, "pump_curve_name": null, "speed_pattern_name": null }, "geometry": { "type": "Point", "coordinates": [ 4979020.21999999973923, 3915339.0 ] } } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /examples/data/ky4_elevation.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/examples/data/ky4_elevation.tif -------------------------------------------------------------------------------- /examples/data/ky4_pumps.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3547" } }, 4 | "features": [ 5 | { "type": "Feature", "properties": { "name": "~@Pump-1", "start_node_name": "I-Pump-1", "end_node_name": "O-Pump-1", "initial_status": "Closed", "pump_type": "POWER", "base_speed": 1.0, "power": 111854.9808, "pump_curve_name": null, "speed_pattern_name": null }, "geometry": { "type": "Point", "coordinates": [ 4978752.04, 3915150.0 ] } }, 6 | { "type": "Feature", "properties": { "name": "~@Pump-2", "start_node_name": "I-Pump-2", "end_node_name": "O-Pump-2", "initial_status": "Open", "pump_type": "POWER", "base_speed": 1.0, "power": 37284.9936, "pump_curve_name": null, "speed_pattern_name": null }, "geometry": { "type": "Point", "coordinates": [ 4979020.21999999973923, 3915339.0 ] } } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /examples/data/ky4_reservoirs.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3547" } }, 4 | "features": [ 5 | { "type": "Feature", "properties": { "name": "R-1", "initial_quality": 0.0, "base_head": 149.3110044, "head_pattern_name": null }, "geometry": { "type": "Point", "coordinates": [ 4978709.0, 3915386.0 ] } } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /examples/data/ky4_tanks.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3547" } }, 4 | "features": [ 5 | { "type": "Feature", "properties": { "name": "T-1", "elevation": 196.940424, "initial_quality": 0.0, "diameter": 17.6784, "init_level": 25.563576, "max_level": 31.659576, "min_level": 24.039576, "min_vol": 0.0, "overflow": "0", "vol_curve_name": null }, "geometry": { "type": "Point", "coordinates": [ 4959474.0, 3897659.0 ] } }, 6 | { "type": "Feature", "properties": { "name": "T-2", "elevation": 207.43922952, "initial_quality": 0.0, "diameter": 14.0208, "init_level": 25.732773528000003, "max_level": 31.82877048, "min_level": 25.732773528000003, "min_vol": 0.0, "overflow": "0", "vol_curve_name": null }, "geometry": { "type": "Point", "coordinates": [ 4972993.0, 3900300.0 ] } }, 7 | { "type": "Feature", "properties": { "name": "T-3", "elevation": 217.7030952, "initial_quality": 0.0, "diameter": 13.4112, "init_level": 30.7089048, "max_level": 33.7569048, "min_level": 27.051298704000001, "min_vol": 0.0, "overflow": "0", "vol_curve_name": null }, "geometry": { "type": "Point", "coordinates": [ 4980614.0, 3906672.0 ] } }, 8 | { "type": "Feature", "properties": { "name": "T-4", "elevation": 220.58034624000001, "initial_quality": 0.0, "diameter": 21.336, "init_level": 29.355659856000003, "max_level": 32.40365376, "min_level": 21.735659856000002, "min_vol": 0.0, "overflow": "0", "vol_curve_name": null }, "geometry": { "type": "Point", "coordinates": [ 4988798.0, 3907639.0 ] } } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /examples/fire_flow.py: -------------------------------------------------------------------------------- 1 | """ 2 | The following example runs hydraulic simulations with and without fire 3 | fighting flow demand added to a single junction. 4 | """ 5 | import wntr 6 | 7 | # Create a water network model and simulate under nominal conditions 8 | inp_file = 'networks/Net3.inp' 9 | wn = wntr.network.WaterNetworkModel(inp_file) 10 | wn.options.hydraulic.demand_model = 'PDD' 11 | 12 | # Add fire demand and simulate 13 | fire_flow_demand = 0.252 # 4000 gal/min = 0.252 m3/s 14 | fire_start = 10*3600 15 | fire_end = 36*3600 16 | node = wn.get_node('197') 17 | node.add_fire_fighting_demand(wn, fire_flow_demand, fire_start, fire_end) 18 | sim = wntr.sim.WNTRSimulator(wn) 19 | fire_results = sim.run_sim() 20 | 21 | # Reset initial values and simulate hydraulics under nominal conditions 22 | wn.reset_initial_values() 23 | node.remove_fire_fighting_demand(wn) 24 | sim = wntr.sim.WNTRSimulator(wn) 25 | results = sim.run_sim() 26 | 27 | # Plot resulting differences on the network 28 | pressure_at_24hr = results.node['pressure'].loc[24*3600, :] 29 | fire_pressure_at_24hr = fire_results.node['pressure'].loc[24*3600, :] 30 | pressure_difference = fire_pressure_at_24hr - pressure_at_24hr 31 | wntr.graphics.plot_network(wn, node_attribute=pressure_difference, node_size=30, 32 | title='Nominal - Fire Fighting \npressure difference at 24 hours') 33 | -------------------------------------------------------------------------------- /examples/getting_started.py: -------------------------------------------------------------------------------- 1 | """ 2 | The following example demonstrates how to import WNTR, create a water 3 | network model from an EPANET INP file, simulate hydraulics, and plot 4 | simulation results on the network. 5 | """ 6 | # Import WNTR 7 | import wntr 8 | 9 | # Create a water network model 10 | inp_file = 'networks/Net3.inp' 11 | wn = wntr.network.WaterNetworkModel(inp_file) 12 | 13 | # Simulate hydraulics 14 | sim = wntr.sim.EpanetSimulator(wn) 15 | results = sim.run_sim() 16 | 17 | # Plot results on the network 18 | pressure_at_5hr = results.node['pressure'].loc[5*3600, :] 19 | wntr.graphics.plot_network(wn, node_attribute=pressure_at_5hr, 20 | node_size=30, title='Pressure at 5 hours') 21 | -------------------------------------------------------------------------------- /examples/getting_started_tutorial.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# WNTR Getting Started Tutorial\n", 8 | "The following tutorial demonstrates how to import WNTR, create a water \n", 9 | "network model from an EPANET INP file, simulate hydraulics, and plot \n", 10 | "simulation results on the network." 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "## Import WNTR" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": null, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "import wntr" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "## Create a water network model\n", 34 | "Create a WaterNetworkModel object from an EPANET INP file" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": null, 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "inp_file = 'networks/Net3.inp'\n", 44 | "wn = wntr.network.WaterNetworkModel(inp_file)" 45 | ] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "metadata": {}, 50 | "source": [ 51 | "## Simulate hydraulics\n", 52 | "Simulate hydraulics using the EpanetSimulator and store results" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "sim = wntr.sim.EpanetSimulator(wn)\n", 62 | "results = sim.run_sim()" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "metadata": {}, 68 | "source": [ 69 | "## Plot results on the network\n", 70 | "Extract pressure at hour 5 and plot a network graphic" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": null, 76 | "metadata": {}, 77 | "outputs": [], 78 | "source": [ 79 | "pressure_at_5hr = results.node['pressure'].loc[5*3600, :]\n", 80 | "ax = wntr.graphics.plot_network(wn, node_attribute=pressure_at_5hr, node_size=30, title='Pressure at 5 hours')" 81 | ] 82 | } 83 | ], 84 | "metadata": { 85 | "kernelspec": { 86 | "display_name": "Python 3 (ipykernel)", 87 | "language": "python", 88 | "name": "python3" 89 | }, 90 | "language_info": { 91 | "codemirror_mode": { 92 | "name": "ipython", 93 | "version": 3 94 | }, 95 | "file_extension": ".py", 96 | "mimetype": "text/x-python", 97 | "name": "python", 98 | "nbconvert_exporter": "python", 99 | "pygments_lexer": "ipython3", 100 | "version": "3.11.7" 101 | } 102 | }, 103 | "nbformat": 4, 104 | "nbformat_minor": 4 105 | } 106 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools", "numpy>=1.21,<2.0"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [tool.pytest.ini_options] 6 | markers = ["time_consuming:excluded from ci quick test"] 7 | addopts = "--doctest-modules" 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Required 2 | numpy>=1.21,<2.0 3 | scipy<1.13.0 4 | networkx 5 | pandas 6 | matplotlib 7 | setuptools 8 | 9 | # Optional 10 | plotly<6.0 11 | folium 12 | utm 13 | openpyxl 14 | geopandas 15 | rasterio 16 | rtree 17 | 18 | # Documentation 19 | sphinx 20 | sphinx_design 21 | sphinx_rtd_theme 22 | pydata_sphinx_theme 23 | sphinxcontrib-bibtex 24 | 25 | # Testing 26 | pytest 27 | nbformat 28 | nbconvert 29 | ipykernel 30 | coverage 31 | -------------------------------------------------------------------------------- /wntr/__init__.py: -------------------------------------------------------------------------------- 1 | from wntr import epanet 2 | from wntr import network 3 | from wntr import morph 4 | from wntr import metrics 5 | from wntr import sim 6 | from wntr import scenario 7 | from wntr import graphics 8 | from wntr import gis 9 | from wntr import library 10 | from wntr import utils 11 | from wntr import msx 12 | 13 | __version__ = '1.4.0' 14 | 15 | __copyright__ = """Copyright 2023-2025 National Technology & Engineering 16 | Solutions of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 17 | with NTESS, the U.S. Government retains certain rights in this software.""" 18 | 19 | __license__ = "Revised BSD License" 20 | 21 | from wntr.utils.logger import start_logging 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /wntr/epanet/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The wntr.epanet package provides EPANET2 compatibility functions for WNTR. 3 | """ 4 | from .io import InpFile #, BinFile, HydFile, RptFile 5 | from .util import FlowUnits, MassUnits, HydParam, QualParam, EN 6 | from . import toolkit, io, util, exceptions, msx 7 | -------------------------------------------------------------------------------- /wntr/epanet/libepanet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/__init__.py -------------------------------------------------------------------------------- /wntr/epanet/libepanet/darwin-arm/libepanet2.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/darwin-arm/libepanet2.dylib -------------------------------------------------------------------------------- /wntr/epanet/libepanet/darwin-arm/libepanetmsx.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/darwin-arm/libepanetmsx.dylib -------------------------------------------------------------------------------- /wntr/epanet/libepanet/darwin-formula/libomp.rb: -------------------------------------------------------------------------------- 1 | class Libomp < Formula 2 | desc "LLVM's OpenMP runtime library" 3 | homepage "https://openmp.llvm.org/" 4 | url "https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.0/openmp-14.0.0.src.tar.xz" 5 | sha256 "28a1cbdd3dfdd331e4ed2dda2b4477fc418e455c883bd0d1d6acc331118e4688" 6 | license "MIT" 7 | 8 | livecheck do 9 | url "https://llvm.org/" 10 | regex(/LLVM (\d+\.\d+\.\d+)/i) 11 | end 12 | 13 | bottle do 14 | sha256 cellar: :any, arm64_monterey: "cf1058b26e1a778e523d51562c99b4145aea1b1cb89f1c60b3315677a86c7a08" 15 | sha256 cellar: :any, arm64_big_sur: "bbf77a1a151f00a18e340ab1f655fb87fe787a85834518f1dc44bf0c52ae7d4c" 16 | sha256 cellar: :any, monterey: "e66d2009d6d205c19499dcb453dfac4376ab6bdba805987be00ddbbab65a0818" 17 | sha256 cellar: :any, big_sur: "ed9dc636a5fc8c2a0cfb1643f7932d742ae4805c3f193a9e56cab7d7cf7342e7" 18 | sha256 cellar: :any, catalina: "c72ce9beecde09052e7eac3550b0286ed9bfb2d14f1dd5954705ab5fb25f231b" 19 | sha256 cellar: :any_skip_relocation, x86_64_linux: "9fe14d5f4c8b472de1fad74278da6ba38da7322775b8a88ac61de0c373c4ad10" 20 | end 21 | 22 | depends_on "cmake" => :build 23 | depends_on :xcode => :build # Sometimes CLT cannot build arm64 24 | uses_from_macos "llvm" => :build 25 | 26 | on_linux do 27 | keg_only "provided by LLVM, which is not keg-only on Linux" 28 | end 29 | 30 | def install 31 | # Disable LIBOMP_INSTALL_ALIASES, otherwise the library is installed as 32 | # libgomp alias which can conflict with GCC's libgomp. 33 | 34 | args = ["-DLIBOMP_INSTALL_ALIASES=OFF"] 35 | args << "-DOPENMP_ENABLE_LIBOMPTARGET=OFF" if OS.linux? 36 | 37 | # Build universal binary 38 | ENV.permit_arch_flags 39 | ENV.runtime_cpu_detection 40 | args << "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" 41 | 42 | system "cmake", "-S", "openmp-#{version}.src", "-B", "build/shared", *std_cmake_args, *args 43 | system "cmake", "--build", "build/shared" 44 | system "cmake", "--install", "build/shared" 45 | 46 | system "cmake", "-S", "openmp-#{version}.src", "-B", "build/static", 47 | "-DLIBOMP_ENABLE_SHARED=OFF", 48 | *std_cmake_args, *args 49 | system "cmake", "--build", "build/static" 50 | system "cmake", "--install", "build/static" 51 | end 52 | 53 | test do 54 | (testpath/"test.cpp").write <<~EOS 55 | #include 56 | #include 57 | int main (int argc, char** argv) { 58 | std::array arr = {0,0}; 59 | #pragma omp parallel num_threads(2) 60 | { 61 | size_t tid = omp_get_thread_num(); 62 | arr.at(tid) = tid + 1; 63 | } 64 | if(arr.at(0) == 1 && arr.at(1) == 2) 65 | return 0; 66 | else 67 | return 1; 68 | } 69 | EOS 70 | system ENV.cxx, "-Werror", "-Xpreprocessor", "-fopenmp", "test.cpp", "-std=c++11", 71 | "-L#{lib}", "-lomp", "-o", "test" 72 | system "./test" 73 | end 74 | end -------------------------------------------------------------------------------- /wntr/epanet/libepanet/darwin-x64/libepanet2.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/darwin-x64/libepanet2.dylib -------------------------------------------------------------------------------- /wntr/epanet/libepanet/darwin-x64/libepanet20.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/darwin-x64/libepanet20.dylib -------------------------------------------------------------------------------- /wntr/epanet/libepanet/darwin-x64/libepanet22.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/darwin-x64/libepanet22.dylib -------------------------------------------------------------------------------- /wntr/epanet/libepanet/darwin-x64/libepanetmsx.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/darwin-x64/libepanetmsx.dylib -------------------------------------------------------------------------------- /wntr/epanet/libepanet/linux-x64/libepanet2.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/linux-x64/libepanet2.so -------------------------------------------------------------------------------- /wntr/epanet/libepanet/linux-x64/libepanet20.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/linux-x64/libepanet20.so -------------------------------------------------------------------------------- /wntr/epanet/libepanet/linux-x64/libepanet22.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/linux-x64/libepanet22.so -------------------------------------------------------------------------------- /wntr/epanet/libepanet/linux-x64/libepanetmsx.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/linux-x64/libepanetmsx.so -------------------------------------------------------------------------------- /wntr/epanet/libepanet/windows-x64/epanet2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/windows-x64/epanet2.dll -------------------------------------------------------------------------------- /wntr/epanet/libepanet/windows-x64/epanet20.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/windows-x64/epanet20.dll -------------------------------------------------------------------------------- /wntr/epanet/libepanet/windows-x64/epanet22.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/windows-x64/epanet22.dll -------------------------------------------------------------------------------- /wntr/epanet/libepanet/windows-x64/epanetmsx.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/epanet/libepanet/windows-x64/epanetmsx.dll -------------------------------------------------------------------------------- /wntr/epanet/msx/__init__.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | The wntr.epanet.msx package provides EPANET-MSX compatibility functions for 4 | WNTR. 5 | 6 | The following environment variable must be set, or the command `set_msx_path` 7 | must be run prior to trying to instantiate the EPANET-MSX toolkit. 8 | 9 | .. envvar:: WNTR_PATH_TO_EPANETMSX 10 | 11 | The full path to the directory where EPANET-MSX has been installed. 12 | Specifically, the directory should contain both toolkit files, epanet2.dll 13 | and epanetmsx.dll (or the appropriate equivalent files for your system 14 | architecture). 15 | """ 16 | 17 | import os as _os 18 | 19 | def set_msx_path(path): 20 | if not _os.path.isdir(path): 21 | raise FileNotFoundError('Directory not found, {}'.format(path)) 22 | _os.environ['WNTR_PATH_TO_EPANETMSX'] = path 23 | 24 | from .io import MsxFile, MsxBinFile 25 | from .toolkit import MSXepanet 26 | 27 | -------------------------------------------------------------------------------- /wntr/gis/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The wntr.gis package contains methods to convert between water network models 3 | and GIS formatted data and geospatial functions to snap data and find intersections. 4 | """ 5 | from wntr.gis.network import WaterNetworkGIS 6 | from wntr.gis.geospatial import snap, intersect, sample_raster, connect_lines 7 | 8 | -------------------------------------------------------------------------------- /wntr/graphics/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The wntr.graphics package contains graphic functions 3 | """ 4 | from wntr.graphics.network import plot_network, plot_interactive_network, plot_leaflet_network, network_animation 5 | from wntr.graphics.layer import plot_valve_layer 6 | from wntr.graphics.curve import plot_fragility_curve, plot_pump_curve, plot_tank_volume_curve 7 | from wntr.graphics.color import custom_colormap, random_colormap 8 | 9 | -------------------------------------------------------------------------------- /wntr/graphics/color.py: -------------------------------------------------------------------------------- 1 | from matplotlib.colors import LinearSegmentedColormap, ListedColormap 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | import logging 5 | 6 | logger = logging.getLogger(__name__) 7 | 8 | def custom_colormap(N, colors=['blue','white','red'], name='custom'): 9 | """ 10 | Create a custom colormap. Default settings creates a colormap named 'custom' 11 | which transitions from blue to white to red. 12 | 13 | Parameters 14 | ----------- 15 | N : int 16 | Number of bins in the colormap. 17 | 18 | colors : list of colors (optional) 19 | Colors can be specified in any way understandable by 20 | matplotlib.colors.ColorConverter.to_rgb(). 21 | 22 | name : str (optional) 23 | Name of the colormap 24 | 25 | Returns 26 | -------- 27 | cmap : matplotlib.colors.LinearSegmentedColormap object 28 | """ 29 | 30 | cmap = LinearSegmentedColormap.from_list(name=name, 31 | colors = colors, 32 | N=N) 33 | return cmap 34 | 35 | def random_colormap(N, colormap='jet', name='random', seed=None): 36 | """ 37 | Create a random ordered colormap. Default settings creates a colormap named 'random' 38 | using the jet colormap. 39 | 40 | Parameters 41 | ----------- 42 | N : int 43 | Number of bins in the colormap. 44 | 45 | colormap : str (optional) 46 | Name of matplotlib colormap 47 | 48 | name : str (optional) 49 | Name of the colormap 50 | 51 | seed : int or None 52 | Random seed 53 | 54 | Returns 55 | -------- 56 | cmap : matplotlib.colors.ListedColormap object 57 | """ 58 | if seed is not None: 59 | np.random.seed(seed) 60 | 61 | vals = np.arange(0,1,1/N) 62 | np.random.shuffle(vals) 63 | cmap = plt.get_cmap(colormap) 64 | cmap_random = ListedColormap(cmap(vals), name=name) 65 | 66 | return cmap_random 67 | -------------------------------------------------------------------------------- /wntr/library/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The wntr.library package contains classes to help define water network models 3 | """ 4 | from .demand_library import DemandPatternLibrary 5 | from . import msx -------------------------------------------------------------------------------- /wntr/library/msx/__init__.py: -------------------------------------------------------------------------------- 1 | from ._msxlibrary import MsxLibrary 2 | -------------------------------------------------------------------------------- /wntr/library/msx/lead_ppm.json: -------------------------------------------------------------------------------- 1 | { 2 | "wntr-version": "", 3 | "name": "lead_ppm", 4 | "title": "Lead Plumbosolvency Model (from Burkhardt et al 2020)", 5 | "description": "Parameters for EPA HPS Simulator Model", 6 | "references": [ 7 | "J. B. Burkhardt, et al. (2020) \"Framework for Modeling Lead in Premise Plumbing Systems Using EPANET\". J Water Resour Plan Manag. 146(12). https://doi.org/10.1061/(asce)wr.1943-5452.0001304 PMID:33627937" 8 | ], 9 | "reaction_system": { 10 | "species": [ 11 | { 12 | "name": "PB2", 13 | "species_type": "bulk", 14 | "units": "ug", 15 | "atol": null, 16 | "rtol": null, 17 | "note": "dissolved lead (Pb)" 18 | } 19 | ], 20 | "constants": [ 21 | { 22 | "name": "M", 23 | "value": 0.117, 24 | "units": "ug * m^(-2) * s^(-1)", 25 | "note": "Desorption rate (ug/m^2/s)" 26 | }, 27 | { 28 | "name": "E", 29 | "value": 140.0, 30 | "units": "ug/L", 31 | "note": "saturation/plumbosolvency level (ug/L)" 32 | } 33 | ], 34 | "parameters": [ 35 | { 36 | "name": "F", 37 | "global_value": 0.0, 38 | "note": "determines which pipes have reactions" 39 | } 40 | ], 41 | "terms": [], 42 | "pipe_reactions": [ 43 | { 44 | "species_name": "PB2", 45 | "expression_type": "rate", 46 | "expression": "F * Av * M * (E - PB2) / E" 47 | } 48 | ], 49 | "tank_reactions": [ 50 | { 51 | "species_name": "PB2", 52 | "expression_type": "rate", 53 | "expression": "0" 54 | } 55 | ] 56 | }, 57 | "network_data": { 58 | "initial_quality": { 59 | "PB2": { 60 | "global_value": 0.0, 61 | "node_values": {}, 62 | "link_values": {} 63 | } 64 | }, 65 | "parameter_values": { 66 | "F": { 67 | "pipe_values": {}, 68 | "tank_values": {} 69 | } 70 | }, 71 | "sources": {}, 72 | "patterns": {} 73 | }, 74 | "options": { 75 | "timestep": 1, 76 | "area_units": "M2", 77 | "rate_units": "SEC", 78 | "solver": "RK5", 79 | "coupling": "NONE", 80 | "rtol": 1e-08, 81 | "atol": 1e-08, 82 | "compiler": "NONE", 83 | "segments": 5000, 84 | "peclet": 1000, 85 | "report": { 86 | "pagesize": null, 87 | "report_filename": null, 88 | "species": { 89 | "PB2": "YES" 90 | }, 91 | "species_precision": { 92 | "PB2": 5 93 | }, 94 | "nodes": "all", 95 | "links": "all" 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /wntr/library/msx/nicotine.json: -------------------------------------------------------------------------------- 1 | { 2 | "wntr-version": "", 3 | "name": "nicotine", 4 | "title": "Nicotine - Chlorine reaction", 5 | "description": null, 6 | "references": [], 7 | "reaction_system": { 8 | "species": [ 9 | { 10 | "name": "Nx", 11 | "species_type": "bulk", 12 | "units": "mg", 13 | "atol": null, 14 | "rtol": null, 15 | "note": "Nicotine" 16 | }, 17 | { 18 | "name": "HOCL", 19 | "species_type": "bulk", 20 | "units": "mg", 21 | "atol": null, 22 | "rtol": null, 23 | "note": "Free chlorine" 24 | } 25 | ], 26 | "constants": [ 27 | { 28 | "name": "kd", 29 | "value": 0.00233, 30 | "units": "min^(-1)", 31 | "note": "decay rate" 32 | }, 33 | { 34 | "name": "K1", 35 | "value": 0.0592, 36 | "units": "L * min^(-1) * mg^(-1)", 37 | "note": "decay constant for chlorine as function of mass(Nic)" 38 | }, 39 | { 40 | "name": "K2", 41 | "value": 0.184, 42 | "units": "L * min^(-1) * mg^(-1)", 43 | "note": "decay constant for nicotine as function of mass(Cl)" 44 | } 45 | ], 46 | "parameters": [], 47 | "terms": [ 48 | { 49 | "name": "RxCl", 50 | "expression": "kd * HOCL + K1 * Nx * HOCL" 51 | }, 52 | { 53 | "name": "RxN", 54 | "expression": "K2 * Nx * HOCL" 55 | } 56 | ], 57 | "pipe_reactions": [ 58 | { 59 | "species_name": "Nx", 60 | "expression_type": "rate", 61 | "expression": "-RxN" 62 | }, 63 | { 64 | "species_name": "HOCL", 65 | "expression_type": "rate", 66 | "expression": "-RxCl" 67 | } 68 | ], 69 | "tank_reactions": [] 70 | }, 71 | "network_data": { 72 | "initial_quality": { 73 | "Nx": { 74 | "global_value": 0.0, 75 | "node_values": {}, 76 | "link_values": {} 77 | }, 78 | "HOCL": { 79 | "global_value": 0.0, 80 | "node_values": {}, 81 | "link_values": {} 82 | } 83 | }, 84 | "parameter_values": {}, 85 | "sources": {}, 86 | "patterns": {} 87 | }, 88 | "options": { 89 | "timestep": 1, 90 | "area_units": "m2", 91 | "rate_units": "min", 92 | "solver": "RK5", 93 | "coupling": "NONE", 94 | "rtol": 0.0001, 95 | "atol": 0.0001, 96 | "compiler": "NONE", 97 | "segments": 5000, 98 | "peclet": 1000, 99 | "report": { 100 | "pagesize": null, 101 | "report_filename": null, 102 | "species": {}, 103 | "species_precision": {}, 104 | "nodes": null, 105 | "links": null 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /wntr/metrics/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The wntr.metrics package contains methods to compute resilience, including 3 | hydraulic, water quality, water security, and economic metrics. Methods to 4 | compute topographic metrics are included in the wntr.network.graph module. 5 | """ 6 | from wntr.metrics.topographic import terminal_nodes, bridges, \ 7 | central_point_dominance, spectral_gap, algebraic_connectivity, \ 8 | critical_ratio_defrag, valve_segments, valve_segment_attributes 9 | from wntr.metrics.hydraulic import expected_demand, average_expected_demand, \ 10 | water_service_availability, todini_index, modified_resilience_index, \ 11 | tank_capacity, entropy 12 | from wntr.metrics.water_security import mass_contaminant_consumed, \ 13 | volume_contaminant_consumed, extent_contaminant 14 | from wntr.metrics.economic import annual_network_cost, annual_ghg_emissions, \ 15 | pump_power, pump_energy, pump_cost 16 | from wntr.metrics.misc import query, population, population_impacted 17 | -------------------------------------------------------------------------------- /wntr/metrics/misc.py: -------------------------------------------------------------------------------- 1 | """ 2 | The wntr.metrics.misc module contains metrics that do not fall into the 3 | topographic, hydraulic, water quality, water security, or economic categories. 4 | """ 5 | from wntr.metrics.hydraulic import average_expected_demand 6 | import logging 7 | 8 | logger = logging.getLogger(__name__) 9 | 10 | def query(arg1, operation, arg2): 11 | """ 12 | Returns a boolean mask using comparison operators, i.e. "arg1 operation arg2". 13 | For example, this can be used to return the node-time pairs 14 | when demand < 90% expected demand. 15 | 16 | Parameters 17 | ----------- 18 | arg1 : pandas DataFrame, pandas Series, numpy array, list, scalar 19 | Argument 1 20 | 21 | operation : numpy ufunc 22 | Numpy universal comparison function, options = np.greater, 23 | np.greater_equal, np.less, np.less_equal, np.equal, np.not_equal 24 | 25 | arg2 : same size and type as arg1, or a scalar 26 | Argument 2 27 | 28 | Returns 29 | ------- 30 | A boolean mask (same size and type as arg1) 31 | """ 32 | try: 33 | mask = operation(arg1, arg2) 34 | except AttributeError: 35 | logger.error('operation(arg1, arg2) failed') 36 | 37 | return mask 38 | 39 | def population(wn, R=0.00000876157): 40 | r""" 41 | Compute population per node, rounded to the nearest integer :cite:p:`usepa15`. 42 | 43 | .. math:: pop=\dfrac{Average\ expected\ demand}{R} 44 | 45 | Parameters 46 | ----------- 47 | wn : wntr WaterNetworkModel 48 | Water network model. The water network model is needed to 49 | get demand timeseries at junctions and options related to 50 | duration, timestep, and demand multiplier. 51 | 52 | R : float (optional, default = 0.00000876157 m3/s = 200 gallons/day) 53 | Average volume of water consumed per capita per day in m3/s 54 | 55 | Returns 56 | ------- 57 | A pandas Series that contains population per node 58 | """ 59 | 60 | ave_ex_dem = average_expected_demand(wn) 61 | pop = ave_ex_dem/R 62 | 63 | return pop.round() 64 | 65 | 66 | def population_impacted(pop, arg1, operation=None, arg2=None): 67 | """ 68 | Computes population impacted using comparison operators. 69 | For example, this can be used to find the population impacted when 70 | demand < 90% expected. 71 | 72 | Parameters 73 | ----------- 74 | pop : pd.Series (index = node names) 75 | A pandas Series that contains population per node 76 | 77 | arg1 : pd.DataFrame (columns = node names) or pd.Series (index = node names) 78 | Argument 1 79 | 80 | operation : numpy.ufunc 81 | Numpy universal comparison function, options = np.greater, 82 | np.greater_equal, np.less, np.less_equal, np.equal, np.not_equal 83 | 84 | arg2 : same size and type as arg1, or a scalar 85 | Argument 2 86 | 87 | Returns 88 | -------- 89 | A pandas Series that contains population impacted per node 90 | """ 91 | mask = query(arg1, operation, arg2) 92 | pop_impacted = mask.multiply(pop) 93 | 94 | return pop_impacted 95 | -------------------------------------------------------------------------------- /wntr/morph/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The wntr.morph package contains methods to modify water network 3 | model morphology, including network skeletonization, modifying 4 | node coordinates, and splitting or breaking pipes. 5 | """ 6 | from wntr.morph.node import scale_node_coordinates, translate_node_coordinates, \ 7 | rotate_node_coordinates, \ 8 | convert_node_coordinates_UTM_to_longlat, \ 9 | convert_node_coordinates_longlat_to_UTM, \ 10 | convert_node_coordinates_to_UTM, \ 11 | convert_node_coordinates_to_longlat 12 | from wntr.morph.link import split_pipe, break_pipe 13 | from wntr.morph.skel import skeletonize 14 | -------------------------------------------------------------------------------- /wntr/msx/__init__.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | The wntr.msx package contains methods to define EPANET Multi-species Extension 4 | (MSX) water quality models. 5 | """ 6 | 7 | from .base import VariableType, SpeciesType, ReactionType, ExpressionType 8 | from .elements import Species, Constant, Parameter, Term, Reaction, HydraulicVariable, MathFunction 9 | from .model import MsxModel 10 | from .options import MsxSolverOptions 11 | 12 | from . import base, elements, model, options, io 13 | -------------------------------------------------------------------------------- /wntr/network/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The wntr.network package contains methods to define a water network model, 3 | network controls, and water network model I/O. 4 | """ 5 | from .base import Node, Link, NodeType, LinkType, LinkStatus 6 | from .elements import Junction, Reservoir, Tank, Pipe, Pump, Valve, Pattern, \ 7 | TimeSeries, Demands, Curve, Source 8 | from .model import WaterNetworkModel 9 | from .layer import generate_valve_layer 10 | from .options import Options 11 | from .controls import Comparison, ControlPriority, TimeOfDayCondition, \ 12 | SimTimeCondition, ValueCondition, TankLevelCondition, RelativeCondition, \ 13 | OrCondition, AndCondition, ControlAction, Control, ControlChecker, \ 14 | ControlChangeTracker, Rule 15 | from .io import to_dict, from_dict, to_gis, from_gis, to_graph, \ 16 | read_inpfile, write_inpfile, \ 17 | read_json, write_json, \ 18 | read_geojson, write_geojson, \ 19 | read_shapefile, write_shapefile 20 | -------------------------------------------------------------------------------- /wntr/network/layer.py: -------------------------------------------------------------------------------- 1 | """ 2 | The wntr.network.layer module includes methods to generate network layers 3 | (information that is not stored in the water network model or the graph). 4 | """ 5 | import numpy as np 6 | import pandas as pd 7 | import random 8 | 9 | def generate_valve_layer(wn, placement_type='strategic', n=1, seed=None): 10 | """ 11 | Generate valve layer data, which can be used in valve segmentation analysis. 12 | 13 | Parameters 14 | ----------- 15 | wn : wntr WaterNetworkModel 16 | A WaterNetworkModel object 17 | 18 | placement_type : string 19 | Options include 'strategic' and 'random'. 20 | 21 | - If 'strategic', n is the number of pipes from each node that do not 22 | contain a valve. In this case, n is generally 0, 1 or 2 23 | (i.e. N, N-1, N-2 valve placement). 24 | - If 'random', then n randomly placed valves are used to define the 25 | valve layer. 26 | 27 | n : int 28 | 29 | - If 'strategic', n is the number of pipes from each node that do not 30 | contain a valve. 31 | - If 'random', n is the number of number of randomly placed valves. 32 | 33 | seed : int or None 34 | Random seed 35 | 36 | Returns 37 | --------- 38 | valve_layer : pandas DataFrame 39 | Valve layer, defined by node and link pairs (for example, valve 0 is 40 | on link A and protects node B). The valve_layer DataFrame is indexed by 41 | valve number, with columns named 'node' and 'link'. 42 | """ 43 | 44 | if seed is not None: 45 | np.random.seed(seed) 46 | random.seed(seed) 47 | valve_layer = [] 48 | if placement_type=='random': 49 | all_valves = [] 50 | for pipe_name, pipe in wn.pipes(): 51 | all_valves.append((pipe_name, pipe.start_node_name)) 52 | all_valves.append((pipe_name, pipe.end_node_name)) 53 | 54 | for valve_tuple in random.sample(all_valves, n): 55 | pipe_name, node_name = valve_tuple 56 | valve_layer.append([pipe_name, node_name]) 57 | 58 | elif placement_type == 'strategic': 59 | for node_name, node in wn.nodes(): 60 | links = wn.get_links_for_node(node_name) 61 | for l in np.random.choice(links, max(len(links)-n,0), replace=False): 62 | valve_layer.append([l, node_name]) 63 | 64 | valve_layer = pd.DataFrame(valve_layer, columns=['link', 'node']) 65 | 66 | return valve_layer -------------------------------------------------------------------------------- /wntr/scenario/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The wntr.scenario package contains methods to define disaster scenarios and 3 | fragility/survival curves. 4 | """ 5 | from wntr.scenario.earthquake import Earthquake 6 | from wntr.scenario.fragility_curve import FragilityCurve -------------------------------------------------------------------------------- /wntr/sim/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The wntr.sim package contains methods to run hydraulic and water quality 3 | simulations using the water network model. 4 | """ 5 | from wntr.sim.core import WaterNetworkSimulator, WNTRSimulator 6 | from wntr.sim.results import SimulationResults 7 | from wntr.sim.solvers import NewtonSolver 8 | from wntr.sim.epanet import EpanetSimulator -------------------------------------------------------------------------------- /wntr/sim/aml/__init__.py: -------------------------------------------------------------------------------- 1 | """WNTR's algebraic modeling language module (SWIG).""" 2 | 3 | from .expr import Var, Param, exp, log, sin, cos, tan, asin, acos, atan, inequality, sign, abs, value, ConditionalExpression 4 | from .aml import Model, ParamDict, VarDict, ConstraintDict, Constraint 5 | 6 | -------------------------------------------------------------------------------- /wntr/sim/aml/evaluator.i: -------------------------------------------------------------------------------- 1 | %module evaluator 2 | %include exception.i 3 | 4 | %{ 5 | #define SWIG_FILE_WITH_INIT 6 | #include "evaluator.hpp" 7 | %} 8 | 9 | %exception 10 | { 11 | try 12 | { 13 | $action 14 | } 15 | catch (StructureException &e) 16 | { 17 | std::string s("Evaluator error: "), s2(e.what()); 18 | s = s + s2; 19 | SWIG_exception(SWIG_RuntimeError, s.c_str()); 20 | } 21 | catch (...) 22 | { 23 | SWIG_exception(SWIG_RuntimeError, "unkown exception"); 24 | } 25 | } 26 | 27 | %include "numpy.i" 28 | %init %{ 29 | import_array(); 30 | %} 31 | 32 | %apply (double *ARGOUT_ARRAY1, int DIM1) {(double *array_out, int array_length_out)} 33 | %apply (double *ARGOUT_ARRAY1, int DIM1) {(double *values_array_out, int values_array_length_out)} 34 | %apply (int *ARGOUT_ARRAY1, int DIM1) {(int *col_ndx_array_out, int col_ndx_array_length_out)} 35 | %apply (int *ARGOUT_ARRAY1, int DIM1) {(int *row_nnz_array_out, int row_nnz_array_length_out)} 36 | %apply (double *IN_ARRAY1, int DIM1) {(double *array_in, int array_length_in)} 37 | 38 | %include "evaluator.hpp" 39 | -------------------------------------------------------------------------------- /wntr/sim/aml/evaluator.py: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by SWIG (http://www.swig.org). 2 | # Version 4.0.2 3 | # 4 | # Do not make changes to this file unless you know what you are doing--modify 5 | # the SWIG interface file instead. 6 | 7 | from sys import version_info as _swig_python_version_info 8 | if _swig_python_version_info < (2, 7, 0): 9 | raise RuntimeError("Python 2.7 or later required") 10 | 11 | # Pull in all the attributes from the low-level C/C++ module 12 | if __package__ or "." in __name__: 13 | from ._evaluator import * 14 | else: 15 | from _evaluator import * 16 | 17 | try: 18 | import builtins as __builtin__ 19 | except ImportError: 20 | import __builtin__ 21 | 22 | def _swig_repr(self): 23 | try: 24 | strthis = "proxy of " + self.this.__repr__() 25 | except __builtin__.Exception: 26 | strthis = "" 27 | return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) 28 | 29 | 30 | def _swig_setattr_nondynamic_instance_variable(set): 31 | def set_instance_attr(self, name, value): 32 | if name == "thisown": 33 | self.this.own(value) 34 | elif name == "this": 35 | set(self, name, value) 36 | elif hasattr(self, name) and isinstance(getattr(type(self), name), property): 37 | set(self, name, value) 38 | else: 39 | raise AttributeError("You cannot add instance attributes to %s" % self) 40 | return set_instance_attr 41 | 42 | 43 | def _swig_setattr_nondynamic_class_variable(set): 44 | def set_class_attr(cls, name, value): 45 | if hasattr(cls, name) and not isinstance(getattr(cls, name), property): 46 | set(cls, name, value) 47 | else: 48 | raise AttributeError("You cannot add class attributes to %s" % cls) 49 | return set_class_attr 50 | 51 | 52 | def _swig_add_metaclass(metaclass): 53 | """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass""" 54 | def wrapper(cls): 55 | return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy()) 56 | return wrapper 57 | 58 | 59 | class _SwigNonDynamicMeta(type): 60 | """Meta class to enforce nondynamic attributes (no new attributes) for a class""" 61 | __setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__) 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /wntr/sim/models/__init__.py: -------------------------------------------------------------------------------- 1 | """Elements of the WNTRSimulator model.""" 2 | 3 | from wntr.sim.models import constants, param, var, constraint 4 | -------------------------------------------------------------------------------- /wntr/sim/models/constants.py: -------------------------------------------------------------------------------- 1 | """Contant values used by WNTRSimulator.""" 2 | 3 | import logging 4 | from wntr.utils.polynomial_interpolation import cubic_spline 5 | 6 | logger = logging.getLogger(__name__) 7 | 8 | 9 | def hazen_williams_constants(m): 10 | m.hw_k = 10.666829500036352 11 | m.hw_exp = 1.852 12 | m.hw_minor_exp = 2 13 | 14 | m.hw_q1 = 0.0002 15 | m.hw_q2 = 0.0004 16 | m.hw_m = 0.001 17 | 18 | x1 = m.hw_q1 19 | x2 = m.hw_q2 20 | f1 = m.hw_m * m.hw_q1 21 | f2 = m.hw_q2 ** m.hw_exp 22 | df1 = m.hw_m 23 | df2 = m.hw_exp * m.hw_q2 ** (m.hw_exp - 1) 24 | a, b, c, d = cubic_spline(x1, x2, f1, f2, df1, df2) 25 | m.hw_a = a 26 | m.hw_b = b 27 | m.hw_c = c 28 | m.hw_d = d 29 | 30 | 31 | def darcy_weisbach_constants(m): 32 | m.dw_k = 0.0826 33 | 34 | 35 | def pdd_constants(m): 36 | m.pdd_smoothing_delta = 0.05 37 | m.pdd_slope = 1e-11 38 | 39 | 40 | def head_pump_constants(m): 41 | m.pump_q1 = 0.0 42 | m.pump_q2 = 1e-8 43 | m.pump_slope = -1e-11 44 | 45 | 46 | def leak_constants(m): 47 | m.leak_delta = 1e-4 48 | m.leak_slope = 1e-11 49 | -------------------------------------------------------------------------------- /wntr/sim/models/utils.py: -------------------------------------------------------------------------------- 1 | """Utilities for the WNTRSimulator model.""" 2 | 3 | from wntr.utils.ordered_set import OrderedDict, OrderedSet 4 | from six import with_metaclass 5 | import abc 6 | 7 | 8 | class ModelUpdater(object): 9 | def __init__(self): 10 | self.update_functions = OrderedDict() 11 | 12 | def add(self, obj, attr, func): 13 | if (obj, attr) not in self.update_functions: 14 | self.update_functions[(obj, attr)] = OrderedSet() 15 | self.update_functions[(obj, attr)].add(func) 16 | 17 | def update(self, m, wn, obj, attr): 18 | if (obj, attr) in self.update_functions: 19 | for func in self.update_functions[(obj, attr)]: 20 | func(m, wn, self, obj, attr) 21 | 22 | 23 | class Definition(with_metaclass(abc.ABCMeta, object)): 24 | @classmethod 25 | @abc.abstractmethod 26 | def build(cls, m, wn, updater, index_over=None): 27 | pass 28 | 29 | @classmethod 30 | def update(cls, m, wn, updater, obj, attr): 31 | cls.build(m, wn, updater, index_over=[obj.name]) 32 | 33 | 34 | -------------------------------------------------------------------------------- /wntr/sim/models/var.py: -------------------------------------------------------------------------------- 1 | """Functions to add variables to the WNTRSimulator model.""" 2 | 3 | import logging 4 | from wntr.sim import aml 5 | 6 | logger = logging.getLogger(__name__) 7 | 8 | 9 | def demand_var(m, wn, index_over=None): 10 | """ 11 | Add a demand variable to the model 12 | 13 | Parameters 14 | ---------- 15 | m: wntr.sim.aml.aml.Model 16 | wn: wntr.network.model.WaterNetworkModel 17 | index_over: list of str 18 | list of junction names 19 | """ 20 | if not hasattr(m, 'demand'): 21 | m.demand = aml.VarDict() 22 | 23 | if index_over is None: 24 | index_over = wn.junction_name_list 25 | 26 | demand_multiplier = wn.options.hydraulic.demand_multiplier 27 | pattern_start = wn.options.time.pattern_start 28 | 29 | for node_name in index_over: 30 | node = wn.get_node(node_name) 31 | m.demand[node_name] = aml.Var(node.demand_timeseries_list.at(wn.sim_time+pattern_start, multiplier=demand_multiplier)) 32 | 33 | 34 | def flow_var(m, wn, index_over=None): 35 | """ 36 | Add a flow variable to the model 37 | 38 | Parameters 39 | ---------- 40 | m: wntr.sim.aml.aml.Model 41 | wn: wntr.network.model.WaterNetworkModel 42 | index_over: list of str 43 | list of link names 44 | """ 45 | if not hasattr(m, 'flow'): 46 | m.flow = aml.VarDict() 47 | 48 | if index_over is None: 49 | index_over = wn.link_name_list 50 | 51 | for link_name in index_over: 52 | link = wn.get_link(link_name) 53 | m.flow[link_name] = aml.Var(0.001) 54 | 55 | 56 | def head_var(m, wn, index_over=None): 57 | """ 58 | Add a head variable to the model 59 | 60 | Parameters 61 | ---------- 62 | m: wntr.sim.aml.aml.Model 63 | wn: wntr.network.model.WaterNetworkModel 64 | index_over: list of str 65 | list of junction names 66 | """ 67 | if not hasattr(m, 'head'): 68 | m.head = aml.VarDict() 69 | 70 | if index_over is None: 71 | index_over = wn.junction_name_list 72 | 73 | for node_name in index_over: 74 | node = wn.get_node(node_name) 75 | m.head[node_name] = aml.Var(node.elevation) 76 | 77 | 78 | def leak_rate_var(m, wn, index_over=None): 79 | """ 80 | Add a variable to the model for leak flow rate 81 | 82 | Parameters 83 | ---------- 84 | m: wntr.sim.aml.aml.Model 85 | wn: wntr.network.model.WaterNetworkModel 86 | index_over: list of str 87 | list of junction/tank names 88 | """ 89 | if not hasattr(m, 'leak_rate'): 90 | m.leak_rate = aml.VarDict() 91 | 92 | if index_over is None: 93 | index_over = wn.junction_name_list + wn.tank_name_list 94 | 95 | for node_name in index_over: 96 | m.leak_rate[node_name] = aml.Var(0) 97 | 98 | 99 | -------------------------------------------------------------------------------- /wntr/sim/network_isolation/__init__.py: -------------------------------------------------------------------------------- 1 | """The network isolation package (SWIG).""" 2 | 3 | from wntr.sim.network_isolation.network_isolation import check_for_isolated_junctions, get_long_size 4 | -------------------------------------------------------------------------------- /wntr/sim/network_isolation/network_isolation.cpp: -------------------------------------------------------------------------------- 1 | #include "network_isolation.hpp" 2 | 3 | 4 | int get_long_size() 5 | { 6 | if (CHAR_BIT != 8) 7 | { 8 | throw std::runtime_error("Expected CHAR_BIT to be 8. Please report this to the WNTR developers."); 9 | } 10 | return (int) sizeof(long); 11 | } 12 | 13 | 14 | void check_for_isolated_junctions(long *sources, int source_length, long *node_indicator, int num_nodes, long *indptr, int indptr_length, long *indices, int indices_length, long *data, int data_length, long *num_connections, int num_connections_length) 15 | { 16 | int source_id; 17 | int node_being_explored; 18 | int ndx; 19 | int number_of_connections; 20 | int val; 21 | int col; 22 | 23 | for (int source_cntr = 0; source_cntr < source_length; ++ source_cntr) 24 | { 25 | source_id = sources[source_cntr]; 26 | if (node_indicator[source_id] == 1) 27 | { 28 | node_indicator[source_id] = 0; 29 | std::set nodes_to_explore; 30 | nodes_to_explore.insert(source_id); 31 | 32 | while (!nodes_to_explore.empty()) 33 | { 34 | std::set::iterator nodes_to_explore_iter = nodes_to_explore.end(); 35 | --nodes_to_explore_iter; 36 | node_being_explored = *nodes_to_explore_iter; 37 | nodes_to_explore.erase(nodes_to_explore_iter); 38 | ndx = indptr[node_being_explored]; 39 | number_of_connections = num_connections[node_being_explored]; 40 | for (int i = 0; i < number_of_connections; ++i) 41 | { 42 | val = data[ndx + i]; 43 | if (val == 1) 44 | { 45 | col = indices[ndx + i]; 46 | if (node_indicator[col] == 1) 47 | { 48 | node_indicator[col] = 0; 49 | nodes_to_explore.insert(col); 50 | } 51 | } 52 | } 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /wntr/sim/network_isolation/network_isolation.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int get_long_size(); 6 | 7 | void check_for_isolated_junctions(long *sources, int source_length, long *node_indicator, int num_nodes, long *indptr, int indptr_length, long *indices, int indices_length, long *data, int data_length, long *num_connections, int num_connections_length); 8 | -------------------------------------------------------------------------------- /wntr/sim/network_isolation/network_isolation.i: -------------------------------------------------------------------------------- 1 | %module network_isolation 2 | %{ 3 | #define SWIG_FILE_WITH_INIT 4 | #include "network_isolation.hpp" 5 | %} 6 | 7 | %include "numpy.i" 8 | %init %{ 9 | import_array(); 10 | %} 11 | 12 | %apply (long *INPLACE_ARRAY1, int DIM1) {(long *node_indicator, int num_nodes)} 13 | %apply (long *IN_ARRAY1, int DIM1) {(long *sources, int source_length)} 14 | %apply (long *IN_ARRAY1, int DIM1) {(long *indptr, int indptr_length)} 15 | %apply (long *IN_ARRAY1, int DIM1) {(long *indices, int indices_length)} 16 | %apply (long *IN_ARRAY1, int DIM1) {(long *data, int data_length)} 17 | %apply (long *IN_ARRAY1, int DIM1) {(long *num_connections, int num_connections_length)} 18 | 19 | %include "network_isolation.hpp" 20 | -------------------------------------------------------------------------------- /wntr/sim/network_isolation/network_isolation.py: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by SWIG (http://www.swig.org). 2 | # Version 4.0.2 3 | # 4 | # Do not make changes to this file unless you know what you are doing--modify 5 | # the SWIG interface file instead. 6 | 7 | from sys import version_info as _swig_python_version_info 8 | if _swig_python_version_info < (2, 7, 0): 9 | raise RuntimeError("Python 2.7 or later required") 10 | 11 | # Pull in all the attributes from the low-level C/C++ module 12 | if __package__ or "." in __name__: 13 | from ._network_isolation import * 14 | else: 15 | from _network_isolation import * 16 | 17 | try: 18 | import builtins as __builtin__ 19 | except ImportError: 20 | import __builtin__ 21 | 22 | def _swig_repr(self): 23 | try: 24 | strthis = "proxy of " + self.this.__repr__() 25 | except __builtin__.Exception: 26 | strthis = "" 27 | return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) 28 | 29 | 30 | def _swig_setattr_nondynamic_instance_variable(set): 31 | def set_instance_attr(self, name, value): 32 | if name == "thisown": 33 | self.this.own(value) 34 | elif name == "this": 35 | set(self, name, value) 36 | elif hasattr(self, name) and isinstance(getattr(type(self), name), property): 37 | set(self, name, value) 38 | else: 39 | raise AttributeError("You cannot add instance attributes to %s" % self) 40 | return set_instance_attr 41 | 42 | 43 | def _swig_setattr_nondynamic_class_variable(set): 44 | def set_class_attr(cls, name, value): 45 | if hasattr(cls, name) and not isinstance(getattr(cls, name), property): 46 | set(cls, name, value) 47 | else: 48 | raise AttributeError("You cannot add class attributes to %s" % cls) 49 | return set_class_attr 50 | 51 | 52 | def _swig_add_metaclass(metaclass): 53 | """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass""" 54 | def wrapper(cls): 55 | return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy()) 56 | return wrapper 57 | 58 | 59 | class _SwigNonDynamicMeta(type): 60 | """Meta class to enforce nondynamic attributes (no new attributes) for a class""" 61 | __setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__) 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /wntr/sim/results.py: -------------------------------------------------------------------------------- 1 | """Simulation results.""" 2 | 3 | import datetime 4 | import enum 5 | 6 | 7 | class ResultsStatus(enum.IntEnum): 8 | converged = 1 9 | error = 0 10 | 11 | 12 | class SimulationResults(object): 13 | """ 14 | Water network simulation results class. 15 | """ 16 | 17 | def __init__(self): 18 | 19 | # Simulation time series 20 | self.timestamp = str(datetime.datetime.now()) 21 | self.network_name = None 22 | self.link = None 23 | self.node = None 24 | -------------------------------------------------------------------------------- /wntr/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandialabs/WNTR/8a61184a69efbbdc07756bcc083f10b4255bdaf3/wntr/tests/__init__.py -------------------------------------------------------------------------------- /wntr/tests/data_for_testing/fire_flow_junctions_impacted.csv: -------------------------------------------------------------------------------- 1 | ,0 2 | 275,0 3 | 229,0 4 | 15,0 5 | 251,0 6 | 151,1 7 | 120,0 8 | 261,0 9 | 153,0 10 | 121,0 11 | 189,0 12 | 267,0 13 | 213,3 14 | 257,0 15 | 113,0 16 | 115,0 17 | 125,0 18 | 255,1 19 | 265,0 20 | 195,0 21 | 237,3 22 | 143,1 23 | 107,0 24 | 263,0 25 | 149,0 26 | 259,0 27 | 269,0 28 | 161,0 29 | 185,0 30 | 169,0 31 | 129,0 32 | 183,0 33 | 273,0 34 | 139,0 35 | 184,0 36 | 187,0 37 | 204,0 38 | 271,0 39 | 141,1 40 | 167,0 41 | -------------------------------------------------------------------------------- /wntr/tests/data_for_testing/fire_flow_people_impacted.csv: -------------------------------------------------------------------------------- 1 | ,0 2 | 275,0.0 3 | 229,0.0 4 | 15,0.0 5 | 251,0.0 6 | 151,340.0 7 | 120,0.0 8 | 261,0.0 9 | 153,0.0 10 | 121,0.0 11 | 189,0.0 12 | 267,0.0 13 | 213,917.0 14 | 257,0.0 15 | 113,0.0 16 | 115,0.0 17 | 125,0.0 18 | 255,420.0 19 | 265,0.0 20 | 195,0.0 21 | 237,917.0 22 | 143,1902.0 23 | 107,0.0 24 | 263,0.0 25 | 149,0.0 26 | 259,0.0 27 | 269,0.0 28 | 161,0.0 29 | 185,0.0 30 | 169,0.0 31 | 129,0.0 32 | 183,0.0 33 | 273,0.0 34 | 139,0.0 35 | 184,0.0 36 | 187,0.0 37 | 204,0.0 38 | 271,0.0 39 | 141,1902.0 40 | 167,0.0 41 | -------------------------------------------------------------------------------- /wntr/tests/data_for_testing/pipe_break_junctions_impacted.csv: -------------------------------------------------------------------------------- 1 | ,0 2 | 20,0 3 | 40,0 4 | 50,0 5 | 60,0 6 | 101,0 7 | 103,0 8 | 109,0 9 | 123,0 10 | 125,0 11 | 129,0 12 | 131,0 13 | 133,0 14 | 135,0 15 | 137,1 16 | 173,3 17 | 175,3 18 | 177,3 19 | 179,1 20 | 180,1 21 | 181,1 22 | 183,0 23 | 187,0 24 | 189,3 25 | 191,0 26 | 193,1 27 | 229,3 28 | 231,0 29 | 233,1 30 | 243,15 31 | 245,0 32 | 247,4 33 | 249,3 34 | 251,1 35 | 315,0 36 | 321,1 37 | 329,0 38 | 330,0 39 | 333,0 40 | -------------------------------------------------------------------------------- /wntr/tests/data_for_testing/pipe_break_people_impacted.csv: -------------------------------------------------------------------------------- 1 | ,0 2 | 20,0.0 3 | 40,0.0 4 | 50,0.0 5 | 60,0.0 6 | 101,0.0 7 | 103,0.0 8 | 109,0.0 9 | 123,0.0 10 | 125,0.0 11 | 129,0.0 12 | 131,0.0 13 | 133,0.0 14 | 135,0.0 15 | 137,329.0 16 | 173,917.0 17 | 175,917.0 18 | 177,917.0 19 | 179,420.0 20 | 180,20.0 21 | 181,20.0 22 | 183,0.0 23 | 187,0.0 24 | 189,917.0 25 | 191,0.0 26 | 193,12371.0 27 | 229,917.0 28 | 231,0.0 29 | 233,32486.0 30 | 243,4142.0 31 | 245,0.0 32 | 247,1391.0 33 | 249,681.0 34 | 251,318.0 35 | 315,0.0 36 | 321,420.0 37 | 329,0.0 38 | 330,0.0 39 | 333,0.0 40 | -------------------------------------------------------------------------------- /wntr/tests/data_for_testing/pump_practice_curves.csv: -------------------------------------------------------------------------------- 1 | # These curves come from a family of actual pump curves 2 | # that have been scaled and randomly changed 3 | # so that they can serve as a testing basis without 4 | # directly releasing pump performance specifications 5 | # dlvilla@sandia.gov 6 | ,flow (m3/s),head (m),curve number 7 | 0,0.0,98.99904,0 8 | 1,0.105681915,91.31808,0 9 | 2,0.176382668,88.33104,0 10 | 3,0.28377588,85.344,0 11 | 4,0.376517515,79.36992,0 12 | 5,0.463334953,73.39584,0 13 | 6,0.565740579,64.008,0 14 | 7,0.613132057,55.4736,0 15 | 8,0.715287247,43.52544,0 16 | 0,0.0,66.01968,1 17 | 1,0.044193533,65.8368,1 18 | 2,0.077059091,65.47104,1 19 | 3,0.125596807,65.10528,1 20 | 4,0.177324675,63.45936,1 21 | 5,0.214427091,62.54496,1 22 | 6,0.229871141,60.71616,1 23 | 7,0.263847712,59.80176,1 24 | 8,0.272364103,57.05856,1 25 | 9,0.287419644,54.864,1 26 | 10,0.329695508,51.2064,1 27 | 11,0.342817819,46.6344,1 28 | 0,0.0,21.39696,2 29 | 1,0.013200266,21.12264,2 30 | 2,0.023592001,20.84832,2 31 | 3,0.032796828,19.75104,2 32 | 4,0.04404861,18.10512,2 33 | 5,0.056725625,17.55648,2 34 | 6,0.067307444,13.716,2 35 | 7,0.081731919,10.42416,2 36 | 8,0.090227983,7.13232,2 37 | 0,0.0,81.153,3 38 | 1,0.047618471,80.6958,3 39 | 2,0.099386625,80.01,3 40 | 3,0.148381288,77.724,3 41 | 4,0.170674825,75.6666,3 42 | 5,0.174439345,74.5236,3 43 | 6,0.192396396,72.009,3 44 | 7,0.19726897,71.3232,3 45 | 8,0.200258823,70.4088,3 46 | 9,0.205367171,70.1802,3 47 | 10,0.206927169,69.9516,3 48 | 11,0.215247862,68.8086,3 49 | 12,0.212702829,68.58,3 50 | 13,0.230197117,61.722,3 51 | 14,0.25382684,54.864,3 52 | 0,0.0,137.16,4 53 | 1,0.082832516,136.779,4 54 | 2,0.157427491,136.017,4 55 | 3,0.238174748,134.112,4 56 | 4,0.312332802,129.921,4 57 | 5,0.394059908,123.063,4 58 | 6,0.411851362,121.158,4 59 | 7,0.425626409,118.872,4 60 | 8,0.430131793,117.729,4 61 | 9,0.435578582,115.824,4 62 | 10,0.449945424,113.919,4 63 | 11,0.490204636,103.251,4 64 | 12,0.508401729,95.25,4 65 | 0,0.0,128.188212,5 66 | 1,0.078451605,127.83312,5 67 | 2,0.140215516,127.122936,5 68 | 3,0.230802593,126.412752,5 69 | 4,0.346271513,123.216924,5 70 | 5,0.399431962,121.441464,5 71 | 6,0.462893998,117.890544,5 72 | 7,0.503652986,116.115084,5 73 | 8,0.548177447,110.788704,5 74 | 9,0.586089294,106.5276,5 75 | 10,0.616837205,99.42576,5 76 | 11,0.665963195,90.54846,5 77 | 0,0.0,28.28544,6 78 | 1,0.015831766,26.09088,6 79 | 2,0.042993772,25.23744,6 80 | 3,0.086366598,24.384,6 81 | 4,0.110592715,22.67712,6 82 | 5,0.136667964,20.97024,6 83 | 6,0.148002742,18.288,6 84 | 7,0.166183444,15.8496,6 85 | 8,0.192500825,12.43584,6 86 | 0,0.0,49.78908,7 87 | 1,0.005028586,49.28616,7 88 | 2,0.009781127,47.27448,7 89 | 3,0.013212743,42.7482,7 90 | 4,0.014714396,40.2336,7 91 | 5,0.021535734,29.16936,7 92 | 6,0.024714589,15.0876,7 93 | 0,0.0,34.47288,8 94 | 1,0.015443564,34.07664,8 95 | 2,0.031929845,33.6804,8 96 | 3,0.049860221,31.6992,8 97 | 4,0.058568851,28.52928,8 98 | 5,0.066978995,26.94432,8 99 | 6,0.073517522,22.98192,8 100 | 7,0.080020689,19.01952,8 101 | 8,0.088197281,13.07592,8 102 | 0,0.0,35.3568,9 103 | 1,0.029727745,32.6136,9 104 | 2,0.062299117,31.5468,9 105 | 3,0.093291238,30.48,9 106 | 4,0.126787743,28.3464,9 107 | 5,0.156038659,26.2128,9 108 | 6,0.192924986,22.86,9 109 | 7,0.222702993,19.812,9 110 | 8,0.252434918,15.5448,9 111 | 0,0.0,14.859,10 112 | 1,0.008879477,14.6685,10 113 | 2,0.013076767,14.478,10 114 | 3,0.023278037,13.716,10 115 | 4,0.034161965,12.573,10 116 | 5,0.036876335,12.192,10 117 | 6,0.048019325,9.525,10 118 | 7,0.053792489,7.239,10 119 | 8,0.064882816,4.953,10 120 | -------------------------------------------------------------------------------- /wntr/tests/data_for_testing/segment_break_junctions_impacted.csv: -------------------------------------------------------------------------------- 1 | ,0 2 | 101,0 3 | 10,0 4 | 151,2 5 | 133,0 6 | 20,0 7 | 193,2 8 | 201,0 9 | 40,0 10 | 289,0 11 | 50,0 12 | 330,0 13 | 335,0 14 | 60,0 15 | 333,0 16 | 329,9 17 | 103,2 18 | 105,2 19 | 109,2 20 | 107,1 21 | 117,1 22 | 115,1 23 | 111,2 24 | 113,0 25 | 225,1 26 | 112,0 27 | 116,0 28 | 114,0 29 | 119,0 30 | 305,10 31 | 121,10 32 | 120,10 33 | 171,7 34 | 173,10 35 | 123,0 36 | 297,0 37 | 122,0 38 | 129,9 39 | 125,9 40 | 131,0 41 | 169,9 42 | 135,1 43 | 137,1 44 | 145,7 45 | 147,7 46 | 149,2 47 | 153,7 48 | 155,7 49 | 159,7 50 | 161,7 51 | 163,9 52 | 175,10 53 | 177,10 54 | 179,1 55 | 221,10 56 | 180,2 57 | 321,2 58 | 181,2 59 | 185,1 60 | 187,8 61 | 211,8 62 | 183,8 63 | 189,3 64 | 191,8 65 | 229,3 66 | 197,2 67 | 195,2 68 | 199,2 69 | 315,0 70 | 203,0 71 | 207,2 72 | 204,0 73 | 202,0 74 | 205,0 75 | 186,0 76 | 209,0 77 | 213,0 78 | 215,8 79 | 313,8 80 | 217,0 81 | 223,1 82 | 219,10 83 | 311,10 84 | 231,2 85 | 235,2 86 | 233,2 87 | 323,2 88 | 237,0 89 | 319,0 90 | 240,16 91 | 238,16 92 | 239,16 93 | 241,16 94 | 243,16 95 | 245,16 96 | 269,1 97 | 247,16 98 | 261,0 99 | 249,16 100 | 251,16 101 | 257,1 102 | 263,1 103 | 271,1 104 | 273,0 105 | 275,0 106 | 283,0 107 | 277,1 108 | 281,1 109 | 285,0 110 | 287,1 111 | 295,2 112 | 293,2 113 | 291,2 114 | 299,0 115 | 303,10 116 | 301,0 117 | 307,0 118 | 309,8 119 | 325,0 120 | 317,2 121 | -------------------------------------------------------------------------------- /wntr/tests/data_for_testing/segment_break_people_impacted.csv: -------------------------------------------------------------------------------- 1 | ,0 2 | 101,0.0 3 | 10,0.0 4 | 151,1950.0 5 | 133,0.0 6 | 20,0.0 7 | 193,12819.0 8 | 201,0.0 9 | 40,0.0 10 | 289,0.0 11 | 50,0.0 12 | 330,0.0 13 | 335,0.0 14 | 60,0.0 15 | 333,0.0 16 | 329,12642.0 17 | 103,2808.0 18 | 105,2808.0 19 | 109,2808.0 20 | 107,421.0 21 | 117,421.0 22 | 115,421.0 23 | 111,2808.0 24 | 113,0.0 25 | 225,131.0 26 | 112,0.0 27 | 116,0.0 28 | 114,0.0 29 | 119,0.0 30 | 305,3176.0 31 | 121,3176.0 32 | 120,3176.0 33 | 171,2558.0 34 | 173,3176.0 35 | 123,0.0 36 | 297,0.0 37 | 122,0.0 38 | 129,12642.0 39 | 125,12642.0 40 | 131,0.0 41 | 169,12642.0 42 | 135,329.0 43 | 137,329.0 44 | 145,2558.0 45 | 147,2558.0 46 | 149,1950.0 47 | 153,2558.0 48 | 155,2558.0 49 | 159,2558.0 50 | 161,2558.0 51 | 163,12642.0 52 | 175,3176.0 53 | 177,3176.0 54 | 179,420.0 55 | 221,3176.0 56 | 180,440.0 57 | 321,440.0 58 | 181,440.0 59 | 185,112.0 60 | 187,2227.0 61 | 211,2227.0 62 | 183,2227.0 63 | 189,917.0 64 | 191,2227.0 65 | 229,917.0 66 | 197,12819.0 67 | 195,12819.0 68 | 199,12819.0 69 | 315,0.0 70 | 203,0.0 71 | 207,12819.0 72 | 204,0.0 73 | 202,0.0 74 | 205,0.0 75 | 186,0.0 76 | 209,0.0 77 | 213,0.0 78 | 215,2227.0 79 | 313,2227.0 80 | 217,0.0 81 | 223,131.0 82 | 219,3176.0 83 | 311,3176.0 84 | 231,32830.0 85 | 235,32830.0 86 | 233,32830.0 87 | 323,32830.0 88 | 237,0.0 89 | 319,0.0 90 | 240,4149.0 91 | 238,4149.0 92 | 239,4149.0 93 | 241,4149.0 94 | 243,4149.0 95 | 245,4149.0 96 | 269,127.0 97 | 247,4149.0 98 | 261,0.0 99 | 249,4149.0 100 | 251,4149.0 101 | 257,176.0 102 | 263,127.0 103 | 271,127.0 104 | 273,0.0 105 | 275,0.0 106 | 283,0.0 107 | 277,33.0 108 | 281,33.0 109 | 285,0.0 110 | 287,33.0 111 | 295,606.0 112 | 293,606.0 113 | 291,606.0 114 | 299,0.0 115 | 303,3176.0 116 | 301,0.0 117 | 307,0.0 118 | 309,2227.0 119 | 325,0.0 120 | 317,32830.0 121 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/io.inp: -------------------------------------------------------------------------------- 1 | [TITLE] 2 | 3 | [JUNCTIONS] 4 | ;ID Elev Demand Pattern 5 | j1 0 0 pattern1 ; 6 | j2 1.38 100 pattern1 ; 7 | j3 0 0 pattern1 ; 8 | j4 0 ; 9 | 10 | [RESERVOIRS] 11 | ;ID Head Pattern 12 | 13 | [TANKS] 14 | ;ID Elevation InitLevel MinLevel MaxLevel Diameter MinVol VolCurve 15 | t1 0 20 10 100 10 0 ; 16 | 17 | [PIPES] 18 | ;ID Node1 Node2 Length Diameter Roughness MinorLoss Status 19 | p1 t1 j1 1000 457.2 100 0.73 Open ; 20 | 21 | [PUMPS] 22 | ;ID Node1 Node2 Parameters 23 | pump1 j2 j3 HEAD curve1 SPEED 1.2 PATTERN pattern1 24 | pump2 j3 j4 POWER 22.3 25 | 26 | [VALVES] 27 | ;ID Node1 Node2 Diameter Type Setting MinorLoss 28 | v1 j1 j2 12 TCV 3.52 0.54 29 | v2 j2 j3 12 PSV 2.51 0.985 30 | v3 j1 j2 12 GPV GPVCurve 0.56 31 | 32 | [PATTERNS] 33 | pattern1 1.0 1.0 1.0 1.0 34 | pattern2 1.0 1.25 1.5 1.25 35 | 36 | [CURVES] 37 | curve1 0 50 38 | curve1 10 40 39 | curve1 20 30 40 | curve1 30 20 41 | curve1 40 10 42 | curve1 50 0 43 | GPVCurve 0 0 44 | GPVCurve 10 5 45 | GPVCurve 20 25 46 | 47 | [CONTROLS] 48 | link v1 0.82 at time 3.4 49 | link v2 2.61 if node t1 below 5.01 50 | link p1 closed at clocktime 5 am 51 | link p1 open at clocktime 5 pm 52 | link p1 closed at clocktime 20 53 | link p1 open at clocktime 22 54 | 55 | [COORDINATES] 56 | ;Node X-Coord Y-Coord 57 | t1 1.00 0.00 58 | j1 26.00 0.00 59 | j2 51.00 0.00 60 | j3 76 0.00 61 | j4 101 0.00 62 | 63 | 64 | [TIMES] 65 | Duration 24:00 66 | Hydraulic Timestep 1:00 67 | Quality Timestep 1:00 68 | Rule Timestep 1:00 69 | Pattern Timestep 6:00 70 | Pattern Start 0:00 71 | Report Timestep 1:00 72 | Report Start 0:00 73 | Start ClockTime 12 am 74 | Statistic NONE 75 | 76 | [OPTIONS] 77 | Units GPM 78 | Headloss H-W 79 | Quality None 80 | Specific Gravity 1.0 81 | Viscosity 1.0 82 | Trials 50 83 | Accuracy 0.001 84 | Unbalanced Stop 85 | Pattern pattern1 86 | Demand Multiplier 1.0 87 | Tolerance 0.01 88 | Demand Model PDA 89 | Minimum Pressure 0 90 | Required Pressure 20 91 | Pressure Exponent 0.5 92 | Pressure psi 93 | 94 | [REPORT] 95 | Status Yes 96 | Summary No 97 | Energy No 98 | 99 | [VERTICES] 100 | ;Link X-Coord Y-Coord 101 | p1 15 5 102 | p1 20 5 103 | 104 | [LABELS] 105 | 106 | [BACKDROP] 107 | 108 | [TAGS] 109 | 110 | [DEMANDS] 111 | ;Junction Demand Pattern Category 112 | j1 0 pattern2 113 | j1 20 pattern2 114 | j2 50 pattern2 115 | j2 75 pattern2 116 | j4 0 pattern2 117 | [STATUS] 118 | 119 | [RULES] 120 | 121 | [ENERGY] 122 | 123 | [EMITTERS] 124 | 125 | [QUALITY] 126 | 127 | [SOURCES] 128 | 129 | [REACTIONS] 130 | 131 | [MIXING] 132 | 133 | [END] 134 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/link_segments_random.csv: -------------------------------------------------------------------------------- 1 | ,0 2 | 101,9 3 | 10,9 4 | 151,10 5 | 133,10 6 | 20,1 7 | 193,10 8 | 201,10 9 | 40,10 10 | 289,11 11 | 50,11 12 | 330,10 13 | 335,10 14 | 60,10 15 | 333,2 16 | 329,10 17 | 103,13 18 | 105,13 19 | 109,14 20 | 107,10 21 | 117,10 22 | 115,3 23 | 111,10 24 | 113,4 25 | 225,10 26 | 112,10 27 | 116,10 28 | 114,10 29 | 119,10 30 | 305,10 31 | 121,10 32 | 120,10 33 | 171,10 34 | 173,10 35 | 123,5 36 | 297,10 37 | 122,10 38 | 129,10 39 | 125,10 40 | 131,10 41 | 169,10 42 | 135,10 43 | 137,10 44 | 145,10 45 | 147,10 46 | 149,10 47 | 153,10 48 | 155,15 49 | 159,15 50 | 161,10 51 | 163,10 52 | 175,10 53 | 177,10 54 | 179,10 55 | 221,10 56 | 180,10 57 | 321,10 58 | 181,6 59 | 185,10 60 | 187,10 61 | 211,10 62 | 183,10 63 | 189,7 64 | 191,10 65 | 229,18 66 | 197,10 67 | 195,10 68 | 199,10 69 | 315,10 70 | 203,10 71 | 207,10 72 | 204,18 73 | 202,10 74 | 205,10 75 | 186,10 76 | 209,10 77 | 213,10 78 | 215,10 79 | 313,10 80 | 217,10 81 | 223,10 82 | 219,10 83 | 311,10 84 | 231,18 85 | 235,18 86 | 233,18 87 | 323,18 88 | 237,18 89 | 319,8 90 | 240,21 91 | 238,18 92 | 239,18 93 | 241,21 94 | 243,21 95 | 245,21 96 | 269,21 97 | 247,21 98 | 261,21 99 | 249,21 100 | 251,21 101 | 257,21 102 | 263,22 103 | 271,21 104 | 273,21 105 | 275,21 106 | 283,21 107 | 277,11 108 | 281,11 109 | 285,11 110 | 287,11 111 | 295,11 112 | 293,11 113 | 291,11 114 | 299,10 115 | 303,10 116 | 301,10 117 | 307,10 118 | 309,10 119 | 325,10 120 | 317,18 121 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/link_segments_strategic.csv: -------------------------------------------------------------------------------- 1 | ,0 2 | 101,41 3 | 10,118 4 | 151,42 5 | 133,43 6 | 20,119 7 | 193,44 8 | 201,1 9 | 40,45 10 | 289,2 11 | 50,46 12 | 330,48 13 | 335,3 14 | 60,47 15 | 333,49 16 | 329,61 17 | 103,4 18 | 105,50 19 | 109,51 20 | 107,53 21 | 117,52 22 | 115,5 23 | 111,54 24 | 113,55 25 | 225,90 26 | 112,6 27 | 116,56 28 | 114,7 29 | 119,57 30 | 305,58 31 | 121,8 32 | 120,59 33 | 171,71 34 | 173,72 35 | 123,9 36 | 297,10 37 | 122,11 38 | 129,60 39 | 125,12 40 | 131,63 41 | 169,62 42 | 135,64 43 | 137,65 44 | 145,13 45 | 147,66 46 | 149,67 47 | 153,68 48 | 155,14 49 | 159,69 50 | 161,70 51 | 163,15 52 | 175,16 53 | 177,73 54 | 179,17 55 | 221,89 56 | 180,75 57 | 321,74 58 | 181,76 59 | 185,77 60 | 187,18 61 | 211,78 62 | 183,19 63 | 189,20 64 | 191,79 65 | 229,80 66 | 197,82 67 | 195,81 68 | 199,21 69 | 315,22 70 | 203,85 71 | 207,83 72 | 204,94 73 | 202,84 74 | 205,23 75 | 186,93 76 | 209,24 77 | 213,86 78 | 215,87 79 | 313,115 80 | 217,25 81 | 223,26 82 | 219,27 83 | 311,88 84 | 231,28 85 | 235,91 86 | 233,92 87 | 323,29 88 | 237,30 89 | 319,31 90 | 240,32 91 | 238,95 92 | 239,96 93 | 241,97 94 | 243,98 95 | 245,33 96 | 269,34 97 | 247,99 98 | 261,35 99 | 249,36 100 | 251,100 101 | 257,101 102 | 263,102 103 | 271,103 104 | 273,104 105 | 275,37 106 | 283,38 107 | 277,106 108 | 281,105 109 | 285,108 110 | 287,107 111 | 295,39 112 | 293,109 113 | 291,110 114 | 299,111 115 | 303,112 116 | 301,113 117 | 307,40 118 | 309,114 119 | 325,116 120 | 317,117 121 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/msx_example.inp: -------------------------------------------------------------------------------- 1 | [TITLE] 2 | EPANET-MSX Example Network 3 | 4 | [JUNCTIONS] 5 | ;ID Elev Demand Pattern 6 | A 0 4.1 7 | B 0 3.4 8 | C 0 5.5 9 | D 0 2.3 10 | 11 | [RESERVOIRS] 12 | ;ID Head Pattern 13 | Source 100 14 | 15 | [PIPES] 16 | ;ID Node1 Node2 Length Diameter Roughness 17 | 1 Source A 1000 200 100 18 | 2 A B 800 150 100 19 | 3 A C 1200 200 100 20 | 4 B C 1000 150 100 21 | 5 C D 2000 150 100 22 | 23 | [TIMES] 24 | Duration 48 25 | Hydraulic Timestep 1:00 26 | Quality Timestep 0:05 27 | Report Timestep 2 28 | Report Start 0 29 | Statistic NONE 30 | 31 | [OPTIONS] 32 | Units CMH 33 | Headloss H-W 34 | Quality NONE 35 | 36 | [END] 37 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/msx_example.msx: -------------------------------------------------------------------------------- 1 | [TITLE] 2 | Arsenic Oxidation/Adsorption Example 3 | 4 | [OPTIONS] 5 | AREA_UNITS M2 ;Surface concentration is mass/m2 6 | RATE_UNITS HR ;Reaction rates are concentration/hour 7 | SOLVER RK5 ;5-th order Runge-Kutta integrator 8 | TIMESTEP 360 ;360 sec (5 min) solution time step 9 | RTOL 0.001 ;Relative concentration tolerance 10 | ATOL 0.0001 ;Absolute concentration tolerance 11 | 12 | [SPECIES] 13 | BULK AS3 UG ;Dissolved arsenite 14 | BULK AS5 UG ;Dissolved arsenate 15 | BULK AStot UG ;Total dissolved arsenic 16 | WALL AS5s UG ;Adsorbed arsenate 17 | BULK NH2CL MG ;Monochloramine 18 | 19 | [COEFFICIENTS] 20 | CONSTANT Ka 10.0 ;Arsenite oxidation rate coefficient 21 | CONSTANT Kb 0.1 ;Monochloramine decay rate coefficient 22 | CONSTANT K1 5.0 ;Arsenate adsorption coefficient 23 | CONSTANT K2 1.0 ;Arsenate desorption coefficient 24 | CONSTANT Smax 50 ;Arsenate adsorption saturation limit 25 | 26 | [TERMS] 27 | Ks K1/K2 ;Equil. adsorption coeff. 28 | 29 | [PIPES] 30 | ;Arsenite oxidation 31 | RATE AS3 -Ka*AS3*NH2CL 32 | ;Arsenate production 33 | RATE AS5 Ka*AS3*NH2CL - Av*(K1*(Smax-AS5s)*AS5 - K2*AS5s) 34 | ;Monochloramine decay 35 | RATE NH2CL -Kb*NH2CL 36 | ;Arsenate adsorption 37 | EQUIL AS5s Ks*Smax*AS5/(1+Ks*AS5) - AS5s 38 | ;Total bulk arsenic 39 | FORMULA AStot AS3 + AS5 40 | 41 | [TANKS] 42 | RATE AS3 -Ka*AS3*NH2CL 43 | RATE AS5 Ka*AS3*NH2CL 44 | RATE NH2CL -Kb*NH2CL 45 | FORMULA AStot AS3 + AS5 46 | 47 | [QUALITY] 48 | ;Initial conditions (= 0 if not specified here) 49 | NODE Source AS3 10.0 50 | NODE Source NH2CL 2.5 51 | 52 | [REPORT] 53 | NODES C D ;Report results for nodes C and D 54 | LINKS 5 ;Report results for pipe 5 55 | SPECIES AStot YES ;Report results for each specie 56 | SPECIES AS5 YES 57 | SPECIES AS5s YES 58 | SPECIES NH2CL YES 59 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/node_segments_random.csv: -------------------------------------------------------------------------------- 1 | ,0 2 | 10,9 3 | 15,10 4 | 20,10 5 | 35,10 6 | 40,10 7 | 50,11 8 | 60,10 9 | 601,12 10 | 61,10 11 | 101,13 12 | 103,14 13 | 105,10 14 | 107,10 15 | 109,10 16 | 111,10 17 | 113,10 18 | 115,10 19 | 117,10 20 | 119,10 21 | 120,10 22 | 121,10 23 | 123,10 24 | 125,10 25 | 127,10 26 | 129,10 27 | 131,10 28 | 139,10 29 | 141,10 30 | 143,10 31 | 145,15 32 | 147,15 33 | 149,15 34 | 151,10 35 | 153,10 36 | 157,10 37 | 159,10 38 | 161,10 39 | 163,10 40 | 164,16 41 | 166,17 42 | 167,10 43 | 169,10 44 | 171,10 45 | 173,18 46 | 177,10 47 | 179,10 48 | 181,10 49 | 183,10 50 | 184,19 51 | 185,10 52 | 187,10 53 | 189,10 54 | 191,10 55 | 193,10 56 | 195,10 57 | 197,10 58 | 199,18 59 | 201,18 60 | 203,20 61 | 204,10 62 | 205,18 63 | 206,18 64 | 207,18 65 | 208,21 66 | 209,21 67 | 211,21 68 | 213,21 69 | 215,21 70 | 217,21 71 | 219,21 72 | 225,21 73 | 229,21 74 | 231,22 75 | 237,21 76 | 239,21 77 | 241,11 78 | 243,11 79 | 247,11 80 | 249,21 81 | 251,11 82 | 253,11 83 | 255,11 84 | 257,10 85 | 259,10 86 | 261,10 87 | 263,10 88 | 265,10 89 | 267,10 90 | 269,10 91 | 271,10 92 | 273,18 93 | 275,18 94 | River,10 95 | Lake,9 96 | 1,10 97 | 2,11 98 | 3,23 99 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/node_segments_strategic.csv: -------------------------------------------------------------------------------- 1 | ,0 2 | 10,41 3 | 15,42 4 | 20,43 5 | 35,44 6 | 40,45 7 | 50,46 8 | 60,47 9 | 601,48 10 | 61,49 11 | 101,50 12 | 103,51 13 | 105,52 14 | 107,53 15 | 109,54 16 | 111,55 17 | 113,56 18 | 115,57 19 | 117,58 20 | 119,59 21 | 120,59 22 | 121,60 23 | 123,61 24 | 125,62 25 | 127,63 26 | 129,64 27 | 131,65 28 | 139,66 29 | 141,66 30 | 143,67 31 | 145,68 32 | 147,69 33 | 149,70 34 | 151,71 35 | 153,62 36 | 157,72 37 | 159,73 38 | 161,73 39 | 163,74 40 | 164,75 41 | 166,76 42 | 167,77 43 | 169,78 44 | 171,79 45 | 173,80 46 | 177,81 47 | 179,82 48 | 181,81 49 | 183,83 50 | 184,84 51 | 185,85 52 | 187,86 53 | 189,87 54 | 191,86 55 | 193,88 56 | 195,89 57 | 197,90 58 | 199,91 59 | 201,92 60 | 203,92 61 | 204,93 62 | 205,94 63 | 206,95 64 | 207,96 65 | 208,97 66 | 209,98 67 | 211,98 68 | 213,99 69 | 215,99 70 | 217,100 71 | 219,100 72 | 225,101 73 | 229,102 74 | 231,102 75 | 237,103 76 | 239,104 77 | 241,105 78 | 243,106 79 | 247,107 80 | 249,108 81 | 251,109 82 | 253,110 83 | 255,110 84 | 257,111 85 | 259,111 86 | 261,112 87 | 263,113 88 | 265,114 89 | 267,114 90 | 269,115 91 | 271,116 92 | 273,91 93 | 275,117 94 | River,47 95 | Lake,118 96 | 1,45 97 | 2,46 98 | 3,119 99 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/tank_controls_1.inp: -------------------------------------------------------------------------------- 1 | [TITLE] 2 | Small Test Network 3 3 | 4 | [JUNCTIONS] 5 | ;ID Elev Demand Pattern 6 | junction1 0 0 pattern1 ; 7 | junction2 0 100 pattern1 ; 8 | 9 | [RESERVOIRS] 10 | ;ID Head Pattern 11 | 12 | [TANKS] 13 | ;ID Elevation InitLevel MinLevel MaxLevel Diameter MinVol VolCurve 14 | tank1 0 20 10 100 10 0 ; 15 | 16 | [PIPES] 17 | ;ID Node1 Node2 Length Diameter Roughness MinorLoss Status 18 | pipe1 tank1 junction1 1000 457.2 100 0 Open ; 19 | 20 | [PUMPS] 21 | ;ID Node1 Node2 Parameters 22 | pump1 junction1 junction2 HEAD curve1 ; 23 | 24 | [VALVES] 25 | 26 | [PATTERNS] 27 | pattern1 1.0 1.0 1.0 1.0 28 | pattern2 1.0 1.25 1.5 1.25 29 | 30 | [CURVES] 31 | curve1 100 8 32 | 33 | [CONTROLS] 34 | 35 | [COORDINATES] 36 | ;Node X-Coord Y-Coord 37 | tank1 1.00 0.00 38 | junction1 26.00 0.00 39 | junction2 51.00 0.00 40 | 41 | [TIMES] 42 | Duration 24:00 43 | Hydraulic Timestep 1:00 44 | Quality Timestep 1:00 45 | Rule Timestep 1:00 46 | Pattern Timestep 6:00 47 | Pattern Start 0:00 48 | Report Timestep 1:00 49 | Report Start 0:00 50 | Start ClockTime 12 am 51 | Statistic NONE 52 | 53 | [OPTIONS] 54 | Units CMH 55 | Headloss H-W 56 | Quality None 57 | Specific Gravity 1.0 58 | Viscosity 1.0 59 | Trials 50 60 | Accuracy 0.001 61 | Unbalanced Stop 62 | Pattern pattern1 63 | Demand Multiplier 1.0 64 | Tolerance 0.01 65 | 66 | [REPORT] 67 | Status Yes 68 | Summary No 69 | Energy No 70 | 71 | [VERTICES] 72 | 73 | [LABELS] 74 | 75 | [BACKDROP] 76 | 77 | [TAGS] 78 | 79 | [DEMANDS] 80 | 81 | [STATUS] 82 | 83 | [RULES] 84 | 85 | [ENERGY] 86 | 87 | [EMITTERS] 88 | 89 | [QUALITY] 90 | 91 | [SOURCES] 92 | 93 | [REACTIONS] 94 | 95 | [MIXING] 96 | 97 | [END] 98 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/tank_controls_2.inp: -------------------------------------------------------------------------------- 1 | [TITLE] 2 | Small Test Network 3 3 | 4 | [JUNCTIONS] 5 | ;ID Elev Demand Pattern 6 | junction1 0 0 pattern1 ; 7 | junction2 0 20 pattern1 ; 8 | 9 | [RESERVOIRS] 10 | ;ID Head Pattern 11 | res1 15 pattern1 ; 12 | 13 | [TANKS] 14 | ;ID Elevation InitLevel MinLevel MaxLevel Diameter MinVol VolCurve 15 | tank1 0 20 10 100 2.256758334191025 0 ; 16 | 17 | [PIPES] 18 | ;ID Node1 Node2 Length Diameter Roughness MinorLoss Status 19 | pipe1 tank1 junction1 1000 457.2 100 0 Open ; 20 | pipe2 res1 tank1 1000 457.2 100 0 Closed ; 21 | 22 | [PUMPS] 23 | ;ID Node1 Node2 Parameters 24 | pump1 junction1 junction2 HEAD curve1 ; 25 | 26 | [VALVES] 27 | 28 | [PATTERNS] 29 | pattern1 1.0 1.0 1.0 1.0 30 | pattern2 1.0 1.25 1.5 1.25 31 | 32 | [CURVES] 33 | curve1 20 20 34 | 35 | [CONTROLS] 36 | LINK pipe2 OPEN AT TIME 8:00 37 | 38 | [COORDINATES] 39 | ;Node X-Coord Y-Coord 40 | res1 -24.00 0.00 41 | tank1 1.00 0.00 42 | junction1 26.00 0.00 43 | junction2 51.00 0.00 44 | 45 | [TIMES] 46 | Duration 24:00 47 | Hydraulic Timestep 1:00 48 | Quality Timestep 1:00 49 | Rule Timestep 1:00 50 | Pattern Timestep 6:00 51 | Pattern Start 0:00 52 | Report Timestep 1:00 53 | Report Start 0:00 54 | Start ClockTime 12 am 55 | Statistic NONE 56 | 57 | [OPTIONS] 58 | Units CMH 59 | Headloss H-W 60 | Quality None 61 | Specific Gravity 1.0 62 | Viscosity 1.0 63 | Trials 50 64 | Accuracy 0.001 65 | Unbalanced Stop 66 | Pattern pattern1 67 | Demand Multiplier 1.0 68 | Tolerance 0.01 69 | 70 | [REPORT] 71 | Status Yes 72 | Summary No 73 | Energy No 74 | 75 | [VERTICES] 76 | 77 | [LABELS] 78 | 79 | [BACKDROP] 80 | 81 | [TAGS] 82 | 83 | [DEMANDS] 84 | 85 | [STATUS] 86 | 87 | [RULES] 88 | 89 | [ENERGY] 90 | 91 | [EMITTERS] 92 | 93 | [QUALITY] 94 | 95 | [SOURCES] 96 | 97 | [REACTIONS] 98 | 99 | [MIXING] 100 | 101 | [END] 102 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/valve_crit_demand.csv: -------------------------------------------------------------------------------- 1 | ,0 2 | 0,0.0 3 | 1,0.0 4 | 2,0.0 5 | 3,0.0 6 | 4,0.0 7 | 5,0.0 8 | 6,0.0 9 | 7,0.0 10 | 8,0.0 11 | 9,0.0 12 | 10,0.0 13 | 11,0.0 14 | 12,0.712661226638589 15 | 13,0.40363448326808005 16 | 14,0.0 17 | 15,0.5756266205704406 18 | 16,0.1200507256587291 19 | 17,0.6133967156439064 20 | 18,0.0 21 | 19,0.0 22 | 20,0.14097505988445835 23 | 21,0.0 24 | 22,0.0 25 | 23,0.0 26 | 24,0.44261320193696374 27 | 25,0.0 28 | 26,0.0 29 | 27,0.8203031851473341 30 | 28,0.2940441719184692 31 | 29,0.0 32 | 30,0.0 33 | 31,0.0 34 | 32,0.0 35 | 33,0.0 36 | 34,0.0 37 | 35,0.0 38 | 36,0.1967249637963686 39 | 37,0.463740670602651 40 | 38,0.0 41 | 39,0.0 42 | 40,0.0 43 | 41,0.0 44 | 42,0.0 45 | 43,0.39390088945362134 46 | 44,0.5696706478465439 47 | 45,0.02510315457413248 48 | 46,0.0 49 | 47,0.0 50 | 48,0.3158478019948283 51 | 49,0.0 52 | 50,0.18736157253599095 53 | 51,0.0 54 | 52,0.0 55 | 53,0.0 56 | 54,0.0 57 | 55,0.0 58 | 56,0.0 59 | 57,0.0 60 | 58,0.0 61 | 59,0.0 62 | 60,0.0 63 | 61,0.0 64 | 62,0.0 65 | 63,0.0 66 | 64,0.0 67 | 65,0.0 68 | 66,0.0 69 | 67,0.0 70 | 68,0.0 71 | 69,0.03621517025611176 72 | 70,0.0 73 | 71,0.0 74 | 72,0.0 75 | 73,0.0 76 | 74,0.0 77 | 75,0.0 78 | 76,0.0 79 | 77,0.0 80 | 78,0.0 81 | 79,0.0 82 | 80,0.0 83 | 81,0.0 84 | 82,0.28060580563735793 85 | 83,0.0 86 | 84,0.0 87 | 85,0.0 88 | 86,0.0 89 | 87,0.0 90 | 88,0.0 91 | 89,0.0 92 | 90,0.0 93 | 91,0.0 94 | 92,0.0 95 | 93,0.0 96 | 94,0.0 97 | 95,0.0 98 | 96,0.0 99 | 97,0.0 100 | 98,0.0 101 | 99,0.0 102 | 100,0.0 103 | 101,0.0 104 | 102,0.0 105 | 103,0.0 106 | 104,0.34787915776624967 107 | 105,0.0 108 | 106,0.0 109 | 107,0.19352839077609718 110 | 108,0.34992154225509964 111 | 109,0.0 112 | 110,0.0 113 | 111,0.0 114 | 112,0.0 115 | 113,0.0 116 | 114,0.0 117 | 115,0.0 118 | 116,0.0 119 | 117,0.0 120 | 118,0.0 121 | 119,0.7415446212201031 122 | 120,0.0 123 | 121,0.2545569486882311 124 | 122,0.0 125 | 123,0.0 126 | 124,0.0 127 | 125,0.0 128 | 126,0.0 129 | 127,0.0 130 | 128,0.0 131 | 129,0.0 132 | 130,0.0 133 | 131,0.0 134 | 132,0.0 135 | 133,0.0 136 | 134,0.0 137 | 135,0.0 138 | 136,0.0 139 | 137,0.0 140 | 138,0.0 141 | 139,0.0 142 | 140,0.0 143 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/valve_crit_valve.csv: -------------------------------------------------------------------------------- 1 | ,0 2 | 0,1 3 | 1,1 4 | 2,1 5 | 3,1 6 | 4,2 7 | 5,2 8 | 6,3 9 | 7,3 10 | 8,3 11 | 9,3 12 | 10,3 13 | 11,2 14 | 12,4 15 | 13,3 16 | 14,2 17 | 15,2 18 | 16,4 19 | 17,4 20 | 18,4 21 | 19,3 22 | 20,5 23 | 21,4 24 | 22,4 25 | 23,4 26 | 24,5 27 | 25,3 28 | 26,6 29 | 27,7 30 | 28,6 31 | 29,6 32 | 30,6 33 | 31,6 34 | 32,4 35 | 33,4 36 | 34,4 37 | 35,2 38 | 36,4 39 | 37,5 40 | 38,4 41 | 39,3 42 | 40,3 43 | 41,2 44 | 42,3 45 | 43,3 46 | 44,3 47 | 45,1 48 | 46,2 49 | 47,2 50 | 48,2 51 | 49,3 52 | 50,3 53 | 51,3 54 | 52,2 55 | 53,3 56 | 54,3 57 | 55,3 58 | 56,3 59 | 57,3 60 | 58,1 61 | 59,3 62 | 60,4 63 | 61,4 64 | 62,3 65 | 63,3 66 | 64,2 67 | 65,4 68 | 66,3 69 | 67,3 70 | 68,3 71 | 69,2 72 | 70,4 73 | 71,3 74 | 72,3 75 | 73,3 76 | 74,3 77 | 75,4 78 | 76,4 79 | 77,5 80 | 78,4 81 | 79,5 82 | 80,4 83 | 81,4 84 | 82,5 85 | 83,4 86 | 84,4 87 | 85,2 88 | 86,2 89 | 87,4 90 | 88,4 91 | 89,2 92 | 90,2 93 | 91,2 94 | 92,3 95 | 93,3 96 | 94,2 97 | 95,3 98 | 96,3 99 | 97,2 100 | 98,3 101 | 99,3 102 | 100,3 103 | 101,3 104 | 102,3 105 | 103,3 106 | 104,1 107 | 105,2 108 | 106,2 109 | 107,3 110 | 108,4 111 | 109,3 112 | 110,3 113 | 111,3 114 | 112,3 115 | 113,2 116 | 114,4 117 | 115,4 118 | 116,3 119 | 117,3 120 | 118,2 121 | 119,4 122 | 120,3 123 | 121,3 124 | 122,4 125 | 123,3 126 | 124,4 127 | 125,3 128 | 126,4 129 | 127,4 130 | 128,3 131 | 129,5 132 | 130,4 133 | 131,6 134 | 132,6 135 | 133,4 136 | 134,5 137 | 135,4 138 | 136,3 139 | 137,4 140 | 138,5 141 | 139,4 142 | 140,3 143 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/valve_layer_random.csv: -------------------------------------------------------------------------------- 1 | ,link,node 2 | 0,105,105 3 | 1,161,149 4 | 2,113,111 5 | 3,295,249 6 | 4,197,177 7 | 5,333,601 8 | 6,115,115 9 | 7,313,269 10 | 8,321,265 11 | 9,101,101 12 | 10,189,173 13 | 11,225,197 14 | 12,233,203 15 | 13,180,164 16 | 14,181,166 17 | 15,317,273 18 | 16,333,61 19 | 17,123,121 20 | 18,120,119 21 | 19,181,164 22 | 20,319,205 23 | 21,319,273 24 | 22,275,241 25 | 23,153,145 26 | 24,123,119 27 | 25,20,3 28 | 26,202,184 29 | 27,297,120 30 | 28,330,601 31 | 29,240,206 32 | 30,189,171 33 | 31,109,109 34 | 32,20,20 35 | 33,177,159 36 | 34,285,249 37 | 35,204,184 38 | 36,115,107 39 | 37,103,103 40 | 38,113,113 41 | 39,263,229 42 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/valve_layer_stategic_1.csv: -------------------------------------------------------------------------------- 1 | ,link,node 2 | 0,10,10 3 | 1,20,20 4 | 2,201,40 5 | 3,289,50 6 | 4,330,60 7 | 5,335,60 8 | 6,333,601 9 | 7,329,61 10 | 8,335,61 11 | 9,101,101 12 | 10,103,101 13 | 11,103,103 14 | 12,105,105 15 | 13,107,105 16 | 14,115,107 17 | 15,109,109 18 | 16,225,111 19 | 17,111,111 20 | 18,112,111 21 | 19,114,113 22 | 20,113,113 23 | 21,112,115 24 | 22,115,115 25 | 23,114,115 26 | 24,119,117 27 | 25,121,117 28 | 26,123,119 29 | 27,171,119 30 | 28,173,119 31 | 29,297,120 32 | 30,122,120 33 | 31,121,120 34 | 32,123,121 35 | 33,122,121 36 | 34,125,121 37 | 35,125,123 38 | 36,131,125 39 | 37,129,125 40 | 38,135,127 41 | 39,133,127 42 | 40,145,129 43 | 41,137,129 44 | 42,145,139 45 | 43,149,141 46 | 44,153,141 47 | 45,151,143 48 | 46,155,145 49 | 47,155,147 50 | 48,159,149 51 | 49,163,151 52 | 50,161,151 53 | 51,163,153 54 | 52,175,157 55 | 53,175,159 56 | 54,179,161 57 | 55,221,161 58 | 56,179,163 59 | 57,180,163 60 | 58,181,164 61 | 59,185,169 62 | 60,183,169 63 | 61,187,169 64 | 62,189,171 65 | 63,187,171 66 | 64,189,173 67 | 65,197,177 68 | 66,201,179 69 | 67,199,179 70 | 68,315,181 71 | 69,193,181 72 | 70,203,183 73 | 71,199,183 74 | 72,204,184 75 | 73,202,185 76 | 74,205,185 77 | 75,209,187 78 | 76,186,187 79 | 77,207,189 80 | 78,209,189 81 | 79,313,189 82 | 80,223,191 83 | 81,217,191 84 | 82,116,193 85 | 83,217,193 86 | 84,219,193 87 | 85,219,195 88 | 86,223,197 89 | 87,229,199 90 | 88,231,199 91 | 89,323,201 92 | 90,231,201 93 | 91,205,204 94 | 92,319,205 95 | 93,237,205 96 | 94,240,206 97 | 95,237,207 98 | 96,238,207 99 | 97,240,208 100 | 98,241,209 101 | 99,269,211 102 | 100,245,211 103 | 101,261,213 104 | 102,245,213 105 | 103,249,215 106 | 104,257,217 107 | 105,249,217 108 | 106,261,229 109 | 107,271,229 110 | 108,273,237 111 | 109,269,237 112 | 110,275,239 113 | 111,283,239 114 | 112,275,241 115 | 113,277,241 116 | 114,285,247 117 | 115,281,247 118 | 116,295,249 119 | 117,283,249 120 | 118,295,251 121 | 119,287,255 122 | 120,289,255 123 | 121,293,255 124 | 122,303,257 125 | 123,297,257 126 | 124,301,259 127 | 125,307,261 128 | 126,305,261 129 | 127,117,263 130 | 128,307,263 131 | 129,321,265 132 | 130,183,265 133 | 131,311,267 134 | 132,215,267 135 | 133,325,269 136 | 134,211,269 137 | 135,191,271 138 | 136,315,271 139 | 137,319,273 140 | 138,317,273 141 | 139,239,275 142 | 140,323,275 143 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/valve_layer_stategic_2.csv: -------------------------------------------------------------------------------- 1 | ,link,node 2 | 0,330,60 3 | 1,329,61 4 | 2,101,101 5 | 3,105,105 6 | 4,225,111 7 | 5,111,111 8 | 6,114,113 9 | 7,112,115 10 | 8,115,115 11 | 9,119,117 12 | 10,123,119 13 | 11,171,119 14 | 12,297,120 15 | 13,122,120 16 | 14,123,121 17 | 15,122,121 18 | 16,131,125 19 | 17,135,127 20 | 18,145,129 21 | 19,149,141 22 | 20,163,151 23 | 21,179,161 24 | 22,179,163 25 | 23,185,169 26 | 24,183,169 27 | 25,189,171 28 | 26,201,179 29 | 27,315,181 30 | 28,203,183 31 | 29,202,185 32 | 30,209,187 33 | 31,207,189 34 | 32,209,189 35 | 33,223,191 36 | 34,116,193 37 | 35,217,193 38 | 36,229,199 39 | 37,323,201 40 | 38,319,205 41 | 39,237,207 42 | 40,269,211 43 | 41,261,213 44 | 42,257,217 45 | 43,261,229 46 | 44,273,237 47 | 45,275,239 48 | 46,275,241 49 | 47,285,247 50 | 48,295,249 51 | 49,287,255 52 | 50,289,255 53 | 51,303,257 54 | 52,307,261 55 | 53,117,263 56 | 54,321,265 57 | 55,311,267 58 | 56,325,269 59 | 57,191,271 60 | 58,319,273 61 | 59,239,275 62 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/valve_layer_stategic_3.csv: -------------------------------------------------------------------------------- 1 | ,link,node 2 | 0,225,111 3 | 1,112,115 4 | 2,123,119 5 | 3,297,120 6 | 4,123,121 7 | 5,185,169 8 | 6,207,189 9 | 7,116,193 10 | 8,287,255 11 | -------------------------------------------------------------------------------- /wntr/tests/networks_for_testing/valve_layer_stategic_4.csv: -------------------------------------------------------------------------------- 1 | ,link,node 2 | -------------------------------------------------------------------------------- /wntr/tests/test_epanet_exceptions.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from os.path import abspath, dirname, join, exists 3 | 4 | import wntr.epanet.exceptions 5 | 6 | testdir = dirname(abspath(__file__)) 7 | datadir = join(testdir, "networks_for_testing") 8 | 9 | 10 | class TestEpanetExceptions(unittest.TestCase): 11 | 12 | def test_epanet_exception(self): 13 | try: 14 | raise wntr.epanet.exceptions.EpanetException(213, '13:00:00 pm', 'Cannot specify am/pm for times greater than 12:00:00') 15 | except Exception as e: 16 | self.assertTupleEqual(e.args, ("(Error 213) invalid option value '13:00:00 pm' ['Cannot specify am/pm for times greater than 12:00:00']",)) 17 | try: 18 | raise wntr.epanet.exceptions.EpanetException(999) 19 | except Exception as e: 20 | self.assertTupleEqual(e.args, ('(Error 999) unknown error',)) 21 | try: 22 | raise wntr.epanet.exceptions.EpanetException(108) 23 | except Exception as e: 24 | self.assertTupleEqual(e.args, ('(Error 108) cannot use external file while hydraulics solver is active',)) 25 | 26 | def test_epanet_syntax_error(self): 27 | try: 28 | raise wntr.epanet.exceptions.ENSyntaxError(223, line_num=38, line='I AM A SYNTAX ERROR') 29 | except SyntaxError as e: 30 | self.assertTupleEqual(e.args, ('(Error 223) not enough nodes in network, at line 38:\n I AM A SYNTAX ERROR',)) 31 | 32 | def test_epanet_key_error(self): 33 | try: 34 | raise wntr.epanet.exceptions.ENKeyError(206, 'NotACurve') 35 | except KeyError as e: 36 | self.assertTupleEqual(e.args, ("(Error 206) undefined curve, 'NotACurve'",)) 37 | 38 | def test_epanet_value_error(self): 39 | try: 40 | raise wntr.epanet.exceptions.ENValueError(213, 423.0e28) 41 | except ValueError as e: 42 | self.assertTupleEqual(e.args, ('(Error 213) invalid option value 4.23e+30',)) 43 | 44 | def test_broken_time_string(self): 45 | f = wntr.epanet.io.InpFile() 46 | inp_file = join(datadir, "bad_times.inp") 47 | try: 48 | f.read(inp_file) 49 | except Exception as e: 50 | self.assertIsInstance(e.__cause__, wntr.epanet.exceptions.ENValueError) 51 | else: 52 | self.fail('Failed to catch expected errors in bad_times.inp') 53 | 54 | def test_broken_syntax(self): 55 | f = wntr.epanet.io.InpFile() 56 | inp_file = join(datadir, "bad_syntax.inp") 57 | try: 58 | f.read(inp_file) 59 | except Exception as e: 60 | self.assertIsInstance(e, wntr.epanet.exceptions.ENSyntaxError) 61 | else: 62 | self.fail('Failed to catch expected errors in bad_syntax.inp') 63 | 64 | def test_bad_values(self): 65 | f = wntr.epanet.io.InpFile() 66 | inp_file = join(datadir, "bad_values.inp") 67 | try: 68 | f.read(inp_file) 69 | except Exception as e: 70 | self.assertIsInstance(e.__cause__, wntr.epanet.exceptions.ENKeyError) 71 | else: 72 | self.fail('Failed to catch expected errors in bad_values.inp') 73 | 74 | if __name__ == "__main__": 75 | unittest.main() 76 | -------------------------------------------------------------------------------- /wntr/tests/test_epanet_msx_io.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import warnings 3 | from os.path import abspath, dirname, join 4 | 5 | import numpy as np 6 | import pandas as pd 7 | import wntr 8 | import wntr.msx 9 | import wntr.epanet.msx 10 | 11 | testdir = dirname(abspath(str(__file__))) 12 | test_network_dir = join(testdir, "networks_for_testing") 13 | inp_filename = join(test_network_dir, "msx_example.inp") 14 | msx_filename = join(test_network_dir, "msx_example.msx") 15 | 16 | 17 | class Test(unittest.TestCase): 18 | @classmethod 19 | def setUpClass(self): 20 | pass 21 | 22 | @classmethod 23 | def tearDownClass(self): 24 | pass 25 | 26 | def test_msx_io(self): 27 | wn_model = wntr.network.WaterNetworkModel(inp_file_name=inp_filename) 28 | msx_model = wntr.msx.MsxModel(msx_file_name=msx_filename) 29 | wntr.epanet.InpFile().write("test.inp", wn_model) 30 | wntr.epanet.msx.MsxFile().write("test.msx", msx_model) 31 | msx_model2 = wntr.msx.MsxModel(msx_file_name="test.msx") 32 | true_vars = ["AS3", "AS5", "AS5s", "AStot", "NH2CL", "Ka", "Kb", "K1", "K2", "Smax", "Ks"] 33 | true_vars.sort() 34 | in_vars = msx_model.species_name_list + msx_model.constant_name_list + msx_model.parameter_name_list + msx_model.term_name_list 35 | in_vars.sort() 36 | io_vars = msx_model2.species_name_list + msx_model2.constant_name_list + msx_model2.parameter_name_list + msx_model2.term_name_list 37 | io_vars.sort() 38 | self.assertListEqual(true_vars, in_vars) 39 | self.assertListEqual(true_vars, io_vars) 40 | 41 | if __name__ == "__main__": 42 | unittest.main(verbosity=2) 43 | -------------------------------------------------------------------------------- /wntr/tests/test_epanet_msx_sim.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import warnings 3 | from os.path import abspath, dirname, join 4 | 5 | import numpy as np 6 | import pandas as pd 7 | import wntr 8 | import wntr.msx 9 | import wntr.epanet.msx 10 | 11 | testdir = dirname(abspath(str(__file__))) 12 | test_network_dir = join(testdir, "networks_for_testing") 13 | inp_filename = join(test_network_dir, "msx_example.inp") 14 | msx_filename = join(test_network_dir, "msx_example.msx") 15 | 16 | 17 | class TestEpanetMSXSim(unittest.TestCase): 18 | @classmethod 19 | def setUpClass(self): 20 | pass 21 | 22 | @classmethod 23 | def tearDownClass(self): 24 | pass 25 | 26 | def test_msx_sim(self): 27 | wn = wntr.network.WaterNetworkModel(inp_file_name=inp_filename) 28 | wn.add_msx_model(msx_filename=msx_filename) 29 | sim = wntr.sim.EpanetSimulator(wn) 30 | msx_model = wntr.msx.MsxModel(msx_file_name=msx_filename) 31 | 32 | # run sim 33 | res = sim.run_sim() 34 | 35 | # check results object keys 36 | for species in wn.msx.species_name_list: 37 | assert species in res.node.keys() 38 | assert species in res.link.keys() 39 | 40 | 41 | # sanity check at test point 42 | expected = 10.032905 # Node 'C' at time 136800 for AStot 43 | error = abs( 44 | (res.node["AStot"].loc[136800, "C"] - expected) / expected 45 | ) 46 | self.assertLess(error, 0.0001) # 0.01% error 47 | 48 | 49 | if __name__ == "__main__": 50 | unittest.main(verbosity=2) 51 | -------------------------------------------------------------------------------- /wntr/tests/test_epanet_msx_tooklit.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import warnings 3 | from os.path import abspath, dirname, join 4 | 5 | import numpy as np 6 | import pandas as pd 7 | import wntr 8 | import wntr.msx 9 | import wntr.epanet.msx 10 | import wntr.epanet.msx.toolkit 11 | 12 | testdir = dirname(abspath(str(__file__))) 13 | test_network_dir = join(testdir, "networks_for_testing") 14 | inp_filename = join(test_network_dir, 'msx_example.inp') 15 | msx_filename = join(test_network_dir, 'msx_example.msx') 16 | 17 | class Test(unittest.TestCase): 18 | @classmethod 19 | def setUpClass(self): 20 | pass 21 | 22 | @classmethod 23 | def tearDownClass(self): 24 | pass 25 | 26 | def test_msx_io(self): 27 | wn_model = wntr.network.WaterNetworkModel(inp_file_name=inp_filename) 28 | msx_model = wntr.msx.MsxModel(msx_file_name=msx_filename) 29 | wntr.epanet.msx.toolkit.MSXepanet(inp_filename, msxfile=msx_filename) 30 | 31 | 32 | 33 | if __name__ == "__main__": 34 | unittest.main(verbosity=2) 35 | -------------------------------------------------------------------------------- /wntr/tests/test_examples.py: -------------------------------------------------------------------------------- 1 | # This is a test to ensure all of the examples run. 2 | import os 3 | import sys 4 | import unittest 5 | import pytest 6 | from os import listdir 7 | from os.path import abspath, dirname, isfile, join 8 | from subprocess import call 9 | 10 | testdir = dirname(abspath(str(__file__))) 11 | examplesdir = join(testdir, "..", "..", "examples") 12 | 13 | 14 | class TestExamples(unittest.TestCase): 15 | @classmethod 16 | def setUpClass(self): 17 | import wntr 18 | 19 | self.wntr = wntr 20 | 21 | @classmethod 22 | def tearDownClass(self): 23 | pass 24 | 25 | @pytest.mark.time_consuming 26 | def test_that_examples_run(self): 27 | cwd = os.getcwd() 28 | os.chdir(examplesdir) 29 | example_files = [ 30 | f 31 | for f in listdir(examplesdir) 32 | if isfile(join(examplesdir, f)) 33 | and f.endswith(".py") 34 | and not f.startswith("test") 35 | ] 36 | flag = 0 37 | failed_examples = [] 38 | for f in example_files: 39 | if "sensor_placement" in f: 40 | try: 41 | import chama 42 | except ImportError: 43 | continue 44 | tmp_flag = call([sys.executable, join(examplesdir, f)]) 45 | print(f, tmp_flag) 46 | if tmp_flag == 1: 47 | failed_examples.append(f) 48 | flag = 1 49 | os.chdir(cwd) 50 | if len(failed_examples) > 0: 51 | print("failed examples: {0}".format(failed_examples)) 52 | self.assertEqual(flag, 0) 53 | 54 | 55 | if __name__ == "__main__": 56 | unittest.main() 57 | -------------------------------------------------------------------------------- /wntr/tests/test_metrics_economic.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from os.path import abspath, dirname, join 3 | 4 | import pandas as pd 5 | import wntr 6 | from pandas.testing import assert_frame_equal, assert_series_equal 7 | 8 | testdir = dirname(abspath(str(__file__))) 9 | datadir = join(testdir, "networks_for_testing") 10 | netdir = join(testdir, "..", "..", "examples", "networks") 11 | 12 | 13 | class TestEconomicMetrics(unittest.TestCase): 14 | def test_annual_network_cost1(self): 15 | inp_file = join(netdir, "Net1.inp") 16 | wn = wntr.network.WaterNetworkModel(inp_file) 17 | 18 | cost = wntr.metrics.annual_network_cost(wn) 19 | self.assertAlmostEqual(cost, 460147, 0) 20 | 21 | def test_annual_network_cost2(self): 22 | # Network cost using a tank volume curve 23 | inp_file = join(datadir, "Anytown_multipointcurves.inp") 24 | wn = wntr.network.WaterNetworkModel(inp_file) 25 | 26 | cost = wntr.metrics.annual_network_cost(wn) 27 | self.assertAlmostEqual(cost, 1201467.78, 0) 28 | 29 | def test_annual_ghg_emissions(self): 30 | inp_file = join(netdir, "Net1.inp") 31 | wn = wntr.network.WaterNetworkModel(inp_file) 32 | 33 | cost = wntr.metrics.annual_ghg_emissions(wn) 34 | self.assertAlmostEqual(cost, 410278, 0) 35 | 36 | 37 | if __name__ == "__main__": 38 | unittest.main() 39 | -------------------------------------------------------------------------------- /wntr/tests/test_metrics_entropy.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from os.path import abspath, dirname, join 3 | 4 | import numpy as np 5 | import wntr 6 | 7 | testdir = dirname(abspath(str(__file__))) 8 | datadir = join(testdir, "networks_for_testing") 9 | 10 | 11 | class TestEntropyMetric(unittest.TestCase): 12 | def test_layout1(self): 13 | inp_file = join(datadir, "Awumah_layout1.inp") 14 | wn = wntr.network.WaterNetworkModel(inp_file) 15 | 16 | attr = { 17 | "1": 940.7, 18 | "2": 550.0, 19 | "3": 659.3, 20 | "4": 290.7, 21 | "5": 400.0, 22 | "6": 59.3, 23 | "7": 450.0, 24 | "8": 200.0, 25 | "9": 300.0, 26 | "10": 250.0, 27 | "11": 100.0, 28 | "12": 150.0, 29 | } 30 | 31 | G_flowrate = wn.to_graph(link_weight=attr, modify_direction=True) 32 | 33 | [S, S_ave] = wntr.metrics.entropy(G_flowrate) 34 | 35 | # The values in the paper are different, perhaps due to significant figure 36 | # rounding during the calculation 37 | expected_Saverage = 0.0805 # 0.088 38 | error = abs((S.mean() - expected_Saverage) / expected_Saverage) 39 | self.assertLess(error, 0.05) # 5% error 40 | 41 | expected_Smax = 0.5108 # 0.5130 42 | error = abs((S.max() - expected_Smax) / expected_Smax) 43 | 44 | expected_S_ave = 2.289 # 2.280 45 | error = abs((S_ave - expected_S_ave) / expected_S_ave) 46 | self.assertLess(error, 0.05) # 5% error 47 | 48 | def test_layout8(self): 49 | inp_file = join(datadir, "Awumah_layout8.inp") 50 | wn = wntr.network.WaterNetworkModel(inp_file) 51 | 52 | attr = { 53 | "1": 678.8, 54 | "2": 403.3, 55 | "3": 921.2, 56 | "4": 175.5, 57 | "5": 253.3, 58 | "6": 227.1, 59 | "7": 126.3, 60 | "8": 544.1, 61 | "9": 126.3, 62 | "10": 279.6, 63 | "11": 200.0, 64 | "12": 144.1, 65 | "13": 126.3, 66 | "14": 79.6, 67 | "15": 44.1, 68 | "16": 20.4, 69 | } 70 | 71 | G_flowrate = wn.to_graph(link_weight=attr, modify_direction=True) 72 | 73 | [S, S_ave] = wntr.metrics.entropy(G_flowrate) 74 | 75 | # The values in the paper are different, perhaps due to significant figure 76 | # rounding during the calculation 77 | expected_Saverage = 0.4391 # 0.3860 78 | error = abs((S.mean() - expected_Saverage) / expected_Saverage) 79 | self.assertLess(error, 0.05) # 5% error 80 | 81 | expected_Smax = 1.1346 # 0.5130 82 | error = abs((S.max() - expected_Smax) / expected_Smax) 83 | self.assertLess(error, 0.05) # 5% error 84 | 85 | expected_S_ave = 2.544 # 2.670 86 | error = abs((S_ave - expected_S_ave) / expected_S_ave) 87 | self.assertLess(error, 0.05) # 5% error 88 | 89 | 90 | if __name__ == "__main__": 91 | unittest.main() 92 | -------------------------------------------------------------------------------- /wntr/tests/test_metrics_population.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from os.path import abspath, dirname, join 3 | import numpy as np 4 | import pandas as pd 5 | import wntr 6 | from pandas.testing import assert_frame_equal, assert_series_equal 7 | 8 | testdir = dirname(abspath(str(__file__))) 9 | datadir = join(testdir, "networks_for_testing") 10 | net3dir = join(testdir, "..", "..", "examples", "networks") 11 | 12 | 13 | class TestPopulationMetrics(unittest.TestCase): 14 | def test_population_net3(self): 15 | inp_file = join(net3dir, "Net3.inp") 16 | wn = wntr.network.WaterNetworkModel(inp_file) 17 | pop = wntr.metrics.population(wn) 18 | expected = 79000 19 | error = abs((pop.sum() - expected) / expected) 20 | self.assertLess(error, 0.01) # 1% error 21 | 22 | def test_population_net6(self): 23 | inp_file = join(net3dir, "Net6.inp") 24 | wn = wntr.network.WaterNetworkModel(inp_file) 25 | pop = wntr.metrics.population(wn) 26 | expected = 152000 27 | error = abs((pop.sum() - expected) / expected) 28 | self.assertLess(error, 0.01) # 1% error 29 | 30 | def test_population_impacted(self): # tests query and population impacted 31 | 32 | pop = pd.Series([100, 200, 300, 400, 500], index=["J1", "J2", "J3", "J4", "J5"]) 33 | 34 | # arg1 as a Series, arg2 as a scalar 35 | wsa = pd.Series([0.6, 0.7, 0.8, 0.9, 1], index=["J1", "J2", "J3", "J4", "J5"]) 36 | pop_impacted = wntr.metrics.population_impacted(pop, wsa, np.less, 0.8) 37 | expected = pd.Series([100, 200, 0, 0, 0], index=["J1", "J2", "J3", "J4", "J5"]) 38 | assert_series_equal(pop_impacted, expected, check_dtype=False) 39 | 40 | # arg1 as a Series, arg2 as a Series 41 | wsa = pd.Series([0.6, 0.7, 0.8, 0.9, 1], index=["J1", "J2", "J3", "J4", "J5"]) 42 | wsa_threshold = pd.Series([1, 0, 1, 0, 1], index=["J1", "J2", "J3", "J4", "J5"]) 43 | pop_impacted = wntr.metrics.population_impacted( 44 | pop, wsa, np.less_equal, wsa_threshold 45 | ) 46 | expected = pd.Series( 47 | [100, 0, 300, 0, 500], index=["J1", "J2", "J3", "J4", "J5"] 48 | ) 49 | assert_series_equal(pop_impacted, expected, check_dtype=False) 50 | 51 | # arg1 as a DataFrame, arg2 as a scalar 52 | wsa = pd.Series([0.6, 0.7, 0.8, 0.9, 1], index=["J1", "J2", "J3", "J4", "J5"]) 53 | wsa = wsa.to_frame().transpose() 54 | wsa.loc[1, :] = [0, 1, 0, 1, 0] 55 | wsa.loc[2, :] = [1, 0, 1, 0, 1] 56 | pop_impacted = wntr.metrics.population_impacted(pop, wsa, np.less, 0.8) 57 | expected = pd.DataFrame( 58 | [[100, 200, 0, 0, 0], [100, 0, 300, 0, 500], [0, 200, 0, 400, 0]], 59 | columns=["J1", "J2", "J3", "J4", "J5"], 60 | index=[0, 1, 2], 61 | ) 62 | assert_frame_equal(pop_impacted, expected, check_dtype=False) 63 | 64 | 65 | if __name__ == "__main__": 66 | unittest.main() 67 | -------------------------------------------------------------------------------- /wntr/tests/test_metrics_pump_cost.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from os.path import abspath, dirname, join 3 | 4 | import pandas as pd 5 | 6 | testdir = dirname(abspath(str(__file__))) 7 | test_datadir = join(testdir, "networks_for_testing") 8 | ex_datadir = join(testdir, "..", "..", "examples", "networks") 9 | 10 | 11 | class TestPumpNet3(unittest.TestCase): 12 | @classmethod 13 | def setUpClass(self): 14 | import wntr 15 | 16 | self.wntr = wntr 17 | 18 | inp_file = join(ex_datadir, "Net3.inp") 19 | self.wn = self.wntr.network.WaterNetworkModel(inp_file) 20 | self.wn.options.energy.global_efficiency = 75 # 75% 21 | self.wn.options.energy.global_price = 3.61e-8 # $/J; equal to $0.13/kW-h 22 | self.wn.options.time.hydraulic_timestep = 15*60 23 | self.wn.options.time.quality_timestep = 15*60 24 | self.wn.options.time.report_timestep = 15*60 25 | 26 | @classmethod 27 | def tearDownClass(self): 28 | pass 29 | 30 | def test_energy_report(self): 31 | 32 | sim = self.wntr.sim.EpanetSimulator(self.wn) 33 | results = sim.run_sim() 34 | 35 | flowrate = results.link["flowrate"].loc[:, self.wn.pump_name_list] 36 | head = results.node["head"].loc[:, self.wn.node_name_list] 37 | pump_energy = self.wntr.metrics.pump_energy(flowrate, head, self.wn) 38 | 39 | pump_status = results.link["status"].loc[:, self.wn.pump_name_list] 40 | utilization = pump_status.mean() * 100 41 | 42 | timestep = self.wn.options.time.report_timestep 43 | total_pumped_volume_Mgal = (flowrate * timestep * 264.172 / 1e6).sum() 44 | pump_energy_kWhr = pump_energy / (1000 * 3600) 45 | total_pump_energy_kWhr = pump_energy_kWhr.sum() 46 | energy_per_vol = total_pump_energy_kWhr / total_pumped_volume_Mgal # kW-hr/Mgal 47 | 48 | pump_power_kW = pump_energy_kWhr / (timestep / 3600) 49 | average_power = {} 50 | for pump in pump_power_kW.columns: 51 | average_power[pump] = pump_power_kW.loc[pump_status[pump] == 1, pump].mean() 52 | average_power = pd.Series(average_power) 53 | 54 | peak_power = pump_power_kW.max() 55 | 56 | pump_cost = self.wntr.metrics.pump_cost(pump_energy, self.wn) 57 | cost_per_day = pump_cost.sum() / 7 # pump energy (J) * cost ($/J) 58 | 59 | # Compare results to an Energy Report from EPANET GUI (setting global price to $0.13) 60 | results = pd.DataFrame(index=["10", "335"]) 61 | results["utilization"] = utilization 62 | results["energy_per_vol"] = energy_per_vol 63 | results["average_power"] = average_power 64 | results["peak_power"] = peak_power 65 | results["cost_per_day"] = cost_per_day 66 | 67 | solution = { 68 | "utilization": [58.33, 23.60], 69 | "energy_per_vol": [313.71, 394.29], 70 | "average_power": [62.05, 309.41], 71 | "peak_power": [62.76, 310.84], 72 | "cost_per_day": [112.93, 227.85], 73 | } 74 | solution = pd.DataFrame(solution, index=["10", "335"]) 75 | 76 | error = abs(results - solution) / solution 77 | 78 | self.assertLess(error.max().max(), 0.01) 79 | 80 | 81 | if __name__ == "__main__": 82 | unittest.main() 83 | -------------------------------------------------------------------------------- /wntr/tests/test_network_layers.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from os.path import abspath, dirname, join 3 | 4 | import pandas as pd 5 | import wntr 6 | from pandas.testing import assert_frame_equal 7 | 8 | testdir = dirname(abspath(str(__file__))) 9 | test_datadir = join(testdir, "networks_for_testing") 10 | ex_datadir = join(testdir, "..", "..", "examples", "networks") 11 | 12 | 13 | class TestValveLayer(unittest.TestCase): 14 | @classmethod 15 | def setUpClass(self): 16 | 17 | inp_file = join(ex_datadir, "Net3.inp") 18 | self.wn = wntr.network.WaterNetworkModel(inp_file) 19 | 20 | @classmethod 21 | def tearDownClass(self): 22 | pass 23 | 24 | def test_valve_layer_random(self): 25 | 26 | valves = wntr.network.generate_valve_layer(self.wn, "random", 40, 123) 27 | 28 | # valves.to_csv('valve_layer_random.csv') 29 | # ax = wntr.graphics.plot_network(self.wn, node_size=7, valve_layer=valves, 30 | # title='Random, 40') 31 | 32 | expected = pd.read_csv( 33 | join(test_datadir, "valve_layer_random.csv"), index_col=0, dtype="object" 34 | ) 35 | 36 | assert_frame_equal(valves, expected) 37 | 38 | def test_valve_layer_strategic(self): 39 | 40 | # Compute the expected number of valves for N-0, N-1, N-2, N-3, N-4 41 | G = self.wn.to_graph() 42 | node_degree = pd.Series(dict(G.degree())) 43 | expected_n_valves = pd.Series(index=[4, 3, 2, 1, 0]) 44 | for N in [4, 3, 2, 1, 0]: 45 | expected_n_valves[N] = node_degree[node_degree > N].shape[0] 46 | 47 | expected_n_valves = expected_n_valves.cumsum() 48 | 49 | for N in [0, 1, 2, 3, 4]: 50 | 51 | valves = wntr.network.generate_valve_layer(self.wn, "strategic", N, 123) 52 | 53 | # valves.to_csv('valve_layer_stategic_'+str(N)+'.csv') 54 | # ax = wntr.graphics.plot_network(self.wn, node_size=7, valve_layer=valves, 55 | # title='Strategic, '+str(N)) 56 | 57 | expected_valves = pd.read_csv( 58 | join(test_datadir, "valve_layer_stategic_" + str(N) + ".csv"), 59 | index_col=0, 60 | dtype="object", 61 | ) 62 | 63 | self.assertEqual(valves.shape[0], expected_n_valves[N]) 64 | assert_frame_equal(valves, expected_valves, check_index_type=False) 65 | 66 | 67 | if __name__ == "__main__": 68 | unittest.main() 69 | -------------------------------------------------------------------------------- /wntr/tests/test_network_minor_loss.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import wntr 3 | 4 | 5 | class TestMinorLosses(unittest.TestCase): 6 | @classmethod 7 | def setUpClass(self): 8 | pass 9 | 10 | @classmethod 11 | def tearDownClass(self): 12 | pass 13 | 14 | def test_pipe_minor_loss(self): 15 | wn = wntr.network.WaterNetworkModel() 16 | wn.options.time.duration = 3600 * 2 17 | wn.add_reservoir(name="r1", base_head=20.0) 18 | wn.add_junction(name="j1", base_demand=0.1) 19 | wn.add_pipe( 20 | name="p1", start_node_name="r1", end_node_name="j1", minor_loss=100.0 21 | ) 22 | wn.options.hydraulic.demand_model = "DDA" 23 | sim = wntr.sim.WNTRSimulator(wn) 24 | 25 | results1 = sim.run_sim() 26 | wntr.network.write_inpfile(wn, "temp.inp", "CMH") 27 | 28 | wn2 = wntr.network.WaterNetworkModel("temp.inp") 29 | sim = wntr.sim.EpanetSimulator(wn2) 30 | results2 = sim.run_sim() 31 | 32 | head1 = results1.node["head"].j1.iloc[0] 33 | head2 = results2.node["head"].j1.iloc[0] 34 | head_diff = abs(head1 - head2) 35 | self.assertLess(head_diff, 0.01) 36 | -------------------------------------------------------------------------------- /wntr/tests/test_network_pump_outage.py: -------------------------------------------------------------------------------- 1 | import math 2 | import unittest 3 | from os.path import abspath, dirname, join 4 | 5 | from wntr.network.controls import Control, Rule 6 | 7 | testdir = dirname(abspath(str(__file__))) 8 | test_datadir = join(testdir, "networks_for_testing") 9 | ex_datadir = join(testdir, "..", "..", "examples", "networks") 10 | 11 | 12 | class TestOutageResults(unittest.TestCase): 13 | @classmethod 14 | def setUpClass(self): 15 | import wntr 16 | 17 | self.wntr = wntr 18 | 19 | @classmethod 20 | def tearDownClass(self): 21 | pass 22 | 23 | def test_outage(self): 24 | inp_file = join(ex_datadir, "Net3.inp") 25 | wn = self.wntr.network.WaterNetworkModel(inp_file) 26 | wn.convert_controls_to_rules(priority=3) 27 | 28 | # Original simulation 29 | sim = self.wntr.sim.EpanetSimulator(wn) 30 | results1 = sim.run_sim() 31 | 32 | pump_flowrate = results1.link["flowrate"].loc[13 * 3600 : 36 * 3600, "10"] 33 | assert pump_flowrate.sum() > 0 34 | 35 | # Add power outage 36 | pump = wn.get_link("10") 37 | pump.add_outage(wn, 12 * 3600, 36 * 3600) 38 | 39 | sim = self.wntr.sim.EpanetSimulator(wn) 40 | results2 = sim.run_sim() 41 | 42 | assert "10_outage" in wn.control_name_list 43 | num_controls = wn.num_controls 44 | 45 | pump_flowrate = results2.link["flowrate"].loc[13 * 3600 : 36 * 3600, "10"] 46 | assert pump_flowrate.sum() == 0 47 | 48 | # Remove power outage 49 | pump.remove_outage(wn) 50 | 51 | assert wn.num_controls == num_controls - 1 52 | 53 | sim = self.wntr.sim.EpanetSimulator(wn) 54 | results3 = sim.run_sim() 55 | 56 | pump_flowrate = results3.link["flowrate"].loc[13 * 3600 : 36 * 3600, "10"] 57 | assert pump_flowrate.sum() > 0 58 | 59 | # (results1.node['pressure'] - results2.node['pressure']).plot() 60 | # (results1.node['pressure'] - results3.node['pressure']).plot() 61 | 62 | max_diff = ( 63 | abs(results1.node["pressure"] - results3.node["pressure"]).max().max() 64 | ) 65 | 66 | assert max_diff < 0.0001 67 | 68 | 69 | if __name__ == "__main__": 70 | unittest.main() 71 | 72 | -------------------------------------------------------------------------------- /wntr/tests/test_scenario_fragility_curve.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from os.path import abspath, dirname, join 3 | 4 | import numpy as np 5 | import pandas as pd 6 | import wntr 7 | from scipy.stats import lognorm, norm 8 | 9 | testdir = dirname(abspath(str(__file__))) 10 | datadir = join(testdir, "..", "..", "tests", "networks_for_testing") 11 | 12 | FC1 = wntr.scenario.FragilityCurve() 13 | FC1.add_state("Major", 2, {"Default": norm(loc=1, scale=2)}) 14 | FC1.add_state("Minor", 1, {"Default": norm(loc=0, scale=1)}) 15 | 16 | FC2 = wntr.scenario.FragilityCurve() 17 | FC2.add_state( 18 | "Minor", 19 | 1, 20 | {"Default": lognorm(0.25, loc=0, scale=1), "3": lognorm(0.2, loc=0, scale=1)}, 21 | ) 22 | FC2.add_state("Major", 2, {"Default": lognorm(0.25, loc=1, scale=2)}) 23 | 24 | # x = np.linspace(-5,5,100) 25 | # for name, state in FC2.states(): 26 | # dist=state.distribution['Default'] 27 | # plt.plot(x,dist.cdf(x), label=name) 28 | # plt.ylim((0,1)) 29 | # plt.legend() 30 | 31 | 32 | class TestFragilityCurveScenario(unittest.TestCase): 33 | def test_get_priority_map(self): 34 | priority_map = FC1.get_priority_map() 35 | self.assertDictEqual(priority_map, {None: 0, "Minor": 1, "Major": 2}) 36 | 37 | def test_cdf_probability(self): 38 | x = pd.Series({"1": 0, "2": 1, "3": 2}) 39 | Pr = FC1.cdf_probability(x) 40 | self.assertEqual(Pr.loc["1", "Minor"], 0.5) 41 | self.assertLess(Pr.loc["2", "Minor"] - 0.841, 0.001) 42 | self.assertLess(Pr.loc["3", "Minor"] - 0.977, 0.001) 43 | self.assertEqual(Pr.loc["2", "Major"], 0.5) 44 | 45 | def test_sample_damage_state(self): 46 | x = pd.Series({"1": 0, "2": 1, "3": 2}) 47 | Pr = FC1.cdf_probability(x) 48 | states = FC1.sample_damage_state(Pr, seed=45) 49 | # p with random seed of 45 50 | # 1 0.989012 51 | # 2 0.549545 52 | # 3 0.281447 53 | self.assertEqual(states.loc["1"], None) 54 | self.assertEqual(states.loc["2"], "Minor") 55 | self.assertEqual(states.loc["3"], "Major") 56 | 57 | 58 | if __name__ == "__main__": 59 | unittest.main() 60 | -------------------------------------------------------------------------------- /wntr/tests/test_sim_PDD.py: -------------------------------------------------------------------------------- 1 | import math 2 | import unittest 3 | from os.path import abspath, dirname, join 4 | 5 | testdir = dirname(abspath(str(__file__))) 6 | test_datadir = join(testdir, "networks_for_testing") 7 | ex_datadir = join(testdir, "..", "..", "examples", "networks") 8 | 9 | 10 | class TestPDD(unittest.TestCase): 11 | @classmethod 12 | def setUpClass(self): 13 | import wntr 14 | 15 | self.wntr = wntr 16 | 17 | @classmethod 18 | def tearDownClass(self): 19 | pass 20 | 21 | def test_pdd_with_wntr(self): 22 | inp_file = join(test_datadir, "simulator.inp") 23 | wn = self.wntr.network.WaterNetworkModel(inp_file) 24 | res1 = wn.get_node("reservoir1") 25 | res1.head_timeseries.base_value = 10.0 26 | p1 = wn.get_link("pipe1") 27 | p1.length = 0.0 28 | p2 = wn.get_link("pipe2") 29 | p2.length = 0.0 30 | 31 | for jname, j in wn.nodes(self.wntr.network.Junction): 32 | j.minimum_pressure = 0.0 33 | j.required_pressure = 15.0 34 | 35 | wn.options.hydraulic.demand_model = "PDA" 36 | sim = self.wntr.sim.WNTRSimulator(wn) 37 | results = sim.run_sim() 38 | 39 | for t in results.time: 40 | self.assertEqual( 41 | results.node["demand"].at[t, "junction2"], 42 | 150.0 / 3600.0 * math.sqrt((10.0 - 0.0) / (15.0 - 0.0)), 43 | ) 44 | 45 | 46 | if __name__ == "__main__": 47 | unittest.main() 48 | -------------------------------------------------------------------------------- /wntr/tests/test_sim_results.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from os.path import abspath, dirname, join 3 | #import matplotlib.pylab as plt 4 | import wntr 5 | 6 | testdir = dirname(abspath(str(__file__))) 7 | datadir = join(testdir, "..", "..", "examples", "networks") 8 | 9 | class TestSimulationResults(unittest.TestCase): 10 | 11 | @classmethod 12 | def setUpClass(self): 13 | inp_file = join(datadir, "Net2.inp") 14 | self.wn = wntr.network.WaterNetworkModel(inp_file) 15 | sim = wntr.sim.EpanetSimulator(self.wn) 16 | sim.run_sim() 17 | 18 | binfile = wntr.epanet.io.BinFile() 19 | results_GPM = binfile.read('temp.bin', False, False, False) 20 | # time index needs to be converted to hours 21 | for key in results_GPM.node.keys(): 22 | results_GPM.node[key].index = results_GPM.node[key].index/3600 23 | for key in results_GPM.link.keys(): 24 | results_GPM.link[key].index = results_GPM.link[key].index/3600 25 | 26 | self.results_GPM = results_GPM 27 | 28 | self.tol = {} 29 | self.tol['node'] = {} 30 | self.tol['node']['demand'] = 1e-3 31 | self.tol['node']['head'] = 1e-3 32 | self.tol['node']['pressure'] = 1e-3 33 | self.tol['node']['quality'] = 1e-3 34 | self.tol['link'] = {} 35 | self.tol['link']['flowrate'] = 1e-2 36 | self.tol['link']['velocity'] = 1e-3 37 | self.tol['link']['headloss'] = 1e-3 38 | self.tol['link']['status'] = None # status is not checked. 39 | self.tol['link']['setting'] = 1e-5 40 | self.tol['link']['friction_factor'] = 1e-5 41 | self.tol['link']['quality'] = 1e-5 42 | self.tol['link']['reaction_rate'] = 1e-3 43 | 44 | @classmethod 45 | def tearDownClass(self): 46 | pass 47 | 48 | 49 | 50 | if __name__ == "__main__": 51 | unittest.main() 52 | 53 | -------------------------------------------------------------------------------- /wntr/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The wntr.utils package contains helper functions. 3 | """ 4 | from wntr.utils import logger 5 | 6 | -------------------------------------------------------------------------------- /wntr/utils/doc_inheritor.py: -------------------------------------------------------------------------------- 1 | """Utilitiy for inheriting docstrings.""" 2 | 3 | import inspect 4 | 5 | 6 | class DocInheritor(object): 7 | def __init__(self, methods): 8 | self.methods = methods 9 | 10 | def __call__(self, cls): 11 | mro = inspect.getmro(cls) 12 | if mro[0] is not cls: 13 | raise RuntimeError('Unexpected') 14 | if len(mro) < 2: 15 | raise ValueError('Cannot determine parent class for {0}'.format(cls)) 16 | parent = mro[1] 17 | for meth in self.methods: 18 | if not hasattr(parent, meth): 19 | raise ValueError('Parent class {0} does not have method {1}'.format(parent, meth)) 20 | setattr(getattr(cls, meth), '__doc__', getattr(parent, meth).__doc__) 21 | return cls 22 | 23 | 24 | # Example: 25 | # 26 | # class Foo(object): 27 | # def __init__(self, x): 28 | # """ 29 | # Parameters 30 | # ---------- 31 | # x: float 32 | # """ 33 | # self.x = x 34 | # 35 | # def inc(self): 36 | # """ 37 | # increment x 38 | # """ 39 | # self.x += 1 40 | # 41 | # 42 | # @DocInheritor({'inc'}) 43 | # class Bar(Foo): 44 | # def inc(self): 45 | # self.x += 2 46 | -------------------------------------------------------------------------------- /wntr/utils/logger.py: -------------------------------------------------------------------------------- 1 | """Fuctions to set up a default handler for WNTR that will output to the console and to wntr.log.""" 2 | 3 | import logging 4 | logging.getLogger('wntr').addHandler(logging.NullHandler()) 5 | 6 | class _LogWrapper(object): # pragma: no cover 7 | initialized = None 8 | 9 | def __init__(self): 10 | self.logger = logger = logging.getLogger('wntr') 11 | if not len(self.logger.handlers): 12 | logger.setLevel(logging.DEBUG) 13 | # warnings/notes are sent to the final report using the logfile 14 | self.fh = fh = logging.FileHandler('wntr.log', mode='w') 15 | fh.setLevel(logging.WARNING) 16 | # all info is sent to the screen 17 | self.ch = ch = logging.StreamHandler() 18 | ch.setLevel(logging.INFO) 19 | formatter = logging.Formatter( 20 | '%(name)-12s %(levelname)-8s %(message)s') 21 | fh.setFormatter(formatter) 22 | ch.setFormatter(formatter) 23 | logger.addHandler(fh) 24 | logger.addHandler(ch) 25 | 26 | def start_logging(): # pragma: no cover 27 | """ 28 | Start the wntr logger. 29 | """ 30 | if _LogWrapper.initialized is None: 31 | _LogWrapper.initialized = _LogWrapper() 32 | -------------------------------------------------------------------------------- /wntr/utils/ordered_set.py: -------------------------------------------------------------------------------- 1 | """An ordered set implementation (like an ordered dict).""" 2 | 3 | import sys 4 | from collections.abc import MutableSet 5 | from collections import OrderedDict 6 | from collections.abc import Iterable 7 | 8 | 9 | class OrderedSet(MutableSet): 10 | """ 11 | An ordered set. 12 | """ 13 | def __init__(self, iterable=None): 14 | """ 15 | Parameters 16 | ---------- 17 | iterable: Iterable 18 | An iterable with which to initialize the set. 19 | """ 20 | self._data = OrderedDict() 21 | if iterable is not None: 22 | self.update(iterable) 23 | 24 | def __contains__(self, item): 25 | return item in self._data 26 | 27 | def __iter__(self): 28 | return self._data.__iter__() 29 | 30 | def __len__(self): 31 | return len(self._data) 32 | 33 | def add(self, value): 34 | """ 35 | Add an element to the set. 36 | 37 | Parameters 38 | ---------- 39 | value: object 40 | The object to be added to the set. 41 | """ 42 | self._data[value] = None 43 | 44 | def discard(self, value): 45 | """ 46 | Discard and element from the set. 47 | 48 | Parameters 49 | ---------- 50 | value: object 51 | The object to be discarded. 52 | """ 53 | self._data.pop(value, None) 54 | 55 | def update(self, iterable): 56 | """ 57 | Update the set with the objects in iterable. 58 | 59 | Parameters 60 | ---------- 61 | iterable: Iterable 62 | """ 63 | for i in iterable: 64 | self.add(i) 65 | 66 | def __repr__(self): 67 | s = '{' 68 | for i in self: 69 | s += str(i) 70 | s += ', ' 71 | s += '}' 72 | return s 73 | 74 | def __str__(self): 75 | return self.__repr__() 76 | 77 | def union(self, iterable): 78 | ret = OrderedSet(self) 79 | for i in iterable: 80 | ret.add(i) 81 | return ret 82 | 83 | def __sub__(self, other): 84 | ret = OrderedSet(self) 85 | for i in other: 86 | ret.discard(i) 87 | return ret 88 | -------------------------------------------------------------------------------- /wntr/utils/polynomial_interpolation.py: -------------------------------------------------------------------------------- 1 | """Functions for a polynomial interpolation using cubic spline.""" 2 | 3 | def cubic_spline(x1, x2, f1, f2, df1, df2): 4 | """ 5 | Method to compute the coefficients of a smoothing polynomial. 6 | 7 | Parameters 8 | ---------- 9 | x1: float 10 | point on the x-axis at which the smoothing polynomial begins 11 | x2: float 12 | point on the x-axis at which the smoothing polynomial ens 13 | f1: float 14 | function evaluated at x1 15 | f2: float 16 | function evaluated at x2 17 | df1: float 18 | derivative evaluated at x1 19 | df2: float 20 | derivative evaluated at x2 21 | 22 | Returns 23 | ------- 24 | A tuple with the smoothing polynomail coefficients starting with the cubic term. 25 | """ 26 | a = (2 * (f1 - f2) - (x1 - x2) * (df2 + df1)) / (x2 ** 3 - x1 ** 3 + 3 * x1 * x2 * (x1 - x2)) 27 | b = (df1 - df2 + 3 * (x2 ** 2 - x1 ** 2) * a) / (2 * (x1 - x2)) 28 | c = df2 - 3 * x2 ** 2 * a - 2 * x2 * b 29 | d = f2 - x2 ** 3 * a - x2 ** 2 * b - x2 * c 30 | return a, b, c, d 31 | 32 | --------------------------------------------------------------------------------