diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml new file mode 100644 index 00000000..402ea21b --- /dev/null +++ b/.github/workflows/build_wheel.yml @@ -0,0 +1,126 @@ +name: Build Wheels + +# Cross compile wheels only on main branch and tags +on: + pull_request: + branches: + - master + push: + branches: + - master + tags: + - v* + workflow_dispatch: + +jobs: + build_nrtest_plugin: + name: Build nrtest-swmm plugin + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./nrtest-swmm + + steps: + - name: Checkout repo + uses: actions/checkout@v3 + with: + submodules: true + + - name: Install Python + uses: actions/setup-python@v4 + with: + python-version: 3.7 + + - name: Build wheel + run: | + pip install wheel + python setup.py bdist_wheel + - uses: actions/upload-artifact@v3 + with: + path: nrtest-swmm/dist/*.whl + + + + build_wheels: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-2022, macos-12] + pyver: [cp38, cp39, cp310, cp311, cp312] + + steps: + - name: Checkout repo + uses: actions/checkout@v3 + with: + submodules: true + + - name: Build wheels + uses: pypa/cibuildwheel@v2.17.0 + with: + package-dir: ./swmm-toolkit + env: + CIBW_TEST_COMMAND: "pytest {package}/tests" + CIBW_BEFORE_TEST: pip install -r {package}/test-requirements.txt + # mac needs ninja to build + CIBW_BEFORE_BUILD_MACOS: brew install ninja + # remove system swig (cmake bug doesn't respect python venv) + # https://github.com/swig/swig/issues/2481#issuecomment-1949573105 + CIBW_BEFORE_BUILD_LINUX: rm -f $(which swig) && rm -f $(which swig4.0) + # configure cibuildwheel to build native archs ('auto'), and some emulated ones + CIBW_ARCHS_LINUX: x86_64 + CIBW_ARCHS_WINDOWS: AMD64 + CIBW_ARCHS_MACOS: x86_64 + # only build current supported python: https://devguide.python.org/versions/ + # don't build pypy or musllinux to save build time. TODO: find a good way to support those archs + CIBW_BUILD: ${{matrix.pyver}}-* + CIBW_SKIP: cp36-* cp37-* pp* *-musllinux* + # Will avoid testing on emulated architectures + # Skip trying to test arm64 builds on Intel Macs + CIBW_TEST_SKIP: "*-*linux_{aarch64,ppc64le,s390x} *-macosx_arm64 *-macosx_universal2:arm64" + CIBW_BUILD_VERBOSITY: 1 + + - uses: actions/upload-artifact@v3 + with: + path: ./wheelhouse/*.whl + + build_cross_wheels: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest,macos-12] + pyver: [cp38, cp39, cp310, cp311, cp312] + + steps: + - name: Checkout repo + uses: actions/checkout@v3 + with: + submodules: true + + - name: Set up QEMU + if: runner.os == 'Linux' + uses: docker/setup-qemu-action@v2 + with: + platforms: all + + - name: Build wheels + uses: pypa/cibuildwheel@v2.17.0 + with: + package-dir: ./swmm-toolkit + env: + # remove system swig (cmake bug doesn't respect python venv) + # https://github.com/swig/swig/issues/2481#issuecomment-1949573105 + CIBW_BEFORE_BUILD_LINUX: rm -f $(which swig) && rm -f $(which swig4.0) + # configure cibuildwheel to build native archs ('auto'), and some emulated ones + CIBW_ARCHS_LINUX: aarch64 + CIBW_ARCHS_MACOS: arm64 + # only build current supported python: https://devguide.python.org/versions/ + # don't build pypy or musllinux to save build time. TODO: find a good way to support those archs + CIBW_BUILD: ${{matrix.pyver}}-* + CIBW_SKIP: cp36-* cp37-* pp* *-musllinux* + CIBW_BUILD_VERBOSITY: 1 + + - uses: actions/upload-artifact@v3 + with: + path: ./wheelhouse/*.whl diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml deleted file mode 100644 index aea4d1e5..00000000 --- a/.github/workflows/python-package.yml +++ /dev/null @@ -1,86 +0,0 @@ -name: Build Wheels - -on: [push, pull_request] - -env: - DOCKER_IMAGE: dockcross/manylinux2014-x64 - - -jobs: - build_linux_wheels: - name: Build wheels on linux - runs-on: ubuntu-18.04 - - steps: - - name: Checkout repo - uses: actions/checkout@v2 - with: - submodules: true - - - name: Install - run: | - docker pull $DOCKER_IMAGE - docker run --rm $DOCKER_IMAGE > ./dockcross - chmod +x ./dockcross - - - name: Script - run: ./dockcross swmm-toolkit/tools/build-wheels.sh - - - uses: actions/upload-artifact@v2 - with: - path: ./dist/swmm_toolkit-*-manylinux2014_x86_64.whl - - - - build_win-mac_wheels: - name: Build wheels on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - defaults: - run: - working-directory: ./swmm-toolkit - strategy: - fail-fast: false - matrix: - os: [windows-2016, macos-10.15] - py: [3.6, 3.7, 3.8, 3.9] - include: - - os: windows-2016 - sys_pkgs: choco install swig - activate: ./build-env/Scripts/activate - - - os: macos-10.15 - sys_pkgs: brew install swig - activate: source ./build-env/bin/activate - - steps: - - name: Checkout repo - uses: actions/checkout@v2 - with: - submodules: true - - - name: Install Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.py }} - - - name: Install required system packages - run: ${{matrix.sys_pkgs}} - - - name: Build wheel in virtual env - run: | - python -m venv --clear ./build-env - ${{matrix.activate}} - python -m pip install -r build-requirements.txt - python setup.py bdist_wheel - deactivate - - - name: Test wheel - run: | - pip install -r test-requirements.txt - pip install --no-index --find-links=./dist swmm_toolkit - pytest - - - name: Upload artifacts - uses: actions/upload-artifact@v2 - with: - path: swmm-toolkit/dist/*.whl diff --git a/.github/workflows/unit_test.yml b/.github/workflows/unit_test.yml new file mode 100644 index 00000000..c496033f --- /dev/null +++ b/.github/workflows/unit_test.yml @@ -0,0 +1,63 @@ +name: Unit Test + +on: + push: + branches-ignore: + - 'master' + tags-ignore: + - v* + pull_request: + branches-ignore: + - 'master' + +jobs: + build_and_test: + name: Build and test on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + defaults: + run: + working-directory: ./swmm-toolkit + + strategy: + fail-fast: false + matrix: + os: [windows-2022, macos-12, ubuntu-latest] + include: + - os: windows-2022 + sys_pkgs: choco install swig + activate: ./build-env/Scripts/activate + + - os: macos-12 + sys_pkgs: brew install swig ninja + activate: source ./build-env/bin/activate + + - os: ubuntu-latest + activate: source ./build-env/bin/activate + + steps: + - name: Checkout repo + uses: actions/checkout@v3 + with: + submodules: true + + - name: Install Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + + - name: Install required system packages + run: ${{matrix.sys_pkgs}} + + - name: Build wheel in virtual env + run: | + python -m venv --clear ./build-env + ${{matrix.activate}} + python -m pip install -r build-requirements.txt + python setup.py bdist_wheel + deactivate + + - name: Test wheel + run: | + pip install -r test-requirements.txt + pip install --no-index --find-links=./dist swmm_toolkit + pytest \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 123ee6f0..f827f1c0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "swmm-toolkit/swmm-solver"] path = swmm-toolkit/swmm-solver url = https://github.com/OpenWaterAnalytics/Stormwater-Management-Model.git - branch = swig \ No newline at end of file + branch = master diff --git a/nrtest-swmm/nrtest_swmm/__init__.py b/nrtest-swmm/nrtest_swmm/__init__.py index 3ba91075..508300df 100644 --- a/nrtest-swmm/nrtest_swmm/__init__.py +++ b/nrtest-swmm/nrtest_swmm/__init__.py @@ -25,8 +25,8 @@ __credits__ = "Colleen Barr, Maurizio Cingi, Mark Gray, David Hall, Bryant McDonnell" __license__ = "CC0 1.0 Universal" -__version__ = "0.6.0" -__date__ = "May 8, 2020" +__version__ = "0.7.0" +__date__ = "Jul 28, 2021" __maintainer__ = "Michael E. Tryby" __email__ = "tryby.michael@epa.gov" @@ -65,15 +65,15 @@ def swmm_allclose_compare(path_test, path_ref, rtol, atol): for (test, ref) in zip(ordr.output_generator(path_test), ordr.output_generator(path_ref)): - if len(test[0]) != len(ref[0]): - raise ValueError('Inconsistent lengths') + # Compare arrays when lengths are unequal by truncating extra elements + length = min(len(test[0]), len(ref[0])) - # Skip over results if they are equal - if (np.array_equal(test[0], ref[0])): + # Skip over results if they are equal to optimize performance + if (np.array_equal(test[0][:length], ref[0][:length])): continue else: - np.testing.assert_allclose(test[0], ref[0], rtol, atol) + np.testing.assert_allclose(test[0][:length], ref[0][:length], rtol, atol) return True diff --git a/nrtest-swmm/nrtest_swmm/output_reader.py b/nrtest-swmm/nrtest_swmm/output_reader.py index 7b5f9666..a845be5c 100644 --- a/nrtest-swmm/nrtest_swmm/output_reader.py +++ b/nrtest-swmm/nrtest_swmm/output_reader.py @@ -18,7 +18,7 @@ from itertools import islice # project import -from swmm.toolkit import output, output_enum +from swmm.toolkit import output, shared_enum def output_generator(path_ref): @@ -40,7 +40,7 @@ def output_generator(path_ref): with OutputReader(path_ref) as reader: for period_index in range(0, reader.report_periods()): - for element_type in islice(output_enum.ElementType, 4): + for element_type in islice(shared_enum.ElementType, 4): for element_index in range(0, reader.element_count(element_type)): yield (reader.element_result(element_type, period_index, element_index), @@ -57,10 +57,10 @@ def __init__(self, filename): self.handle = None self.count = None self.get_element_result = { - output_enum.ElementType.SUBCATCH: output.get_subcatch_result, - output_enum.ElementType.NODE: output.get_node_result, - output_enum.ElementType.LINK: output.get_link_result, - output_enum.ElementType.SYSTEM: output.get_system_result + shared_enum.ElementType.SUBCATCH: output.get_subcatch_result, + shared_enum.ElementType.NODE: output.get_node_result, + shared_enum.ElementType.LINK: output.get_link_result, + shared_enum.ElementType.SYSTEM: output.get_system_result } def __enter__(self): @@ -73,7 +73,7 @@ def __exit__(self, type, value, traceback): output.close(self.handle) def report_periods(self): - return output.get_times(self.handle, output_enum.Time.NUM_PERIODS) + return output.get_times(self.handle, shared_enum.Time.NUM_PERIODS) def element_count(self, element_type): return self.count[element_type] diff --git a/nrtest-swmm/scripts/report-diff b/nrtest-swmm/scripts/report-diff index 054def11..8fbd085f 100644 --- a/nrtest-swmm/scripts/report-diff +++ b/nrtest-swmm/scripts/report-diff @@ -25,14 +25,14 @@ def _binary_diff(path_test, path_ref, min_cdd): for (test, ref) in zip(ordr.output_generator(path_test), ordr.output_generator(path_ref)): - if len(test[0]) != len(ref[0]): - raise ValueError('Inconsistent lengths') + # Compare arrays when lengths are unequal by truncating extra elements + length = min(len(test[0]), len(ref[0])) # Skip over arrays that are equal - if np.array_equal(test[0], ref[0]): + if np.array_equal(test[0][:length], ref[0][:length]): continue else: - lre = _log_relative_error(test[0], ref[0]) + lre = _log_relative_error(test[0][:length], ref[0][:length]) idx = np.unravel_index(np.argmin(lre), lre.shape) if lre[idx] < min_cdd: diff --git a/nrtest-swmm/setup.py b/nrtest-swmm/setup.py index 7d2338d0..8d0846ff 100644 --- a/nrtest-swmm/setup.py +++ b/nrtest-swmm/setup.py @@ -3,11 +3,11 @@ # # setup.py # -# Modified on October 17, 2019 -# # Author: Michael E. Tryby # US EPA - ORD/NRMRL # +# Modified: Jul 28, 2021 +# # Usage: # \>python setup.py bdist_wheel # @@ -27,7 +27,7 @@ setup( name='nrtest-swmm', - version='0.6.0', + version='0.7.0', description="SWMM extension for nrtest", author="Michael E. Tryby", diff --git a/swmm-toolkit/AUTHORS b/swmm-toolkit/AUTHORS index c7a896b7..a908903a 100644 --- a/swmm-toolkit/AUTHORS +++ b/swmm-toolkit/AUTHORS @@ -5,3 +5,7 @@ Michael Tryby (public domain) Jennifer Wu Caleb Buahin Laurent Courty +Constantine Karos +Abhiram Mullapudi +Brooke Mason +Sara C. Troutman \ No newline at end of file diff --git a/swmm-toolkit/CMakeLists.txt b/swmm-toolkit/CMakeLists.txt index 72f5bfa3..e73fc735 100644 --- a/swmm-toolkit/CMakeLists.txt +++ b/swmm-toolkit/CMakeLists.txt @@ -2,9 +2,9 @@ # CMakeLists.txt - CMake configuration file for swmm-toolkit python package # # Created: Feb 6, 2020 -# Modified Jan 12, 2021 +# Modified Jun 7, 2021 # -# Author: See AUTHORS +# Author: See AUTHORS # ################################################################################ @@ -15,7 +15,7 @@ cmake_minimum_required (VERSION 3.17) project(swmm-toolkit VERSION - 0.8.1 + 0.15.5 ) @@ -36,21 +36,18 @@ cmake_policy(SET CMP0078 NEW) cmake_policy(SET CMP0086 NEW) include(${SWIG_USE_FILE}) - # If wheel build on Apple fetch and build OpenMP Library if (APPLE) include(./extern/openmp.cmake) else() find_package(OpenMP + REQUIRED OPTIONAL_COMPONENTS C ) endif() - -# This gets passed down the project tree to trigger rpath configuration -option(BUILD_WHEEL "Configure for python wheel build" ON) - +# Add project subdirectories add_subdirectory(swmm-solver) add_subdirectory(src/swmm/toolkit) diff --git a/swmm-toolkit/build-requirements.txt b/swmm-toolkit/build-requirements.txt index 8149a1aa..cc5fbd1a 100644 --- a/swmm-toolkit/build-requirements.txt +++ b/swmm-toolkit/build-requirements.txt @@ -1,8 +1,8 @@ -setuptools -wheel -scikit-build -cmake -ninja +setuptools == 65.5.1 +wheel == 0.38.1 +scikit-build == 0.11.1 +cmake == 3.21 +swig == 4.0.2 \ No newline at end of file diff --git a/swmm-toolkit/extern/license-llvm-openmp.txt b/swmm-toolkit/extern/license-llvm-openmp.txt new file mode 100644 index 00000000..99075663 --- /dev/null +++ b/swmm-toolkit/extern/license-llvm-openmp.txt @@ -0,0 +1,361 @@ +============================================================================== +The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +---- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + +============================================================================== +Software from third parties included in the LLVM Project: +============================================================================== +The LLVM Project contains third party software which is under different license +terms. All such code will be identified clearly using at least one of two +mechanisms: +1) It will be in a separate directory tree with its own `LICENSE.txt` or + `LICENSE` file at the top containing the specific license and restrictions + which apply to that software, or +2) It will contain specific license and restriction terms at the top of every + file. + +============================================================================== +Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): +============================================================================== + +The software contained in this directory tree is dual licensed under both the +University of Illinois "BSD-Like" license and the MIT license. As a user of +this code you may choose to use it under either license. As a contributor, +you agree to allow your code to be used under both. The full text of the +relevant licenses is included below. + +In addition, a license agreement from the copyright/patent holders of the +software contained in this directory tree is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 1997-2019 Intel Corporation + +All rights reserved. + +Developed by: + OpenMP Runtime Team + Intel Corporation + http://www.openmprtl.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of Intel Corporation OpenMP Runtime Team nor the + names of its contributors may be used to endorse or promote products + derived from this Software without specific prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 1997-2019 Intel Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +============================================================================== + +Intel Corporation + +Software Grant License Agreement ("Agreement") + +Except for the license granted herein to you, Intel Corporation ("Intel") reserves +all right, title, and interest in and to the Software (defined below). + +Definition + +"Software" means the code and documentation as well as any original work of +authorship, including any modifications or additions to an existing work, that +is intentionally submitted by Intel to llvm.org (http://llvm.org) ("LLVM") for +inclusion in, or documentation of, any of the products owned or managed by LLVM +(the "Work"). For the purposes of this definition, "submitted" means any form of +electronic, verbal, or written communication sent to LLVM or its +representatives, including but not limited to communication on electronic +mailing lists, source code control systems, and issue tracking systems that are +managed by, or on behalf of, LLVM for the purpose of discussing and improving +the Work, but excluding communication that is conspicuously marked otherwise. + +1. Grant of Copyright License. Subject to the terms and conditions of this + Agreement, Intel hereby grants to you and to recipients of the Software + distributed by LLVM a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable copyright license to reproduce, prepare derivative + works of, publicly display, publicly perform, sublicense, and distribute the + Software and such derivative works. + +2. Grant of Patent License. Subject to the terms and conditions of this + Agreement, Intel hereby grants you and to recipients of the Software + distributed by LLVM a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable (except as stated in this section) patent license + to make, have made, use, offer to sell, sell, import, and otherwise transfer + the Work, where such license applies only to those patent claims licensable + by Intel that are necessarily infringed by Intel's Software alone or by + combination of the Software with the Work to which such Software was + submitted. If any entity institutes patent litigation against Intel or any + other entity (including a cross-claim or counterclaim in a lawsuit) alleging + that Intel's Software, or the Work to which Intel has contributed constitutes + direct or contributory patent infringement, then any patent licenses granted + to that entity under this Agreement for the Software or Work shall terminate + as of the date such litigation is filed. + +Unless required by applicable law or agreed to in writing, the software is +provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied, including, without limitation, any warranties or +conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. + +============================================================================== diff --git a/swmm-toolkit/extern/openmp.cmake b/swmm-toolkit/extern/openmp.cmake index 38b1f962..89d74850 100644 --- a/swmm-toolkit/extern/openmp.cmake +++ b/swmm-toolkit/extern/openmp.cmake @@ -2,15 +2,20 @@ # CMakeLists.txt - CMake configuration file for OpenMP Library on Darwin # # Created: Mar 17, 2021 -# Updated: +# Updated: May 19, 2021 # # Author: Michael E. Tryby # US EPA ORD/CESER # # Note: +# Need to build libomp for binary compatibility with Python. +# # OpenMP library build fails for Xcode generator. Use Ninja or Unix Makefiles # instead. # +# All sources were obtained directly from the LLVM releases on github +# See license-llvm-openmp.txt for the corresponding license and +# https://openmp.llvm.org/ for details on the OpenMP run-time. ################################################################################ ##################### CMAKELISTS FOR OPENMP LIBRARY ###################### @@ -21,9 +26,9 @@ include(FetchContent) FetchContent_Declare(OpenMP URL - https://github.com/llvm/llvm-project/releases/download/llvmorg-11.1.0/openmp-11.1.0.src.tar.xz + https://github.com/llvm/llvm-project/releases/download/llvmorg-12.0.1/openmp-12.0.1.src.tar.xz URL_HASH - SHA256=d187483b75b39acb3ff8ea1b7d98524d95322e3cb148842957e9b0fbb866052e + SHA256=60fe79440eaa9ebf583a6ea7f81501310388c02754dbe7dc210776014d06b091 ) set(OPENMP_STANDALONE_BUILD TRUE) @@ -44,3 +49,15 @@ install(TARGETS omp DESTINATION "${LIBRARY_DIST}" ) + +if(CMAKE_C_COMPILER_ID MATCHES "Clang\$") + set(OpenMP_C_FLAGS "-Xpreprocessor -fopenmp -I${CMAKE_BINARY_DIR}/_deps/openmp-build/runtime/src") + set(OpenMP_C_LIB_NAMES "omp") + set(OpenMP_omp_LIBRARY "${CMAKE_BINARY_DIR}/_deps/openmp-build/runtime/src/libomp.dylib") +endif() + +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang\$") + set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I${CMAKE_BINARY_DIR}/_deps/openmp-build/runtime/src") + set(OpenMP_CXX_LIB_NAMES "omp") + set(OpenMP_omp_LIBRARY "${CMAKE_BINARY_DIR}/_deps/openmp-build/runtime/src/libomp.dylib") +endif() \ No newline at end of file diff --git a/swmm-toolkit/pyproject.toml b/swmm-toolkit/pyproject.toml new file mode 100644 index 00000000..5f79a435 --- /dev/null +++ b/swmm-toolkit/pyproject.toml @@ -0,0 +1,10 @@ +[build-system] +requires = [ + "wheel>=0.38.1", + "setuptools>=42", + "scikit-build>=0.13", + "cmake>=3.21", + "swig==4.0.2", + "ninja==1.11.1 ; sys_platform == 'darwin'" +] +build-backend = "setuptools.build_meta" \ No newline at end of file diff --git a/swmm-toolkit/setup.py b/swmm-toolkit/setup.py index c0d39dcf..846887ca 100644 --- a/swmm-toolkit/setup.py +++ b/swmm-toolkit/setup.py @@ -2,7 +2,7 @@ # setup.py - Setup script for swmm-toolkit python package # # Created: Jul 2, 2018 -# Updated: May 7, 2020 +# Updated: Jun 7, 2021 # # Author: See AUTHORS # @@ -16,10 +16,10 @@ import platform import subprocess import pathlib - +import os from skbuild import setup from setuptools import Command - +import sys # Determine platform platform_system = platform.system() @@ -56,16 +56,36 @@ def run(self): p.wait() -# Set up location of wheel libraries depending on build platform -if platform_system == "Windows": - package_dir = {"swmm_toolkit":"bin", "swmm.toolkit": "src/swmm/toolkit"} +# Set up location of wheel libraries depending on build platform and command +# commands that trigger cmake from skbuild.setuptools_wrap._should_run_cmake +commands_that_trigger_cmake = { + "build", + "build_ext", + "develop", + "install", + "install_lib", + "bdist", + "bdist_dumb", + "bdist_egg", + "bdist_rpm", + "bdist_wininst", + "bdist_wheel", + "test", + } +command = sys.argv[1] if len(sys.argv) > 1 else None +if command in commands_that_trigger_cmake: + swmm_toolkit_dir= "bin" if platform_system == "Windows" else "lib" else: - package_dir = {"swmm_toolkit":"lib", "swmm.toolkit": "src/swmm/toolkit"} + swmm_toolkit_dir= "swmm-solver" +package_dir = {"swmm_toolkit" : swmm_toolkit_dir, "swmm.toolkit": "src/swmm/toolkit"} + +if os.environ.get('SWMM_CMAKE_ARGS') is not None: + cmake_args = os.environ.get('SWMM_CMAKE_ARGS').split() # Set Platform specific cmake args here -if platform_system == "Windows": - cmake_args = ["-GVisual Studio 15 2017 Win64"] +elif platform_system == "Windows": + cmake_args = ["-GVisual Studio 17 2022","-Ax64"] elif platform_system == "Darwin": cmake_args = ["-GNinja","-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.9"] @@ -85,42 +105,48 @@ def exclude_files(cmake_manifest): here = pathlib.Path(__file__).parent.resolve() long_description = (here / 'README.md').read_text(encoding='utf-8') +if platform_system == "Darwin": + license_files = ['LICENSE.md', 'extern/license-llvm-openmp.txt'] +else: + license_files = ['LICENSE.md'] setup( - name = "swmm_toolkit", - version = "0.8.1", + name = "swmm-toolkit", + version = "0.15.5", packages = ["swmm_toolkit", "swmm.toolkit"], package_dir = package_dir, zip_safe = False, - install_requires = ["aenum==3.0.0"], + install_requires = ["aenum==3.1.11"], cmdclass = {"clean": CleanCommand}, cmake_args = cmake_args, cmake_process_manifest_hook = exclude_files, - description='OWA SWMM Python Toolkit', + description='PySWMM SWMM Python Toolkit', long_description=long_description, long_description_content_type='text/markdown', - url='https://github.com/OpenWaterAnalytics/swmm-python', + url='https://github.com/pyswmm/swmm-python', author='See AUTHORS', - maintainer_email='tryby.michael@epa.gov', + maintainer_email='bemcdonnell@gmail.com', license='CC0', - - keywords="swmm5, swmm, stormwater, hydraulics, hydrology, ", + license_files=license_files, + keywords="swmm5, swmm, stormwater, hydraulics, hydrology", classifiers=[ "Topic :: Scientific/Engineering", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", "Operating System :: MacOS", "License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Programming Language :: C", - "Development Status :: 4 - Beta", + "Development Status :: 5 - Production/Stable", ] ) diff --git a/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt b/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt index b9760cd6..a88d77a4 100644 --- a/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt +++ b/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt @@ -2,7 +2,7 @@ # CMakeLists.txt - CMake configuration file for swmm.toolkit python package # # Created: Feb 6, 2020 -# Updated: Dec 29, 2020 +# Updated: May 19, 2021 # # Author: See AUTHORS # @@ -31,8 +31,8 @@ else() endif() # Set up rpath on MacOS and Linux -set(PACKAGE_RPATH - "${LIB_ROOT}/../../swmm_toolkit/;${LIB_ROOT}/../../swmm_toolkit.libs/" +set(PACKAGE_RPATH + "${LIB_ROOT}/../../swmm_toolkit/" ) @@ -139,6 +139,7 @@ target_link_libraries(solver set_target_properties(solver PROPERTIES SUFFIX ${PYTHON_SUFFIX} + SWIG_COMPILE_DEFINITIONS EXPORT_TOOLKIT MACOSX_RPATH TRUE SKIP_BUILD_RPATH FALSE BUILD_WITH_INSTALL_RPATH FALSE diff --git a/swmm-toolkit/src/swmm/toolkit/__init__.py b/swmm-toolkit/src/swmm/toolkit/__init__.py index 90ae9dd5..9d09fa28 100644 --- a/swmm-toolkit/src/swmm/toolkit/__init__.py +++ b/swmm-toolkit/src/swmm/toolkit/__init__.py @@ -4,14 +4,14 @@ # __init__.py - SWMM toolkit package # # Created: Aug 9, 2018 -# Updated: Dec 22, 2020 +# Updated: July 2, 2022 # # Author: See AUTHORS # -''' +""" A low level pythonic API for the swmm-output and swmm-solver dlls using SWIG. -''' +""" __author__ = "See AUTHORS" @@ -19,8 +19,8 @@ __credits__ = "Colleen Barr, Sam Hatchett" __license__ = "CC0 1.0 Universal" -__version__ = "0.8.1" -__date__ = "December 22, 2020" +__version__ = "0.15.5" +__date__ = "June 7, 2021" __maintainer__ = "Michael Tryby" __email__ = "tryby.michael@epa.gov" @@ -29,6 +29,7 @@ import os import platform +import sys # Adds directory containing swmm libraries to path @@ -36,6 +37,9 @@ libdir = os.path.join(os.path.dirname(__file__), "../../swmm_toolkit") if hasattr(os, 'add_dll_directory'): + conda_exists = os.path.exists(os.path.join(sys.prefix, 'conda-meta')) + if conda_exists: + os.environ['CONDA_DLL_SEARCH_MODIFICATION_ENABLE'] = "1" os.add_dll_directory(libdir) else: os.environ["PATH"] = libdir + ";" + os.environ["PATH"] diff --git a/swmm-toolkit/src/swmm/toolkit/output_metadata.py b/swmm-toolkit/src/swmm/toolkit/output_metadata.py index 13ca02b5..89b6210b 100644 --- a/swmm-toolkit/src/swmm/toolkit/output_metadata.py +++ b/swmm-toolkit/src/swmm/toolkit/output_metadata.py @@ -88,9 +88,10 @@ def _build_pollut_metadata(self, output_handle): # Create dictionary keys for i in range(1, n): symbolic_name = 'POLLUT_CONC_' + str(i) - extend_enum(shared_enum.SubcatchAttribute, symbolic_name, 8 + i) - extend_enum(shared_enum.NodeAttribute, symbolic_name, 6 + i) - extend_enum(shared_enum.LinkAttribute, symbolic_name, 5 + i) + if symbolic_name not in shared_enum.SubcatchAttribute._member_names_: + extend_enum(shared_enum.SubcatchAttribute, symbolic_name, 8 + i) + extend_enum(shared_enum.NodeAttribute, symbolic_name, 6 + i) + extend_enum(shared_enum.LinkAttribute, symbolic_name, 5 + i) # Update metadata dictionary with pollutant metadata for i, attr in enumerate(islice(shared_enum.SubcatchAttribute, 8, None)): @@ -194,7 +195,9 @@ def __init__(self, output_handle): shared_enum.SystemAttribute.VOLUME_STORED: ("Volume Stored", self._unit_labels[shared_enum.BaseUnits.VOLUME]), shared_enum.SystemAttribute.EVAP_RATE: - ("Evaporation Rate", self._unit_labels[shared_enum.BaseUnits.EVAP_RATE]) + ("Evaporation Rate", self._unit_labels[shared_enum.BaseUnits.EVAP_RATE]), + shared_enum.SystemAttribute.PTNL_EVAP_RATE: + ("Potential Evaporation Rate", self._unit_labels[shared_enum.BaseUnits.EVAP_RATE]) } self._build_pollut_metadata(output_handle) diff --git a/swmm-toolkit/src/swmm/toolkit/shared_enum.py b/swmm-toolkit/src/swmm/toolkit/shared_enum.py index f3906e79..f787b8eb 100644 --- a/swmm-toolkit/src/swmm/toolkit/shared_enum.py +++ b/swmm-toolkit/src/swmm/toolkit/shared_enum.py @@ -304,6 +304,7 @@ class SystemAttribute(Enum, start = 0): :attr:`~OUTFALL_FLOWS` outfall outflow :attr:`~VOLUME_STORED` storage volume :attr:`~EVAP_RATE` evaporation + :attr:`~PTNL_EVAP_RATE` potential evapotranspiration ============================= ==================== """ AIR_TEMP = 0 @@ -320,6 +321,7 @@ class SystemAttribute(Enum, start = 0): OUTFALL_FLOWS = 11 VOLUME_STORED = 12 EVAP_RATE = 13 + PTNL_EVAP_RATE = 14 # @@ -401,6 +403,7 @@ class SimSetting(Enum): HEAD_TOLERANCE = 11 SYSTEM_FLOW_TOLERANCE = 12 LATERAL_FLOW_TOLERANCE = 13 + THREADS = 14 class NodeProperty(Enum): @@ -430,6 +433,7 @@ class NodeResult(Enum): :attr:`~DEPTH` :attr:`~HEAD` :attr:`~LATERAL_INFLOW` + :attr:`~HYD_RES_TIME` """ TOTAL_INFLOW = 0 TOTAL_OUTFLOW = 1 @@ -439,14 +443,19 @@ class NodeResult(Enum): DEPTH = 5 HEAD = 6 LATERAL_INFLOW = 7 + HYD_RES_TIME = 8 class NodePollutant(Enum): """Node Pollutant enum class. :attr:`~QUALITY` + :attr:`~INFLOW_CONC` + :attr:`~REACTOR_CONC` """ QUALITY = 0 + INFLOW_CONC = 1 + REACTOR_CONC = 2 class LinkProperty(Enum): @@ -496,9 +505,11 @@ class LinkPollutant(Enum): :attr:`~QUALITY` :attr:`~TOTAL_LOAD` + :attr:`~REACTOR_CONC` """ QUALITY = 0 TOTAL_LOAD = 1 + REACTOR_CONC = 2 class SubcatchProperty(Enum): @@ -729,3 +740,40 @@ class RainResult(Enum): TOTAL = 0 RAINFALL = 1 SNOWFALL = 2 + +class InletProperty(Enum): + """Inlet Property enum class. + + :attr:`~NUM_INLETS` + :attr:`~CLOG_FACTOR` + :attr:`~FLOW_LIMIT` + :attr:`~DEPRESSION_HEIGHT` + :attr:`~DEPRESSION_WIDTH`""" + NUM_INLETS = 0 + CLOG_FACTOR = 1 + FLOW_LIMIT = 2 + DEPRESSION_HEIGHT = 3 + DEPRESSION_WIDTH = 4 + + +class InletResult(Enum): + """Inlet Result enum class. + + :attr:`~FLOW_FACTOR` + :attr:`~FLOW CAPTURE` + :attr:`~BACK_FLOW` + :attr:`~BLACK_FLOW_RATIO` + """ + FLOW_FACTOR = 0 + FLOW_CAPTURE = 1 + BACK_FLOW = 2 + BLACK_FLOW_RATIO = 3 + +class HotstartFile(Enum): + """Hotstart File enum class. + + :attr:`~USE` + :attr:`~SAVE` + """ + USE = 0 + SAVE = 1 \ No newline at end of file diff --git a/swmm-toolkit/src/swmm/toolkit/solver.i b/swmm-toolkit/src/swmm/toolkit/solver.i index e3af2d87..49257bc0 100644 --- a/swmm-toolkit/src/swmm/toolkit/solver.i +++ b/swmm-toolkit/src/swmm/toolkit/solver.i @@ -39,6 +39,10 @@ Py_INCREF($result); } +%typemap(out) int swmm_getVersion { + $result = PyInt_FromLong($1); +} + %apply int *OUTPUT { int *index, @@ -154,7 +158,10 @@ SM_LidLayerProperty, SM_LidUProperty, SM_LidUOptions, - SM_LidResult + SM_LidResult, + SM_InletProperty, + SM_InletResult, + SM_HotStart } @@ -178,6 +185,22 @@ } +/* INSERTS CUSTOM EXCEPTION HANDLING IN WRAPPER */ +%exception swmm_getSemVersion +{ + $function +} + +%exception swmm_getBuildId +{ + $function +} + +%exception swmm_getVersion +{ + $function +} + /* INSERTS CUSTOM EXCEPTION HANDLING IN WRAPPER */ %exception { @@ -199,6 +222,16 @@ %ignore swmm_getWarnings; %ignore swmm_IsOpenFlag; %ignore swmm_IsStartedFlag; +%ignore swmm_IsStartedFlag; + +%ignore swmm_getCount; +%ignore swmm_getName; +%ignore swmm_getIndex; +%ignore swmm_getValue; +%ignore swmm_setValue; +%ignore swmm_getSavedValue; +%ignore swmm_writeLine; +%ignore swmm_decodeDate; %include "swmm5.h" @@ -209,7 +242,8 @@ %ignore swmm_getObjectIndex; %ignore swmm_freeMemory; + %include "toolkit.h" -%exception; +%exception; \ No newline at end of file diff --git a/swmm-toolkit/src/swmm/toolkit/solver_docs.i b/swmm-toolkit/src/swmm/toolkit/solver_docs.i index 4e130e20..5a440e8b 100644 --- a/swmm-toolkit/src/swmm/toolkit/solver_docs.i +++ b/swmm-toolkit/src/swmm/toolkit/solver_docs.i @@ -377,6 +377,17 @@ patch: char ** " ) swmm_getVersionInfo; +%feature("autodoc", +"Load or save a hotstart file into or out of a running simulation. + +Parameters +---------- +operation: SM_HotStart + The hotstart operation to use (i.e. save or load) +hsfile: str + The path to the hotstart file to either save or load +" +) swmm_hotstart; %feature("autodoc", "Finds the index of an object given its ID. @@ -664,6 +675,26 @@ flowrate: double ) swmm_setNodeInflow; +%feature("autodoc", +"Set node pollutant concentration + +Parameters +---------- +index: int + The node index. +type: SM_NodePollut + The property type code (see :ref: SM_NodePollut). Currently Only QUALITY (0) is supported. +pollutant_index: int + The index of the pollutant to set. +pollutant_value: + The new pollutant concentration to set. + +" +) swmm_setNodePollut; + + + + %feature("autodoc", "Get a node statistics. @@ -863,6 +894,23 @@ setting: double ) swmm_setLinkSetting; +%feature("autodoc", +"Set link pollutant concentration + +Parameters +---------- +index: int + The link index. +type: SM_LinkPollut + The property type code (see :ref: SM_LinkPollut). Currently Only QUALITY (0) is supported. +pollutant_index: int + The index of the pollutant to set. +pollutant_value: + The new pollutant concentration to set. + +" +) swmm_setLinkPollut; + %feature("autodoc", "Get link statistics. @@ -1256,3 +1304,57 @@ total_precip: double The new total precipitation intensity. " ) swmm_setGagePrecip; + + +%feature("autodoc", +"Get a property value for the inlet of a specified link. + +Parameters +---------- +index: int + The index of a link with desired inlets +param: SM_InletProperty + The property type code (See :ref: SM_InletProperty) + +Returns +------- +value: double * + The value of the inlet's property +" +) swmm_getInletParam; + + +%feature("autodoc", +"Get a property value for the inlet of a specified link. + +Parameters +---------- +index: int + The index of a link with desired inlets +param: SM_InletProperty + The property type code (See :ref: SM_InletProperty) + +Returns +------- +value: double * + The new value of the inlet's property +" +) swmm_setInletParam; + + +%feature("autodoc", +"Get a result value for specified link. + +Parameters +---------- +index: int + The index of a link with desired inlets +type: SM_InletResult + The result type code (See :ref: SM_InletResult) + +Returns +------- +result: double * + The value of the inlet's result at the current simulation timestep +" +) swmm_getInletResult; diff --git a/swmm-toolkit/src/swmm/toolkit/solver_rename.i b/swmm-toolkit/src/swmm/toolkit/solver_rename.i index 648f1d9a..14db8184 100644 --- a/swmm-toolkit/src/swmm/toolkit/solver_rename.i +++ b/swmm-toolkit/src/swmm/toolkit/solver_rename.i @@ -44,6 +44,7 @@ %rename(node_set_parameter) swmm_setNodeParam; %rename(node_get_result) swmm_getNodeResult; %rename(node_get_pollutant) swmm_getNodePollut; +%rename(node_set_pollutant) swmm_setNodePollut; %rename(node_get_total_inflow) swmm_getNodeTotalInflow; %rename(node_set_total_inflow) swmm_setNodeInflow; %rename(node_get_stats) swmm_getNodeStats; @@ -63,9 +64,13 @@ %rename(link_set_parameter) swmm_setLinkParam; %rename(link_get_result) swmm_getLinkResult; %rename(link_get_pollutant) swmm_getLinkPollut; +%rename(link_set_pollutant) swmm_setLinkPollut; %rename(link_set_target_setting) swmm_setLinkSetting; %rename(link_get_stats) swmm_getLinkStats; +%rename(inlet_get_parameter) swmm_getInletParam; +%rename(inlet_set_parameter) swmm_setInletParam; +%rename(inlet_get_result) swmm_getInletResult; %rename(pump_get_stats) swmm_getPumpStats; @@ -99,4 +104,6 @@ %rename(raingage_set_precipitation) swmm_setGagePrecip; -%rename(swmm_version_info) swmm_getVersionInfo; +%rename(swmm_version_info) swmm_getSemVersion; +%rename(swmm_build_id) swmm_getBuildId; +%rename(swmm_hotstart) swmm_hotstart; \ No newline at end of file diff --git a/swmm-toolkit/swmm-solver b/swmm-toolkit/swmm-solver index 93891ff1..459db1d4 160000 --- a/swmm-toolkit/swmm-solver +++ b/swmm-toolkit/swmm-solver @@ -1 +1 @@ -Subproject commit 93891ff1e3775073895a3b96f38fa6999e961ed9 +Subproject commit 459db1d4dfc61ff994ae01f92eae64e378e08915 diff --git a/swmm-toolkit/test-requirements.txt b/swmm-toolkit/test-requirements.txt index f6cc17c4..0cc9aaba 100644 --- a/swmm-toolkit/test-requirements.txt +++ b/swmm-toolkit/test-requirements.txt @@ -1,6 +1,8 @@ -pytest -numpy -aenum==3.0.0 +pytest == 7.1.1 +numpy == 1.21.6; python_version == "3.7" +numpy == 1.24.4; python_version < "3.12" +numpy == 1.26.2; python_version >= "3.12" +aenum == 3.1.11 diff --git a/swmm-toolkit/tests/data/test_Example3.inp b/swmm-toolkit/tests/data/test_Example3.inp new file mode 100644 index 00000000..ed2acbba --- /dev/null +++ b/swmm-toolkit/tests/data/test_Example3.inp @@ -0,0 +1,131 @@ +[TITLE] +;;Project Title/Notes + +[OPTIONS] +;;Option Value +FLOW_UNITS CMS +INFILTRATION HORTON +FLOW_ROUTING KINWAVE +LINK_OFFSETS DEPTH +MIN_SLOPE 0 +ALLOW_PONDING NO +SKIP_STEADY_STATE NO + +START_DATE 01/27/2020 +START_TIME 00:00:00 +REPORT_START_DATE 01/27/2020 +REPORT_START_TIME 00:00:00 +END_DATE 01/27/2020 +END_TIME 00:30:00 +SWEEP_START 01/01 +SWEEP_END 02/28 +DRY_DAYS 0 +REPORT_STEP 00:00:01 +WET_STEP 00:00:01 +DRY_STEP 00:00:01 +ROUTING_STEP 0:00:01 +RULE_STEP 00:00:00 + +INERTIAL_DAMPING PARTIAL +NORMAL_FLOW_LIMITED BOTH +FORCE_MAIN_EQUATION H-W +VARIABLE_STEP 0.75 +LENGTHENING_STEP 0 +MIN_SURFAREA 1.14 +MAX_TRIALS 8 +HEAD_TOLERANCE 0.0015 +SYS_FLOW_TOL 5 +LAT_FLOW_TOL 5 +MINIMUM_STEP 0.5 +THREADS 1 + +[EVAPORATION] +;;Data Source Parameters +;;-------------- ---------------- +CONSTANT 0.0 +DRY_ONLY NO + +[OUTFALLS] +;;Name Elevation Type Stage Data Gated Route To +;;-------------- ---------- ---------- ---------------- -------- ---------------- +Outfall 0 FREE NO + +[STORAGE] +;;Name Elev. MaxDepth InitDepth Shape Curve Name/Params N/A Fevap Psi Ksat IMD +;;-------------- -------- ---------- ----------- ---------- ---------------------------- -------- -------- -------- -------- +Tank 10 5 0 TABULAR Tank_Curve 0 0 + +[CONDUITS] +;;Name From Node To Node Length Roughness InOffset OutOffset InitFlow MaxFlow +;;-------------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- +Valve Tank Outfall 400 0.01 0 0 0 0 + +[XSECTIONS] +;;Link Shape Geom1 Geom2 Geom3 Geom4 Barrels Culvert +;;-------------- ------------ ---------------- ---------- ---------- ---------- ---------- ---------- +Valve CIRCULAR 1 0 0 0 1 + +[POLLUTANTS] +;;Name Units Crain Cgw Crdii Kdecay SnowOnly Co-Pollutant Co-Frac Cdwf Cinit +;;-------------- ------ ---------- ---------- ---------- ---------- ---------- ---------------- ---------- ---------- ---------- +P1 MG/L 0.0 0.0 0 0.0 NO * 0.0 0.0 0 + +[TREATMENT] +;;Node Pollutant Function +;;-------------- ---------------- ---------- +Tank P1 C = 2.0 + +[INFLOWS] +;;Node Constituent Time Series Type Mfactor Sfactor Baseline Pattern +;;-------------- ---------------- ---------------- -------- -------- -------- -------- -------- +Tank FLOW "" FLOW 1.0 1.0 5 +Tank P1 "" CONCENTRATION 1.0 1.0 10 + +[CURVES] +;;Name Type X-Value Y-Value +;;-------------- ---------- ---------- ---------- +Tank_Curve Storage 0 100 +Tank_Curve 1 100 +Tank_Curve 2 100 +Tank_Curve 3 100 +Tank_Curve 4 100 +Tank_Curve 5 100 + +[TIMESERIES] +;;Name Date Time Value +;;-------------- ---------- ---------- ---------- +TestRain 1 0 +TestRain 2 0.5 +TestRain 3 0.75 +TestRain 4 1 +TestRain 5 0.75 +TestRain 6 0.5 +TestRain 7 0 + +[PATTERNS] +;;Name Type Multipliers +;;-------------- ---------- ----------- +DailyX1 DAILY 1.0 1.0 1.0 1.0 1.0 1.0 1.0 + +[REPORT] +;;Reporting Options +SUBCATCHMENTS ALL +NODES ALL +LINKS ALL + +[TAGS] + +[MAP] +DIMENSIONS 0.000 0.000 10000.000 10000.000 +Units None + +[COORDINATES] +;;Node X-Coord Y-Coord +;;-------------- ------------------ ------------------ +Outfall -178.777 6435.986 +Tank -1101.499 6828.143 + +[VERTICES] +;;Link X-Coord Y-Coord +;;-------------- ------------------ ------------------ + diff --git a/swmm-toolkit/tests/data/test_Example3.old.inp b/swmm-toolkit/tests/data/test_Example3.old.inp new file mode 100644 index 00000000..dd164967 --- /dev/null +++ b/swmm-toolkit/tests/data/test_Example3.old.inp @@ -0,0 +1,133 @@ +[TITLE] +;;Project Title/Notes + +[OPTIONS] +;;Option Value +FLOW_UNITS CMS +INFILTRATION HORTON +FLOW_ROUTING KINWAVE +LINK_OFFSETS DEPTH +MIN_SLOPE 0 +ALLOW_PONDING NO +SKIP_STEADY_STATE NO + +START_DATE 01/27/2020 +START_TIME 00:00:00 +REPORT_START_DATE 01/27/2020 +REPORT_START_TIME 00:00:00 +END_DATE 01/27/2020 +END_TIME 00:30:00 +SWEEP_START 01/01 +SWEEP_END 02/28 +DRY_DAYS 0 +REPORT_STEP 00:00:01 +WET_STEP 00:00:01 +DRY_STEP 00:00:01 +ROUTING_STEP 0:00:01 + +INERTIAL_DAMPING PARTIAL +NORMAL_FLOW_LIMITED BOTH +FORCE_MAIN_EQUATION H-W +VARIABLE_STEP 0.75 +LENGTHENING_STEP 0 +MIN_SURFAREA 1.14 +MAX_TRIALS 8 +HEAD_TOLERANCE 0.0015 +SYS_FLOW_TOL 5 +LAT_FLOW_TOL 5 +MINIMUM_STEP 0.5 +THREADS 1 + +[EVAPORATION] +;;Data Source Parameters +;;-------------- ---------------- +CONSTANT 0.0 +DRY_ONLY NO + +[OUTFALLS] +;;Name Elevation Type Stage Data Gated Route To +;;-------------- ---------- ---------- ---------------- -------- ---------------- +Outfall 0 FREE NO + +[STORAGE] +;;Name Elev. MaxDepth InitDepth Shape Curve Name/Params N/A Fevap Psi Ksat IMD +;;-------------- -------- ---------- ----------- ---------- ---------------------------- -------- -------- -------- -------- +Tank 10 5 0 TABULAR Tank_Curve 0 0 + +[ORIFICES] +;;Name From Node To Node Type Offset Qcoeff Gated CloseTime +;;-------------- ---------------- ---------------- ------------ ---------- ---------- -------- ---------- +Valve Tank Outfall BOTTOM 0 1 NO 0 + +[XSECTIONS] +;;Link Shape Geom1 Geom2 Geom3 Geom4 Barrels Culvert +;;-------------- ------------ ---------------- ---------- ---------- ---------- ---------- ---------- +Valve RECT_CLOSED 1 1 0 0 + +[POLLUTANTS] +;;Name Units Crain Cgw Crdii Kdecay SnowOnly Co-Pollutant Co-Frac Cdwf Cinit +;;-------------- ------ ---------- ---------- ---------- ---------- ---------- ---------------- ---------- ---------- ---------- +P1 MG/L 0.0 0.0 0 0.0 NO * 0.0 0.0 0 + + +[INFLOWS] +;;Node Constituent Time Series Type Mfactor Sfactor Baseline Pattern +;;-------------- ---------------- ---------------- -------- -------- -------- -------- -------- +Tank FLOW "" FLOW 1.0 1.0 5 +Tank P1 "" CONCENTRATION 1.0 1.0 10 + +[TREATMENT] +;;Node Pollutant Function +;;-------------- ---------------- ---------- +Tank P1 C = 2.0 + +[CURVES] +;;Name Type X-Value Y-Value +;;-------------- ---------- ---------- ---------- +Tank_Curve Storage 0 100 +Tank_Curve 1 100 +Tank_Curve 2 100 +Tank_Curve 3 100 +Tank_Curve 4 100 +Tank_Curve 5 100 + +[TIMESERIES] +;;Name Date Time Value +;;-------------- ---------- ---------- ---------- +TestRain 1 0 +TestRain 2 0.5 +TestRain 3 0.75 +TestRain 4 1 +TestRain 5 0.75 +TestRain 6 0.5 +TestRain 7 0 + +[PATTERNS] +;;Name Type Multipliers +;;-------------- ---------- ----------- +DailyX1 DAILY 1.0 1.0 1.0 1.0 1.0 1.0 1.0 + +[REPORT] +;;Reporting Options +INPUT NO +CONTROLS NO +SUBCATCHMENTS ALL +NODES ALL +LINKS ALL + +[TAGS] + +[MAP] +DIMENSIONS 0.000 0.000 10000.000 10000.000 +Units None + +[COORDINATES] +;;Node X-Coord Y-Coord +;;-------------- ------------------ ------------------ +Outfall -178.777 6435.986 +Tank -1101.499 6828.143 + +[VERTICES] +;;Link X-Coord Y-Coord +;;-------------- ------------------ ------------------ + diff --git a/swmm-toolkit/tests/data/test_inlet_drains.inp b/swmm-toolkit/tests/data/test_inlet_drains.inp new file mode 100644 index 00000000..a60d798a --- /dev/null +++ b/swmm-toolkit/tests/data/test_inlet_drains.inp @@ -0,0 +1,502 @@ +[TITLE] +;;Project Title/Notes +A dual drainage model with street inlets. +See Inlet_Drains_Model.txt for more details. + +[OPTIONS] +;;Option Value +FLOW_UNITS CFS +INFILTRATION HORTON +FLOW_ROUTING DYNWAVE +LINK_OFFSETS DEPTH +MIN_SLOPE 0 +ALLOW_PONDING NO +SKIP_STEADY_STATE NO + +START_DATE 01/01/2007 +START_TIME 00:00:00 +REPORT_START_DATE 01/01/2007 +REPORT_START_TIME 00:00:00 +END_DATE 01/01/2007 +END_TIME 06:00:00 +SWEEP_START 01/01 +SWEEP_END 12/31 +DRY_DAYS 0 +REPORT_STEP 00:01:00 +WET_STEP 00:01:00 +DRY_STEP 01:00:00 +ROUTING_STEP 0:00:15 +RULE_STEP 00:00:00 + +INERTIAL_DAMPING PARTIAL +NORMAL_FLOW_LIMITED SLOPE +FORCE_MAIN_EQUATION H-W +VARIABLE_STEP 0.75 +LENGTHENING_STEP 0 +MIN_SURFAREA 12.566 +MAX_TRIALS 8 +HEAD_TOLERANCE 0.005 +SYS_FLOW_TOL 5 +LAT_FLOW_TOL 5 +MINIMUM_STEP 0.5 +THREADS 1 + +[EVAPORATION] +;;Data Source Parameters +;;-------------- ---------------- +CONSTANT 0.0 +DRY_ONLY NO + +[RAINGAGES] +;;Name Format Interval SCF Source +;;-------------- --------- ------ ------ ---------- +RainGage INTENSITY 0:05 1.0 TIMESERIES 2-yr + +[SUBCATCHMENTS] +;;Name Rain Gage Outlet Area %Imperv Width %Slope CurbLen SnowPack +;;-------------- ---------------- ---------------- -------- -------- -------- -------- -------- ---------------- +S1 RainGage Aux1 4.55 56.8 1587 2 0 +S2 RainGage Aux4 4.74 63.0 1653 2 0 +S3 RainGage Aux3 3.74 39.5 1456 3.1 0 +S4 RainGage J7 6.79 49.9 2331 3.1 0 +S5 RainGage J10 4.79 87.7 1670 2 0 +S6 RainGage J11 1.98 95.0 690 2 0 +S7 RainGage J10 2.33 0.0 907 3.1 0 + +[SUBAREAS] +;;Subcatchment N-Imperv N-Perv S-Imperv S-Perv PctZero RouteTo PctRouted +;;-------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- +S1 0.015 0.24 0.06 0.3 25 OUTLET +S2 0.015 0.24 0.06 0.3 25 OUTLET +S3 0.015 0.24 0.06 0.3 25 OUTLET +S4 0.015 0.24 0.06 0.3 25 OUTLET +S5 0.015 0.24 0.06 0.3 25 OUTLET +S6 0.015 0.24 0.06 0.3 25 OUTLET +S7 0.015 0.24 0.06 0.3 25 OUTLET + +[INFILTRATION] +;;Subcatchment Param1 Param2 Param3 Param4 Param5 +;;-------------- ---------- ---------- ---------- ---------- ---------- +S1 4.5 0.2 6.5 7 0 +S2 4.5 0.2 6.5 7 0 +S3 4.5 0.2 6.5 7 0 +S4 4.5 0.2 6.5 7 0 +S5 4.5 0.2 6.5 7 0 +S6 4.5 0.2 6.5 7 0 +S7 4.5 0.2 6.5 7 0 + +[JUNCTIONS] +;;Name Elevation MaxDepth InitDepth SurDepth Aponded +;;-------------- ---------- ---------- ---------- ---------- ---------- +Aux1 4975 0 0 0 0 +Aux2 4973 0 0 0 0 +Aux3 4968.5 0 0 0 0 +Aux4 4971.8 0 0 0 0 +Aux5 4970.7 0 0 0 0 +Aux6 4969 0 0 0 0 +Aux7 4963 0 0 0 0 +J1 4969 4 0 0 0 +J10 4957.8 0 0 0 0 +J11 4957 0 0 0 0 +J2 4965 4 0 0 0 +J2a 4966.7 4 0 0 0 +J3 4973 0 0 0 0 +J4 4965 0 0 0 0 +J5 4965.8 0 0 0 0 +J6 4969 0 0 0 0 +J7 4963.5 0 0 0 0 +J8 4966.5 0 0 0 0 +J9 4964.8 0 0 0 0 + +[OUTFALLS] +;;Name Elevation Type Stage Data Gated Route To +;;-------------- ---------- ---------- ---------------- -------- ---------------- +O1 4956 FREE NO + +[CONDUITS] +;;Name From Node To Node Length Roughness InOffset OutOffset InitFlow MaxFlow +;;-------------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- +Street1 Aux1 Aux2 377.31 0.016 0 0 0 0 +Street2 Aux2 Aux4 286.06 0.016 0 0 0 0 +Street3 Aux4 Aux5 239.41 0.016 0 0 0 0 +Street4 Aux5 Aux6 157.48 0.016 0 0 0 0 +Street5 Aux6 Aux7 526.0 0.016 0 0 0 0 +C3 J3 J4 109.0 0.016 0 6 0 0 +C4 J4 J5 133.0 0.05 6 4 0 0 +C5 J5 J6 207.0 0.05 4 0 0 0 +C6 J7 J6 140.0 0.05 8 0 0 0 +C7 J6 J8 95.0 0.016 0 0 0 0 +C8 J8 J9 166.0 0.05 0 0 0 0 +C9 J9 J10 320.0 0.05 0 6 0 0 +C10 J10 J11 145.0 0.05 6 6 0 0 +C11 J11 O1 89.0 0.016 0 0 0 0 +C_Aux3 Aux3 J3 444.75 0.05 6 0 0 0 +P1 J1 J5 185.39 0.016 0 0 0 0 +P2 J2a J2 157.48 0.016 0 0 0 0 +P3 J2 J11 529.22 0.016 0 0 0 0 +P4 Aux3 J4 567.19 0.016 0 0 0 0 +P5 J5 J4 125.98 0.016 0 0 0 0 +P6 J4 J7 360.39 0.016 0 0 0 0 +P7 J7 J10 507.76 0.016 0 0 0 0 +P8 J10 J11 144.50 0.016 0 0 0 0 + +[XSECTIONS] +;;Link Shape Geom1 Geom2 Geom3 Geom4 Barrels Culvert +;;-------------- ------------ ---------------- ---------- ---------- ---------- ---------- ---------- +Street1 STREET FullStreet +Street2 STREET FullStreet +Street3 STREET FullStreet +Street4 STREET HalfStreet +Street5 STREET HalfStreet +C3 CIRCULAR 2.25 0 0 0 1 +C4 TRAPEZOIDAL 3 5 5 5 1 +C5 TRAPEZOIDAL 3 5 5 5 1 +C6 TRAPEZOIDAL 3 5 5 5 1 +C7 CIRCULAR 3.5 0 0 0 1 +C8 TRAPEZOIDAL 3 5 5 5 1 +C9 TRAPEZOIDAL 3 5 5 5 1 +C10 TRAPEZOIDAL 3 5 5 5 1 +C11 CIRCULAR 4.75 0 0 0 1 +C_Aux3 TRAPEZOIDAL 3 5 5 5 1 +P1 CIRCULAR 0.5 0 0 0 1 +P2 CIRCULAR 1.5 0 0 0 1 +P3 CIRCULAR 1.5 0 0 0 1 +P4 CIRCULAR 1.67 0 0 0 1 +P5 CIRCULAR 1.83 0 0 0 1 +P6 CIRCULAR 2 0 0 0 1 +P7 CIRCULAR 2 0 0 0 1 +P8 CIRCULAR 3.17 0 0 0 1 + +[STREETS] +;;Name Tcrown Hcurb Sx nRoad a W Sides Tback Sback nBack +;;-------------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- +HalfStreet 20 0.5 4 0.016 0 0 1 20 4 0.016 +FullStreet 20 0.5 4 0.016 0 0 2 20 4 0.016 + +[INLETS] +;;Name Type Parameters: +;;-------------- ---------------- ----------- +ComboInlet GRATE 2 2 P_BAR-50 +ComboInlet CURB 2 0.5 HORIZONTAL + +[INLET_USAGE] +;;Conduit Inlet Node Number %Clogged Qmax aLocal wLocal Placement +;;-------------- ---------------- ---------------- --------- --------- --------- --------- --------- --------- --------- +Street1 ComboInlet J1 1 50 2.2 0.5 2 +Street3 ComboInlet J2a 1 0 0 0 0 +Street4 ComboInlet J2 1 0 0 0 0 +Street5 ComboInlet J11 2 0 0 0 0 + +[TIMESERIES] +;;Name Date Time Value +;;-------------- ---------- ---------- ---------- +2-yr 0:00 0.29 +2-yr 0:05 0.33 +2-yr 0:10 0.38 +2-yr 0:15 0.64 +2-yr 0:20 0.81 +2-yr 0:25 1.57 +2-yr 0:30 2.85 +2-yr 0:35 1.18 +2-yr 0:40 0.71 +2-yr 0:45 0.42 +2-yr 0:50 0.35 +2-yr 0:55 0.3 +2-yr 1:00 0.2 +2-yr 1:05 0.19 +2-yr 1:10 0.18 +2-yr 1:15 0.17 +2-yr 1:20 0.17 +2-yr 1:25 0.16 +2-yr 1:30 0.15 +2-yr 1:35 0.15 +2-yr 1:40 0.14 +2-yr 1:45 0.14 +2-yr 1:50 0.13 +2-yr 1:55 0.13 +; +10-yr 0:00 0.49 +10-yr 0:05 0.56 +10-yr 0:10 0.65 +10-yr 0:15 1.09 +10-yr 0:20 1.39 +10-yr 0:25 2.69 +10-yr 0:30 4.87 +10-yr 0:35 2.02 +10-yr 0:40 1.21 +10-yr 0:45 0.71 +10-yr 0:50 0.6 +10-yr 0:55 0.52 +10-yr 1:00 0.39 +10-yr 1:05 0.37 +10-yr 1:10 0.35 +10-yr 1:15 0.34 +10-yr 1:20 0.32 +10-yr 1:25 0.31 +10-yr 1:30 0.3 +10-yr 1:35 0.29 +10-yr 1:40 0.28 +10-yr 1:45 0.27 +10-yr 1:50 0.26 +10-yr 1:55 0.25 + +[REPORT] +;;Reporting Options +INPUT YES +SUBCATCHMENTS ALL +NODES ALL +LINKS ALL + +[TAGS] +Link Street1 Full_Street +Link Street2 Full_Street +Link Street3 Full_Street +Link Street4 Half_Street +Link Street5 Half_Street +Link C3 Culvert +Link C4 Swale +Link C5 Swale +Link C6 Swale +Link C7 Culvert +Link C8 Swale +Link C9 Swale +Link C10 Swale +Link C11 Culvert +Link C_Aux3 Swale + +[MAP] +DIMENSIONS -255.206 -70.199 1490.833 1514.231 +Units Feet + +[COORDINATES] +;;Node X-Coord Y-Coord +;;-------------- ------------------ ------------------ +Aux1 293.152 1161.023 +Aux2 653.046 1052.180 +Aux3 122.363 696.959 +Aux4 914.142 1058.025 +Aux5 1175.238 1120.376 +Aux6 1260.972 956.704 +Aux7 1381.777 514.399 +J1 647.200 1022.952 +J10 1254.058 640.029 +J11 1270.714 491.017 +J2 1218.105 950.859 +J2a 1159.651 1069.716 +J3 405.287 905.702 +J4 505.345 862.573 +J5 631.281 859.123 +J6 803.079 869.022 +J7 831.398 709.035 +J8 915.930 840.146 +J9 1072.918 867.749 +O1 1411.468 477.401 + +[VERTICES] +;;Link X-Coord Y-Coord +;;-------------- ------------------ ------------------ +Street1 382.860 1112.719 +Street1 514.703 1061.922 +Street2 806.976 1042.437 +Street3 1062.227 1091.149 +Street4 1210.311 1061.922 +Street5 1338.911 781.341 +Street5 1387.623 662.483 +Street5 1393.468 586.493 +C4 559.710 846.393 +C5 672.684 850.497 +C5 712.363 829.795 +C5 743.415 805.643 +C5 768.006 833.950 +C6 791.719 734.912 +C6 798.620 784.942 +C8 965.959 838.421 +C8 995.287 831.520 +C8 1038.415 850.497 +C9 1102.246 867.749 +C9 1131.573 852.222 +C9 1147.099 829.795 +C9 1162.626 809.094 +C9 1198.854 779.766 +C9 1219.556 757.339 +C9 1233.357 721.111 +C9 1238.532 715.936 +C9 1235.082 674.532 +C9 1247.158 646.930 +C_Aux3 163.003 699.992 +C_Aux3 208.620 726.287 +C_Aux3 239.673 793.567 +C_Aux3 251.749 876.374 +C_Aux3 291.427 912.602 +C_Aux3 355.257 929.854 +P3 1331.117 691.711 +P3 1329.168 590.390 +P4 275.901 572.749 +P4 472.567 824.620 +P7 886.602 800.468 + +[Polygons] +;;Subcatchment X-Coord Y-Coord +;;-------------- ------------------ ------------------ +S1 282.657 1334.810 +S1 111.700 1101.604 +S1 172.525 1062.743 +S1 231.660 1027.262 +S1 306.002 990.092 +S1 370.206 959.679 +S1 409.066 946.163 +S1 444.547 936.025 +S1 493.545 924.198 +S1 532.405 915.750 +S1 569.576 907.302 +S1 610.125 897.165 +S1 655.744 897.165 +S1 684.338 1318.700 +S1 651.043 1321.922 +S1 596.269 1332.662 +S1 551.160 1346.624 +S1 495.312 1367.030 +S1 455.573 1384.214 +S1 410.465 1409.991 +S1 386.836 1427.175 +S1 363.208 1442.211 +S2 678.967 1238.149 +S2 673.584 1152.903 +S2 655.744 897.165 +S2 758.808 893.786 +S2 817.943 895.475 +S2 880.458 898.855 +S2 921.007 905.613 +S2 978.453 920.819 +S2 1042.657 937.715 +S2 1103.482 959.679 +S2 1159.238 985.023 +S2 1225.131 1010.367 +S2 1109.646 1274.665 +S2 1052.723 1400.325 +S2 985.061 1370.252 +S2 924.916 1348.772 +S2 861.549 1331.588 +S2 815.367 1325.144 +S2 762.740 1319.774 +S2 719.780 1316.552 +S2 684.338 1317.626 +S3 109.199 1103.258 +S3 141.754 1081.555 +S3 190.586 1051.713 +S3 247.557 1019.158 +S3 304.528 989.317 +S3 354.716 964.900 +S3 398.123 949.980 +S3 490.166 922.509 +S3 477.743 883.275 +S3 501.993 816.065 +S3 556.059 778.895 +S3 488.476 679.210 +S3 422.582 729.897 +S3 282.348 557.560 +S3 179.734 633.927 +S3 153.962 651.561 +S3 107.843 693.610 +S3 71.218 742.443 +S3 48.159 785.849 +S3 31.881 837.394 +S3 29.168 886.226 +S3 31.881 933.702 +S3 38.664 967.613 +S3 50.872 1001.525 +S3 65.793 1035.436 +S3 87.496 1070.704 +S3 109.199 1103.258 +S4 282.348 559.250 +S4 420.893 729.897 +S4 488.476 680.899 +S4 556.828 779.067 +S4 501.213 814.335 +S4 479.468 885.000 +S4 491.718 922.851 +S4 616.511 898.434 +S4 668.056 897.078 +S4 783.355 895.722 +S4 815.909 898.434 +S4 857.959 899.791 +S4 890.595 897.165 +S4 968.316 915.750 +S4 1042.657 937.715 +S4 1074.759 849.857 +S4 1054.484 773.826 +S4 1020.692 702.864 +S4 963.247 623.454 +S4 689.536 256.816 +S5 1301.482 474.258 +S5 1271.677 445.380 +S5 1232.340 393.835 +S5 1241.835 384.340 +S5 1222.844 366.706 +S5 1233.696 355.854 +S5 1026.159 66.931 +S5 1008.525 56.079 +S5 708.750 275.824 +S5 1023.446 704.462 +S5 1150.644 618.812 +S5 1251.203 640.809 +S5 1328.193 519.824 +S6 1334.478 519.824 +S6 1306.266 488.956 +S6 1293.380 474.205 +S6 1232.340 393.835 +S6 1241.835 381.627 +S6 1222.844 365.350 +S6 1232.340 353.142 +S6 1027.516 65.574 +S6 1012.595 56.079 +S6 707.393 273.111 +S6 688.403 254.121 +S6 739.948 218.853 +S6 788.780 159.169 +S6 806.414 106.268 +S6 813.197 1.821 +S6 994.961 12.673 +S6 1228.270 27.594 +S6 1222.844 115.763 +S6 1228.270 167.308 +S6 1241.835 229.705 +S6 1255.399 254.121 +S6 1279.815 302.953 +S6 1309.657 354.498 +S6 1335.430 401.974 +S6 1359.846 448.093 +S6 1370.616 475.830 +S6 1381.615 491.542 +S7 1122.467 968.970 +S7 1174.012 987.282 +S7 1225.557 1005.594 +S7 1377.480 675.977 +S7 1391.044 642.065 +S7 1396.470 598.659 +S7 1381.615 491.542 +S7 1331.336 519.824 +S7 1249.632 640.809 +S7 1150.644 617.241 +S7 1020.733 704.462 +S7 1054.645 772.285 +S7 1076.796 848.212 +S7 1056.370 900.062 +S7 1040.658 937.772 + +[SYMBOLS] +;;Gage X-Coord Y-Coord +;;-------------- ------------------ ------------------ +RainGage -175.841 1212.778 + +[LABELS] +;;X-Coord Y-Coord Label +145.274 1129.896 "S1" "" "Arial" 14 0 0 +758.404 969.723 "S2" "" "Arial" 14 0 0 +247.369 666.226 "S3" "" "Arial" 14 0 0 +628.971 458.688 "S4" "" "Arial" 14 0 0 +952.552 257.845 "S5" "" "Arial" 14 0 0 +827.947 56.930 "S6" "" "Arial" 14 0 0 +1073.058 780.037 "S7" "" "Arial" 14 0 0 +1385.481 454.225 "Outfall" "" "Arial" 10 1 0 + diff --git a/swmm-toolkit/tests/test_metadata.py b/swmm-toolkit/tests/test_metadata.py index 25df8839..f95faec8 100644 --- a/swmm-toolkit/tests/test_metadata.py +++ b/swmm-toolkit/tests/test_metadata.py @@ -38,48 +38,49 @@ def test_outputmetadata(handle): om = output_metadata.OutputMetadata(handle) ref = { - shared_enum.SubcatchAttribute.RAINFALL: ("Rainfall", "in/hr"), - shared_enum.SubcatchAttribute.SNOW_DEPTH: ("Snow Depth", "in"), - shared_enum.SubcatchAttribute.EVAP_LOSS: ("Evaporation Loss", "in/day"), - shared_enum.SubcatchAttribute.INFIL_LOSS: ("Infiltration Loss", "in/hr"), - shared_enum.SubcatchAttribute.RUNOFF_RATE: ("Runoff Rate", "cu ft/sec"), - shared_enum.SubcatchAttribute.GW_OUTFLOW_RATE: ("Groundwater Flow Rate", "cu ft/sec"), - shared_enum.SubcatchAttribute.GW_TABLE_ELEV: ("Groundwater Elevation", "ft"), - shared_enum.SubcatchAttribute.SOIL_MOISTURE: ("Soil Moisture", "%"), - shared_enum.SubcatchAttribute.POLLUT_CONC_0: ("TSS", "mg/L"), - shared_enum.SubcatchAttribute.POLLUT_CONC_1: ("Lead", "ug/L"), - - shared_enum.NodeAttribute.INVERT_DEPTH: ("Invert Depth", "ft"), - shared_enum.NodeAttribute.HYDRAULIC_HEAD: ("Hydraulic Head", "ft"), - shared_enum.NodeAttribute.PONDED_VOLUME: ("Ponded Volume", "cu ft"), - shared_enum.NodeAttribute.LATERAL_INFLOW: ("Lateral Inflow", "cu ft/sec"), - shared_enum.NodeAttribute.TOTAL_INFLOW: ("Total Inflow", "cu ft/sec"), - shared_enum.NodeAttribute.FLOODING_LOSSES: ("Flooding Loss", "cu ft/sec"), - shared_enum.NodeAttribute.POLLUT_CONC_0: ("TSS", "mg/L"), - shared_enum.NodeAttribute.POLLUT_CONC_1: ("Lead", "ug/L"), - - shared_enum.LinkAttribute.FLOW_RATE: ("Flow Rate", "cu ft/sec"), - shared_enum.LinkAttribute.FLOW_DEPTH: ("Flow Depth", "ft"), - shared_enum.LinkAttribute.FLOW_VELOCITY: ("Flow Velocity", "ft/sec"), - shared_enum.LinkAttribute.FLOW_VOLUME: ("Flow Volume", "cu ft"), - shared_enum.LinkAttribute.CAPACITY: ("Capacity", "%"), - shared_enum.LinkAttribute.POLLUT_CONC_0: ("TSS", "mg/L"), - shared_enum.LinkAttribute.POLLUT_CONC_1: ("Lead", "ug/L"), - - shared_enum.SystemAttribute.AIR_TEMP: ("Temperature", "deg F"), - shared_enum.SystemAttribute.RAINFALL: ("Rainfall", "in/hr"), - shared_enum.SystemAttribute.SNOW_DEPTH: ("Snow Depth", "in"), - shared_enum.SystemAttribute.EVAP_INFIL_LOSS: ("Evap and Infil Losses", "in/hr"), - shared_enum.SystemAttribute.RUNOFF_FLOW: ("Runoff Flow Rate", "cu ft/sec"), - shared_enum.SystemAttribute.DRY_WEATHER_INFLOW: ("Dry Weather Inflow", "cu ft/sec"), - shared_enum.SystemAttribute.GW_INFLOW: ("Groundwater Inflow", "cu ft/sec"), - shared_enum.SystemAttribute.RDII_INFLOW: ("RDII Inflow", "cu ft/sec"), - shared_enum.SystemAttribute.DIRECT_INFLOW: ("Direct Inflow", "cu ft/sec"), - shared_enum.SystemAttribute.TOTAL_LATERAL_INFLOW: ("Total Lateral Inflow", "cu ft/sec"), - shared_enum.SystemAttribute.FLOOD_LOSSES: ("Flood Losses", "cu ft/sec"), - shared_enum.SystemAttribute.OUTFALL_FLOWS: ("Outfall Flow", "cu ft/sec"), - shared_enum.SystemAttribute.VOLUME_STORED: ("Volume Stored", "cu ft"), - shared_enum.SystemAttribute.EVAP_RATE: ("Evaporation Rate", "in/day") + shared_enum.SubcatchAttribute.RAINFALL: ("Rainfall", "in/hr"), + shared_enum.SubcatchAttribute.SNOW_DEPTH: ("Snow Depth", "in"), + shared_enum.SubcatchAttribute.EVAP_LOSS: ("Evaporation Loss", "in/day"), + shared_enum.SubcatchAttribute.INFIL_LOSS: ("Infiltration Loss", "in/hr"), + shared_enum.SubcatchAttribute.RUNOFF_RATE: ("Runoff Rate", "cu ft/sec"), + shared_enum.SubcatchAttribute.GW_OUTFLOW_RATE: ("Groundwater Flow Rate", "cu ft/sec"), + shared_enum.SubcatchAttribute.GW_TABLE_ELEV: ("Groundwater Elevation", "ft"), + shared_enum.SubcatchAttribute.SOIL_MOISTURE: ("Soil Moisture", "%"), + shared_enum.SubcatchAttribute.POLLUT_CONC_0: ("TSS", "mg/L"), + shared_enum.SubcatchAttribute.POLLUT_CONC_1: ("Lead", "ug/L"), + + shared_enum.NodeAttribute.INVERT_DEPTH: ("Invert Depth", "ft"), + shared_enum.NodeAttribute.HYDRAULIC_HEAD: ("Hydraulic Head", "ft"), + shared_enum.NodeAttribute.PONDED_VOLUME: ("Ponded Volume", "cu ft"), + shared_enum.NodeAttribute.LATERAL_INFLOW: ("Lateral Inflow", "cu ft/sec"), + shared_enum.NodeAttribute.TOTAL_INFLOW: ("Total Inflow", "cu ft/sec"), + shared_enum.NodeAttribute.FLOODING_LOSSES: ("Flooding Loss", "cu ft/sec"), + shared_enum.NodeAttribute.POLLUT_CONC_0: ("TSS", "mg/L"), + shared_enum.NodeAttribute.POLLUT_CONC_1: ("Lead", "ug/L"), + + shared_enum.LinkAttribute.FLOW_RATE: ("Flow Rate", "cu ft/sec"), + shared_enum.LinkAttribute.FLOW_DEPTH: ("Flow Depth", "ft"), + shared_enum.LinkAttribute.FLOW_VELOCITY: ("Flow Velocity", "ft/sec"), + shared_enum.LinkAttribute.FLOW_VOLUME: ("Flow Volume", "cu ft"), + shared_enum.LinkAttribute.CAPACITY: ("Capacity", "%"), + shared_enum.LinkAttribute.POLLUT_CONC_0: ("TSS", "mg/L"), + shared_enum.LinkAttribute.POLLUT_CONC_1: ("Lead", "ug/L"), + + shared_enum.SystemAttribute.AIR_TEMP: ("Temperature", "deg F"), + shared_enum.SystemAttribute.RAINFALL: ("Rainfall", "in/hr"), + shared_enum.SystemAttribute.SNOW_DEPTH: ("Snow Depth", "in"), + shared_enum.SystemAttribute.EVAP_INFIL_LOSS: ("Evap and Infil Losses", "in/hr"), + shared_enum.SystemAttribute.RUNOFF_FLOW: ("Runoff Flow Rate", "cu ft/sec"), + shared_enum.SystemAttribute.DRY_WEATHER_INFLOW: ("Dry Weather Inflow", "cu ft/sec"), + shared_enum.SystemAttribute.GW_INFLOW: ("Groundwater Inflow", "cu ft/sec"), + shared_enum.SystemAttribute.RDII_INFLOW: ("RDII Inflow", "cu ft/sec"), + shared_enum.SystemAttribute.DIRECT_INFLOW: ("Direct Inflow", "cu ft/sec"), + shared_enum.SystemAttribute.TOTAL_LATERAL_INFLOW: ("Total Lateral Inflow", "cu ft/sec"), + shared_enum.SystemAttribute.FLOOD_LOSSES: ("Flood Losses", "cu ft/sec"), + shared_enum.SystemAttribute.OUTFALL_FLOWS: ("Outfall Flow", "cu ft/sec"), + shared_enum.SystemAttribute.VOLUME_STORED: ("Volume Stored", "cu ft"), + shared_enum.SystemAttribute.EVAP_RATE: ("Evaporation Rate", "in/day"), + shared_enum.SystemAttribute.PTNL_EVAP_RATE: ("Potential Evaporation Rate", "in/day") } for attr in shared_enum.SubcatchAttribute: diff --git a/swmm-toolkit/tests/test_output.py b/swmm-toolkit/tests/test_output.py index 9e3224f8..be628881 100644 --- a/swmm-toolkit/tests/test_output.py +++ b/swmm-toolkit/tests/test_output.py @@ -194,3 +194,12 @@ def test_getsystemresult(handle): assert len(test_array) == 14 assert np.allclose(test_array, ref_array) + +def test_getsystemattribute(handle): + + ref_array = np.array([70.0]) + + test_array = output.get_system_attribute(handle, 0, shared_enum.SystemAttribute.AIR_TEMP) + + assert len(test_array) == 1 + assert np.allclose(test_array, ref_array) diff --git a/swmm-toolkit/tests/test_solver.py b/swmm-toolkit/tests/test_solver.py index ae6a23e9..766089e4 100644 --- a/swmm-toolkit/tests/test_solver.py +++ b/swmm-toolkit/tests/test_solver.py @@ -21,6 +21,13 @@ INPUT_FILE_EXAMPLE_2 = os.path.join(DATA_PATH, 'test_Example2.inp') REPORT_FILE_TEST_2 = os.path.join(DATA_PATH, 'temp_Example2.rpt') OUTPUT_FILE_TEST_2 = os.path.join(DATA_PATH, 'temp_Example2.out') +INPUT_FILE_EXAMPLE_3 = os.path.join(DATA_PATH, 'test_Example3.inp') +REPORT_FILE_TEST_3 = os.path.join(DATA_PATH, 'temp_Example3.rpt') +OUTPUT_FILE_TEST_3 = os.path.join(DATA_PATH, 'temp_Example3.out') +INPUT_FILE_INLET = os.path.join(DATA_PATH, 'test_inlet_drains.inp') +REPORT_FILE_INLET = os.path.join(DATA_PATH, 'temp_inlet_drains.rpt') +OUTPUT_FILE_INLET = os.path.join(DATA_PATH, 'temp_inlet_drains.out') + INPUT_FILE_FAIL = os.path.join(DATA_PATH, 'temp_nodata.inp') @@ -82,6 +89,38 @@ def close(): request.addfinalizer(close) +@pytest.fixture() +def inlet_handle(request): + solver.swmm_open(INPUT_FILE_INLET, REPORT_FILE_INLET, OUTPUT_FILE_INLET) + + + def close(): + solver.swmm_close() + + request.addfinalizer(close) + +@pytest.fixture() +def run_inlet_sim(request): + solver.swmm_open(INPUT_FILE_INLET, REPORT_FILE_INLET, OUTPUT_FILE_INLET) + solver.swmm_start(0) + + def close(): + solver.swmm_end() + solver.swmm_close() + + request.addfinalizer(close) + +@pytest.fixture() +def run_pollut_sim(request): + solver.swmm_open(INPUT_FILE_EXAMPLE_3, REPORT_FILE_TEST_3, OUTPUT_FILE_TEST_3) + solver.swmm_start(0) + + def close(): + solver.swmm_end() + solver.swmm_close() + + request.addfinalizer(close) + def test_step(handle): solver.swmm_start(0) @@ -94,12 +133,30 @@ def test_step(handle): solver.swmm_end() solver.swmm_report() +def test_stride(handle): + solver.swmm_start(0) + steps = 0 + while True: + time = solver.swmm_stride(60 * 60) + steps+=1 + if time == 0: + break + + solver.swmm_end() + solver.swmm_report() + # advancing a 36 hour simulation hourly should yeild 36 steps + assert steps == 36 def test_version(handle): - major, minor, patch = solver.swmm_version_info() + major, minor, patch = solver.swmm_version_info().split('.') print(major, minor, patch) assert major == '5' - + +def test_legacy_version(handle): + version = solver.swmm_get_version() + major = str(version)[0] + assert isinstance(version, int) + assert major == '5' def test_simulation_unit(handle): simulation_system_unit_option = solver.simulation_get_unit(shared_enum.UnitProperty.SYSTEM_UNIT) @@ -296,6 +353,35 @@ def test_link_get_pollutant(run_sim): assert tss == pytest.approx(14.7179, 0.1) assert lead == pytest.approx(2.9435, 0.1) +def test_link_get_pollutant_reactor(run_sim): + pollut = solver.link_get_pollutant(0, shared_enum.LinkPollutant.REACTOR_CONC) + tss, lead = tuple(pollut) + assert tss == 0.0 + assert lead == 0.0 + + for i in range(0, 250): + solver.swmm_step() + pollut = solver.link_get_pollutant(0, shared_enum.LinkPollutant.REACTOR_CONC) + print(pollut) + + tss, lead = tuple(pollut) + + assert tss == pytest.approx(14.7179, 0.1) + assert lead == pytest.approx(2.9435, 0.1) + +def test_link_set_pollutant(run_pollut_sim): + upstream_link = 'Valve' + downstream_node = 'Outfall' + pollutant = 'P1' + + upstream_link = solver.project_get_index(shared_enum.ObjectType.LINK, upstream_link) + downstream_node = solver.project_get_index(shared_enum.ObjectType.NODE, downstream_node) + pollutant = solver.project_get_index(shared_enum.ObjectType.POLLUT, pollutant) + + for i in range(0, 200): + solver.link_set_pollutant(upstream_link,shared_enum.LinkPollutant.QUALITY,pollutant,1000) + solver.swmm_step() + assert round(solver.node_get_pollutant(downstream_node,shared_enum.NodePollutant.QUALITY)[pollutant]) == 1000 def test_link_set_target_setting(run_sim): target_setting = solver.link_get_result(0, shared_enum.LinkResult.TARGET_SETTING) @@ -397,6 +483,59 @@ def test_node_get_pollutant(run_sim): assert tss == pytest.approx(14.7179, 0.1) assert lead == pytest.approx(2.9435, 0.1) +def test_node_get_pollutant_reactor(run_pollut_sim): + # Need to test on a storage node + node_index = solver.project_get_index(shared_enum.ObjectType.NODE, 'Tank') + #print(node_index) + pollut = solver.node_get_pollutant(1, shared_enum.NodePollutant.REACTOR_CONC) + p1 = pollut[0] + assert p1 == 0.0 + + for i in range(0, 250): + solver.swmm_step() + pollut = solver.node_get_pollutant(1, shared_enum.NodePollutant.REACTOR_CONC) + + p1 = pollut[0] + assert p1 == pytest.approx(2.4455, 0.1) + +def test_node_get_pollutant_inflow(run_pollut_sim): + # Need to test on a storage node + node_index = solver.project_get_index(shared_enum.ObjectType.NODE, 'Tank') + #print(node_index) + pollut = solver.node_get_pollutant(1, shared_enum.NodePollutant.INFLOW_CONC) + p1 = pollut[0] + assert p1 == 0.0 + + for i in range(0, 250): + solver.swmm_step() + pollut = solver.node_get_pollutant(1, shared_enum.NodePollutant.INFLOW_CONC) + + p1 = pollut[0] + assert p1 == pytest.approx(10.0, 0.1) + +def test_node_set_pollutant(run_pollut_sim): + upstream_node = 'Tank' + downstream_node = 'Outfall' + pollutant = 'P1' + + upstream_node = solver.project_get_index(shared_enum.ObjectType.NODE, upstream_node) + downstream_node = solver.project_get_index(shared_enum.ObjectType.NODE, downstream_node) + pollutant = solver.project_get_index(shared_enum.ObjectType.POLLUT, pollutant) + + for i in range(0, 200): + solver.node_set_pollutant(upstream_node,shared_enum.NodePollutant.QUALITY, pollutant,1000) + solver.swmm_step() + assert round(solver.node_get_pollutant(downstream_node,shared_enum.NodePollutant.QUALITY)[pollutant]) == 1000 + +def test_node_get_hrt(run_pollut_sim): + upstream_node = 'Tank' + upstream_node = solver.project_get_index(shared_enum.ObjectType.NODE, upstream_node) + + + for i in range(0, 200): + solver.swmm_step() + assert round(solver.node_get_result(upstream_node, shared_enum.NodeResult.HYD_RES_TIME)) == 17 + def test_node_total_inflow(run_sim): total_inflow = solver.node_get_total_inflow(0) @@ -659,3 +798,56 @@ def test_gage_precipitation(run_sim): assert total == 1.0 assert snowfall == 0.0 assert rainfall == 1.0 + + + +def test_inlet_error(inlet_handle): + with pytest.raises(Exception) as e: + index = solver.project_get_index(shared_enum.ObjectType.LINK,"C3") + clogged = solver.inlet_get_parameter(index, shared_enum.InletProperty.CLOG_FACTOR) + assert "Specified link is not assigned an inlet" in str(e.value) + + +def test_inlet_clogging(inlet_handle): + index = solver.project_get_index(shared_enum.ObjectType.LINK,"Street1") + + num_inlets = solver.inlet_get_parameter(index, shared_enum.InletProperty.NUM_INLETS) + assert num_inlets == 1 + + clogged = solver.inlet_get_parameter(index, shared_enum.InletProperty.CLOG_FACTOR) + assert clogged == 50 + + solver.inlet_set_parameter(index, shared_enum.InletProperty.CLOG_FACTOR,0) + clogged = solver.inlet_get_parameter(index, shared_enum.InletProperty.CLOG_FACTOR) + assert clogged == 0 + + flow_limit = solver.inlet_get_parameter(index, shared_enum.InletProperty.FLOW_LIMIT) + assert flow_limit == 2.2 + + solver.inlet_set_parameter(index, shared_enum.InletProperty.FLOW_LIMIT,5.5) + flow_limit = solver.inlet_get_parameter(index, shared_enum.InletProperty.FLOW_LIMIT) + assert flow_limit == 5.5 + + dep_height = solver.inlet_get_parameter(index, shared_enum.InletProperty.DEPRESSION_HEIGHT) + assert dep_height == 0.5 + + dep_width = solver.inlet_get_parameter(index, shared_enum.InletProperty.DEPRESSION_WIDTH) + assert dep_width == 2 + +def test_hotstart(run_inlet_sim): + for i in range(0, 100): + solver.swmm_step() + + # save hotstart and pull out a node depth + solver.swmm_hotstart(shared_enum.HotstartFile.SAVE,'HS_FILE.hs') + prev_depth = solver.node_get_result(0, shared_enum.NodeResult.DEPTH) + solver.swmm_end() + solver.swmm_close() + + # restart sim using hotstart file and check that node depth is the same + solver.swmm_open(INPUT_FILE_INLET, REPORT_FILE_INLET, OUTPUT_FILE_INLET) + solver.swmm_hotstart(shared_enum.HotstartFile.USE,'HS_FILE.hs') + solver.swmm_start(0) + new_depth = solver.node_get_result(0, shared_enum.NodeResult.DEPTH) + assert prev_depth > 0 + assert prev_depth == pytest.approx(new_depth, 0.1) diff --git a/swmm-toolkit/tools/build-wheels.sh b/swmm-toolkit/tools/build-wheels.sh index aa05a3ea..738627ca 100755 --- a/swmm-toolkit/tools/build-wheels.sh +++ b/swmm-toolkit/tools/build-wheels.sh @@ -1,9 +1,10 @@ #!/bin/bash # -# build-wheels.sh - in a manyLinux docker image using dock10cross +# build-wheels.sh - in a manyLinux docker image using dockcross # # Date created: Feb 2, 2021 +# Date modified: Jun 7, 2021 # # Author: See AUTHORS # @@ -12,7 +13,7 @@ set -e -x # Install a system package required by our library -sudo yum install -y swig +# sudo yum install -y swig # Setup and build in swmm-toolkit dir @@ -20,23 +21,21 @@ mkdir -p ./dist cd swmm-toolkit # Build wheels -for PYBIN in /opt/python/*/bin; do - if [ ${PYBIN} != "/opt/python/cp35-cp35m/bin" ]; then - # Setup python virtual environment for build - ${PYBIN}/python -m venv --clear ./build-env - source ./build-env/bin/activate - - # Install build requirements - python -m pip install -r build-requirements.txt - - # Build wheel - python setup.py bdist_wheel - mv ./dist/*.whl ../dist/ - - # cleanup - python setup.py clean - deactivate - fi +for PYBIN in /opt/python/cp{37,38,39,310,311}*/bin; do + # Setup python virtual environment for build + ${PYBIN}/python -m venv --clear ./build-env + source ./build-env/bin/activate + + # Install build requirements + python -m pip install -r build-requirements.txt + + # Build wheel + python setup.py bdist_wheel + mv ./dist/*.whl ../dist/ + + # cleanup + python setup.py clean + deactivate done # Cleanup @@ -47,25 +46,23 @@ rm -rf ./build-env cd .. # Bundle external shared libraries into the wheels -for whl in ./dist/*-linux_x86_64.whl; do - auditwheel repair $whl -w ./dist +for WHL in ./dist/*-linux_x86_64.whl; do + auditwheel repair -L '' -w ./dist $WHL done # Install packages and test -for PYBIN in /opt/python/*/bin; do - if [ ${PYBIN} != "/opt/python/cp35-cp35m/bin" ]; then - # Setup python virtual environment for test - ${PYBIN}/python -m venv --clear ./test-env - source ./test-env/bin/activate +for PYBIN in /opt/python/cp{37,38,39,310}*/bin; do + # Setup python virtual environment for test + ${PYBIN}/python -m venv --clear ./test-env + source ./test-env/bin/activate - python -m pip install -r swmm-toolkit/test-requirements.txt + python -m pip install -r swmm-toolkit/test-requirements.txt - python -m pip install --verbose --no-index --find-links=./dist swmm_toolkit - pytest + python -m pip install --verbose --no-index --find-links=./dist swmm_toolkit + pytest - deactivate - fi + deactivate done # Cleanup