diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 0d8bff3ec..41e7c5020 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -2,7 +2,7 @@ # build-and-test.yml - GitHub Actions CI for swmm-solver # # Created: May 19, 2020 -# Updated: Aug 13, 2020 +# Updated: Jun 22, 2021 # # Author: Michael E. Tryby # US EPA - ORD/CESER @@ -14,40 +14,39 @@ name: Build and Test on: [push, pull_request] -# push: -# branches: [master release develop] -# tags: -# - 'v*.*.*' -# pull_request: -# branches: [master release develop] jobs: build: strategy: fail-fast: false matrix: - os: [windows-2016, ubuntu-16.04, macos-10.15] + os: [windows-2022, ubuntu-20.04, macos-10.15] requirements: [requirements-swmm.txt] include: - - os: windows-2016 + - os: windows-2022 sys_pkgs: choco install boost-msvc-14.1 - generator: Visual Studio 15 2017 Win64 - experimental: true - script_extension: cmd + build_unit_test: make.cmd /g "Visual Studio 17 2022" /A "x64" /t + build_reg_test: make.cmd /g "Visual Studio 17 2022" /A "x64" + before_reg_test: before-nrtest.cmd + run_reg_test: run-nrtests.cmd + build_id: "%GITHUB_RUN_ID%_%GITHUB_RUN_NUMBER%" + experimental: false artifacts_ext: zip artifact_content_type: zip - gh_run_number: "%GITHUB_RUN_ID%_%GITHUB_RUN_NUMBER%" defaults: run: shell: cmd working-directory: ./ci-tools/windows - - os: ubuntu-16.04 + - os: ubuntu-20.04 sys_pkgs: sudo apt install libboost-dev libboost-all-dev - generator: "Unix Makefiles" + # Statically link libraries with -s switch to address GitHub Ubuntu 20.04 symbol errors (issue #340) + build_unit_test: make.sh -s -t -g "Unix Makefiles" + build_reg_test: make.sh -s -g "Unix Makefiles" + before_reg_test: before-nrtest.sh + run_reg_test: run-nrtests.sh + build_id: ${GITHUB_RUN_ID}_${GITHUB_RUN_NUMBER} experimental: true - script_extension: sh - gh_run_number: ${GITHUB_RUN_ID}_${GITHUB_RUN_NUMBER} artifacts_ext: tar.gz artifact_content_type: tar defaults: @@ -57,11 +56,12 @@ jobs: - os: macos-10.15 sys_pkgs: brew install libomp boost - generator: Xcode + build_unit_test: make.zsh -t -g "Xcode" + build_reg_test: make.zsh -g "Xcode" + before_reg_test: before-nrtest.zsh + run_reg_test: run-nrtests.zsh + build_id: ${GITHUB_RUN_ID}_${GITHUB_RUN_NUMBER} experimental: true - ci_tools_path: ci-tools/darwin - script_extension: zsh - gh_run_number: ${GITHUB_RUN_ID}_${GITHUB_RUN_NUMBER} artifacts_ext: tar.gz artifact_content_type: tar defaults: @@ -80,8 +80,6 @@ jobs: PROJECT: swmm BUILD_HOME: build TEST_HOME: nrtests - NRTESTS_URL: https://github.com/OpenWaterAnalytics/swmm-nrtestsuite - # ACTIONS_ALLOW_UNSECURE_COMMANDS: true steps: - name: Checkout repo @@ -102,26 +100,25 @@ jobs: - name: Install requirements run: | python -m pip install --upgrade pip - python -m pip install -r ${{ matrix.requirements }} + python -m pip install -r requirements-swmm.txt - name: Install required system packages run: ${{ matrix.sys_pkgs }} - name: Build and unit test - run: | - ./make.${{ matrix.script_extension }} -t -g "${{ matrix.generator }}" + run: ./${{ matrix.build_unit_test }} - name: Build for reg test - run: | - ./make.${{ matrix.script_extension }} -g "${{ matrix.generator }}" + run: ./${{ matrix.build_reg_test }} - name: Before reg test - run: | - ./before-nrtest.${{ matrix.script_extension }} v1.0.3-dev + env: + NRTESTS_URL: https://github.com/OpenWaterAnalytics/swmm-nrtestsuite + BENCHMARK_TAG: v2.0.1 + run: ./${{ matrix.before_reg_test }} ${{ env.BENCHMARK_TAG }} - name: Run reg test - run: | - ./run-nrtests.${{ matrix.script_extension }} ${{ matrix.gh_run_number }} + run: ./${{ matrix.run_reg_test }} ${{ matrix.build_id }} - name: Upload artifacts if: ${{ always() }} @@ -129,25 +126,3 @@ jobs: with: name: build-test-artifacts path: upload/*.* - - # - name: Create release - # id: create_release - # uses: actions/create-release@v1 - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # with: - # tag_name: ${{ github.ref }} - # release_name: Release ${{ github.ref }} - # draft: true - # prerelease: true - - # - name: Upload release assets - # id: upload-release-asset - # uses: actions/upload-release-asset@v1 - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # with: - # upload_url: ${{ steps.create_release.outputs.upload_url }} - # asset_path: upload/${PROJECT}*.${{ matrix.artifacts_ext }} - # asset_name: owa-${PROJECT}-${{ matrix.os }}-${{ github.ref }}.${{ matrix.artifacts_ext }} - # asset_content_type: application/${{ matrix.artifact_content_type }} diff --git a/.gitignore b/.gitignore index 9aed7e952..fec94365b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ # Build files +ci-tools/ build/ *.o /Debug/ @@ -45,3 +46,4 @@ tests/solver/data/feng* # Generated files *_export.h +version.h diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index f76d9c764..000000000 --- a/AUTHORS +++ /dev/null @@ -1,26 +0,0 @@ -# Authors ordered by first contribution. - - -Authors with Contributions in the Public Domain: - -Lewis Rossman -Robert Dickinson -Michael Tryby -Katherine Ratliff -Michelle Simon - - -Authors with Contributions Subject to Copyright (see LICENSE): - -Bryant E. McDonnell -Adam Erispaha -Sam Hatchett -Gonzalo Peña-Castellanos -Abhiram Mullapudi -Jennifer Wu -Dominik Leutnant -Xu Xi <12907470@qq.com> -Caleb Buahin -Hsi-Nien Tan -Mingda Zhang -Laurent Courty diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 000000000..4723ae477 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,23 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." +authors: +- family-names: "McDonnell" + given-names: "Bryant" + orcid: "https://orcid.org/0000-0002-6250-2220" +- family-names: "Wu" + given-names: "Jia Xin" + orcid: "https://orcid.org/0000-0003-2233-9542" +- family-names: "Ratliff" + given-names: "Katherine" + orcid: "https://orcid.org/0000-0003-1410-2756" +- family-names: "Mullapudi" + given-names: "Abhiram" + orcid: "https://orcid.org/0000-0001-8141-3621" +- family-names: "Tryby" + given-names: "Michael" + orcid: "https://orcid.org/0000-0001-5525-0734" +title: "Open Water Analytics Stormwater Management Model" +version: 5.1.13 +doi: 10.5281/zenodo.5484299 +date-released: 2021-01-12 +url: "https://github.com/OpenWaterAnalytics/Stormwater-Management-Model" diff --git a/CMakeLists.txt b/CMakeLists.txt index 77fee6f75..087455567 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,10 +4,14 @@ # Created: July 11, 2019 # Updated: May 19, 2021 # -# Author: Michael E. Tryby -# US EPA ORD/CESER +# Authors: Michael E. Tryby +# US EPA ORD/CESER # +################################################################################ +################## CMAKELISTS FOR SWMM-SOLVER PROJECT #################### +################################################################################ + cmake_minimum_required (VERSION 3.13) @@ -18,9 +22,9 @@ endif() project(swmm-solver - VERSION 5.1.13 + VERSION 5.1.14 LANGUAGES C CXX - ) +) # Append local dir to module search path # list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) @@ -41,9 +45,12 @@ set(LIBRARY_DIST "lib") set(CONFIG_DIST "cmake") +# Define build options option(BUILD_TESTS "Build component tests (requires Boost)" OFF) option(BUILD_DOCS "Build toolkit docs (requires Doxygen)" OFF) +# Added option to statically link libraries to address GitHub Ubuntu 20.04 symbol errors (issue #340) +option(BUILD_SHARED_LIBS "Build using shared libraries" ON) # Add project subdirectories if(BUILD_DOCS) @@ -68,11 +75,11 @@ endif() include(InstallRequiredSystemLibraries) -# Create install target for License and Authors files +# Create install target for License and Contributors files install( FILES "LICENSE" - "AUTHORS" + "CONTRIBUTORS" DESTINATION "." ) @@ -80,7 +87,7 @@ install( # Configure CPack driven installer package set(CPACK_GENERATOR "ZIP;TGZ") -set(CPACK_PACKAGE_VENDOR "US_EPA") +set(CPACK_PACKAGE_VENDOR "OWA") set(CPACK_ARCHIVE_FILE_NAME "swmm") include(CPack) diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 000000000..7245880ab --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,111 @@ +# +# CONTRIBUTORS +# +# List of people whose contributions reside in the default branch +# of OWA SWMM ordered alphabetically by last name. This file is modeled after +# the CREDITS file maintained by the Linux project. +# +# Fields are: +# name (N), email (E), license (L), description (D) +# + +N: Colleen Barr +E: barr.colleen@epa.gov +L: Public Domain +D: Output file API + +N: Caleb Buahin +E: caleb.buahin@gmail.com +L: MIT License +D: Development operations, bug fix, v5.1.14 merge, review + +N: Laurent Courty +E: lrntct@gmail.com +L: MIT License +D: Bug fix, testing + +N: Robert Dickinson +E: robert.dickinson@gmail.com +L: Public Domain +D: Legacy maintainer + +N: Adam Erispaha +E: aerispaha@gmail.com +L: MIT License +D: Linux makefile + +N: Sam Hatchett +E: samhatchett@gmail.com +L: MIT License +D: Development operations + +N: Constantine Karos +E: ckaros@outlook.com +L: MIT License +D: Bug fix, testing, development operations, Water quality API + +N: Dominik Leutnant +E: leutnant@fh-muenster.de +L: MIT License +D: Mac OS build + +N: Brooke Mason +E: bemason@umich.edu +L: MIT License +D: Water quality API, testing + +N: Bryant McDonnell +E: bemcdonnell@gmail.com +L: MIT License +D: Founder, maintainer, toolkit API, testing, review, bug fix, documentation + +N: Abhiram Mullapudi +E: abhiramm@umich.edu +L: MIT License +D: Rain API, testing, water quality API, development operations, review + +N: Gonzalo Peña-Castellanos +E: goanpeca@gmail.com +L: MIT License +D: Development operations, testing, documentation + +N: Katherine Ratliff +E: ratliff.katherine@epa.gov +L: MIT License +D: Stats API, bug fix, testing, review + +N: Lewis Rossman +E: LRossman@cinci.rr.com +L: Public Domain +D: Legacy developer + +N: Michelle Simon +E: simon.michelle@epa.gov +L: Public Domain +D: Documentation + +N: Hsi-Nien Tan +E: hsi-nien.tan@vumc.org +L: MIT License +D: Bug fix, testing + +N: Michael Tryby +E: tryby.michael@epa.gov +L: Public Domain +D: Mentor, development operations, review +D: Output library, testing framework, CLI, versioning, Python wrapper + +N: Jia Xin Wu +E: wuu.jennifer@gmail.com +L: MIT License +D: Maintainer, LID API, bug fixes, testing, development operations, Python wrapper, review + +N: Xu Xi +E: 12907470@qq.com +L: MIT License +D: Bug fix + +N: Mingda Zhang +E: mingda_zhang@163.com +L: MIT License +D: Bug fix, testing diff --git a/LICENSE b/LICENSE index 270ff7558..1d04a2c91 100644 --- a/LICENSE +++ b/LICENSE @@ -1,32 +1,17 @@ -This project contains original material released as part of USEPA SWMM v5.1.13. -Original material residing in the public domain is unclaimable. - -This project also contains new material prepared by the United States -Government for which domestic copyright protection is not available under 17 -USC § 105. - - -Public Domain - -Material original to USEPA SWMM v5.1.13 No Copyright Restrictions -Output library, shared objects, CLI, build and test systems No Copyright -Restrictions 2020 U.S. Federal Government -=============================================================================== This project contains material from https://github.com/OpenWaterAnalytics/ -Stormwater-Management-Model. All material created by the AUTHORS is released -under the MIT License. +Stormwater-Management-Model. All material created by the CONTRIBUTORS is released +under the MIT License unless otherwise noted. OWA SWMM may also includes third-party software libraries which have separate licensing policies. - MIT License -Copyright (c) 2020 see AUTHORS, excluding material in the public +Copyright (c) 2020-2021 see CONTRIBUTORS, excluding material in the public domain. @@ -49,6 +34,25 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +=============================================================================== + +This project contains original material released as part of USEPA SWMM v5.1.14. +Original material residing in the public domain is unclaimable. + +This project also contains new material prepared by the United States +Government for which domestic copyright protection is not available under 17 +USC § 105. + + +Public Domain + +Material original to USEPA SWMM v5.1.14 No Copyright Restrictions + +Output library, shared objects, CLI, build and test systems No Copyright +Restrictions 2020-2021 U.S. Federal Government + + +=============================================================================== Third-Party Libraries diff --git a/README.md b/README.md index a74ea77ad..e5c747a1b 100644 --- a/README.md +++ b/README.md @@ -2,34 +2,45 @@ ORD Stormwater Management Model (aka "SWMM") +## Introduction +This is the open source SWMM source code repository maintained by the Open +Water Analytics group. + +SWMM is a dynamic hydrology-hydraulic water quality simulation model. It is +used for single event or long-term (continuous) simulation of runoff quantity +and quality from primarily urban areas. SWMM source code is written in the C +Programming Language and released under combination a of MIT-License and Public +Domain. For more information on licensing, please see the [LICENSE](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/LICENSE). + ## Project Information -[![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model) -[![Join the chat at https://gitter.im/OpenWaterAnalytics/lobby](https://badges.gitter.im/OpenWaterAnalytics/Stormwater-Management-Model.svg)](https://gitter.im/OpenWaterAnalytics/lobby) +[![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/LICENSE) [![docs](https://img.shields.io/badge/docs-passing-green.svg)](http://wateranalytics.org/Stormwater-Management-Model/) -## Build Status ![build](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/workflows/Build%20and%20Test/badge.svg?branch=master) -# Introduction -This is the open source SWMM source code repository maintained by the Open -Water Analytics group. +## Citing This Work -SWMM is a dynamic hydrology-hydraulic water quality simulation model. It is -used for single event or long-term (continuous) simulation of runoff quantity -and quality from primarily urban areas. SWMM source code is written in the C -Programming Language and released in the Public Domain. +Open source software is typically developed by unpaid community-forward volunteers +who see greater purpose for their code bases. The contributors dedicate much of +their own time to make robust software so that it can be used and easily understood +by users. When you use any of the compiled or raw code, build scripts, testing +or testing artifacts found in this project consider the amount of time it took +the contributing members to make it. The following link provides the appropriate +way to cite this software. Show your appreciation through proper citation! + +[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5484299.svg)](https://doi.org/10.5281/zenodo.5484299) -# Contributing +## Contributing Everyone is welcome to contribute to this project. -See [CONTRIBUTING.md](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/.github/CONTRIBUTING.md) for insructions on setting your development environment. +See [CONTRIBUTING.md](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/wiki/Contributing) for instructions on setting your development environment. -# Regression Testing +## OWA-SWMM Testing -To run the test suite for please refer to the [REGRESSION_TESTING.md](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/.github/REGRESSION_TESTING.md) +To run the test suite for please refer to the [REGRESSION_TESTING.md](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/wiki/Testing-System) -# Code of Conduct +## Code of Conduct -The SWMM Project follows the [Contributor Covenant Code of Conduct](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/.github/CODE_OF_CONDUCT.md) +The SWMM Project follows the [Contributor Covenant Code of Conduct](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/wiki/Code-of-Conduct) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 491934fb2..8f1b6155d 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -6,15 +6,17 @@ official USEPA SWMM release. See the AUTHORS file for a list of contributors. - -## Toolkit API (new functions): +## Toolkit API (new functions) +-------------------------------- ### Projects + swmm_project_findObject() swmm_getObjectId() swmm_countObjects() ### Simulation Settings + swmm_getSimulationDateTime() swmm_getCurrentDateTime() swmm_setSimulationDateTime() @@ -23,6 +25,7 @@ swmm_getSimulationParam() swmm_getSimulationUnit() ### Nodes + swmm_getNodeType() swmm_getNodeParam() swmm_setNodeParam() @@ -33,13 +36,16 @@ swmm_setNodeInflow() swmm_getNodeStats() ### Storage + swmm_getStorageStats() ### Outfall + swmm_setOutfallStage() swmm_getOutfallStats() ### Links + swmm_getLinkType() swmm_getLinkConnections() swmm_getLinkDirection() @@ -51,9 +57,11 @@ swmm_setLinkSetting() swmm_getLinkStats() ### Pumps + swmm_getPumpStats() ### Subcatchments + swmm_getSubcatchOutConnection() swmm_getSubcatchParam() swmm_setSubcatchParam() @@ -62,10 +70,12 @@ swmm_getSubcatchPollut() swmm_getSubcatchStats() ### System + swmm_getSystemRoutingTotals() swmm_getSystemRunoffTotals() ### LIDs + swmm_getLidUCount() swmm_getLidUParam() swmm_setLidUParam() @@ -79,8 +89,10 @@ swmm_setLidCParam() swmm_getLidGResult() ### Rain Gages + swmm_getGagePrecip() swmm_setGagePrecip() ### Utility + swmm_getVersionInfo() diff --git a/docs/AUTHORS.dox b/docs/AUTHORS.dox index e3e80e375..8e608a884 100644 --- a/docs/AUTHORS.dox +++ b/docs/AUTHORS.dox @@ -1,21 +1,9 @@ -/** +/** @defgroup AUTHORS Authors at Open Water Analytics -The OWA-SWMM project builds on top of the contributions put forward by Lew Rossman with his original work on delivering EPA-SWMM5. We are grateful for all the work that has been put into SWMM5 and we are committed to delivering advances to the engine in a community driven approach. +The OWA-SWMM project builds on top of the contributions put forward by Lew Rossman with his original work on delivering EPA-SWMM5. We are grateful for all the work that has been put into SWMM5 and we are committed to delivering advances to the engine in a community driven approach. -- Lewis Rossman * -- Robert Dickinson * -- Michael Tryby * -- Bryant E. McDonnell -- Adam Erispaha -- Sam Hatchett -- Gonzalo Peña-Castellanos -- Katherine Ratliff * -- Abhiram Mullapudi -- Jennifer Wu -- Hsi-Nien Tan - -Authors ordered by first contribution. Author contributions are made under the @subpage MIT-License, except for authors whose contributions are made in the public domain, who are denoted with *. +The following link provides a list of all contributors as well as their types of contributions [CONTRIBUTORS](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/CONTRIBUTORS) Stand on the shoulders of Giants! For a list of all the contributors over time (SWMM5 and before), please see [Acknowledgements](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/wiki/Acknowledgements) -*/ \ No newline at end of file +*/ diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index f413b5f13..98d6e6ba4 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -31,7 +31,7 @@ set(DOXY_SOURCES set(DOXYGEN_PROJECT_NAME "OWA-SWMM Toolkit") -set(DOXYGEN_PROJECT_NUMBER "5.2") +set(DOXYGEN_PROJECT_NUMBER "5.1.14") set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C "YES") set(DOXYGEN_HIDE_SCOPE_NAMES "YES") set(DOXYGEN_SHOW_INCLUDE_FILES "NO") diff --git a/extern/boost.cmake b/extern/boost.cmake index 4f9c10aaa..839df22ec 100644 --- a/extern/boost.cmake +++ b/extern/boost.cmake @@ -7,6 +7,10 @@ # Author: Michael E. Tryby # US EPA - ORD/CESER # +# Usage: +# Create environment variable with the following pattern -- "BOOST_ROOT_X_XX_X" +# where Xs are the Boost version -- pointing to install location. +# if(WIN32) @@ -17,8 +21,14 @@ else() endif() -# Environment variable "BOOST_ROOT_X_XX_X" points to local install location -if (DEFINED ENV{BOOST_ROOT_1_72_0}) +# ADD NEW BOOST LIBRARIES VERSIONS HERE +if (DEFINED ENV{BOOST_ROOT_1_76_0}) + set(BOOST_ROOT $ENV{BOOST_ROOT_1_76_0}) + +elseif (DEFINED ENV{BOOST_ROOT_1_74_0}) + set(BOOST_ROOT $ENV{BOOST_ROOT_1_74_0}) + +elseif (DEFINED ENV{BOOST_ROOT_1_72_0}) set(BOOST_ROOT $ENV{BOOST_ROOT_1_72_0}) elseif(DEFINED ENV{BOOST_ROOT_1_67_0}) @@ -27,9 +37,11 @@ elseif(DEFINED ENV{BOOST_ROOT_1_67_0}) endif() +set(CMAKE_FIND_DEBUG_MODE FALSE) find_package(Boost 1.67.0 COMPONENTS unit_test_framework ) +set(CMAKE_FIND_DEBUG_MODE FALSE) include_directories (${Boost_INCLUDE_DIRS}) diff --git a/extern/version.cmake b/extern/version.cmake new file mode 100644 index 000000000..202d59963 --- /dev/null +++ b/extern/version.cmake @@ -0,0 +1,43 @@ +# +# version.cmake - generate SWMM version information header +# +# Created: November 2, 2021 +# Updated: +# +# Author: see CONTRIBUTORS +# +# Usage: +# GEN_VER_HEADER=ON -- overwrites version.h file with current info +# + + +option(GEN_VER_HEADER "Automatically update version header" ON) + +if(GEN_VER_HEADER) + + # Get the latest commit hash for the working branch + execute_process( + COMMAND + git rev-parse HEAD + WORKING_DIRECTORY + ${CMAKE_CURRENT_LIST_DIR} + OUTPUT_VARIABLE + GIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # Generate a build id + string( + TIMESTAMP BUILD_ID UTC + ) + + # Configure the version header + configure_file( + ../../extern/version.h.in version.h + ) + + file(COPY ${CMAKE_CURRENT_BINARY_DIR}/version.h + DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/ + ) + +endif() diff --git a/extern/version.h.in b/extern/version.h.in new file mode 100644 index 000000000..6fcc6a895 --- /dev/null +++ b/extern/version.h.in @@ -0,0 +1,39 @@ +/* + * version.h - SWMM version header file + * + * Created on: Nov 2, 2021 + * + * Author: see CONTRIBUTORS + * + * Note: + * The cmake build process automatically generates this file. Do not edit. + */ + + +#ifndef VERSION_H_ +#define VERSION_H_ + + + +#define PROJECT "SWMM" +#define ORGANIZATION "Open_Water_Analytics" + +#define VERSION "@swmm-solver_VERSION@" +#define VERSION_MAJOR @swmm-solver_VERSION_MAJOR@ +#define VERSION_MINOR @swmm-solver_VERSION_MINOR@ +#define VERSION_PATCH @swmm-solver_VERSION_PATCH@ +#define GIT_HASH "@GIT_HASH@" + +#define PLATFORM "@CMAKE_SYSTEM_NAME@" +#define COMPILER "@CMAKE_C_COMPILER_ID@" +#define COMPILER_VERSION "@CMAKE_C_COMPILER_VERSION@" +#define BUILD_ID "@BUILD_ID@" + + +static inline int get_version_legacy() { \ + return VERSION_MAJOR * 10000 + VERSION_MINOR * 1000 + VERSION_PATCH; \ +} + + + +#endif /* VERSION_H_ */ diff --git a/src/outfile/CMakeLists.txt b/src/outfile/CMakeLists.txt index 914eadadc..11b7e5ce8 100644 --- a/src/outfile/CMakeLists.txt +++ b/src/outfile/CMakeLists.txt @@ -2,9 +2,11 @@ # CMakeLists.txt - CMake configuration file for swmm/outfile # # Created: July 11, 2019 +# Updated: Jan 14, 2021 # # Author: Michael E. Tryby # US EPA ORD/CESER +# # # configure file groups @@ -16,8 +18,7 @@ set(SWMM_OUT_PUBLIC_HEADERS # the binary output file API -add_library(swmm-output - SHARED +add_library(swmm-output swmm_output.c errormanager.c ) @@ -41,6 +42,16 @@ file(COPY ${CMAKE_CURRENT_BINARY_DIR}/swmm_output_export.h ) +set_target_properties(swmm-output + PROPERTIES + MACOSX_RPATH TRUE + SKIP_BUILD_RPATH FALSE + BUILD_WITH_INSTALL_RPATH FALSE + INSTALL_RPATH "${PACKAGE_RPATH}" + INSTALL_RPATH_USE_LINK_PATH TRUE +) + + install(TARGETS swmm-output EXPORT swmm-outputTargets diff --git a/src/outfile/include/swmm_output.h b/src/outfile/include/swmm_output.h index 3c57ad29e..fbaa394e9 100644 --- a/src/outfile/include/swmm_output.h +++ b/src/outfile/include/swmm_output.h @@ -12,6 +12,8 @@ #ifndef SWMM_OUTPUT_H_ #define SWMM_OUTPUT_H_ + + #define MAXFILENAME 259 // Max characters in file path #define MAXELENAME 31 // Max characters in element name @@ -26,6 +28,7 @@ typedef struct Handle *SMO_Handle; extern "C" { #endif + int EXPORT_OUT_API SMO_init(SMO_Handle *p_handle); int EXPORT_OUT_API SMO_close(SMO_Handle p_handle); int EXPORT_OUT_API SMO_open(SMO_Handle p_handle, const char *path); @@ -56,8 +59,11 @@ void EXPORT_OUT_API SMO_freeMemory(void *array); void EXPORT_OUT_API SMO_clearError(SMO_Handle p_handle_in); int EXPORT_OUT_API SMO_checkError(SMO_Handle p_handle_in, char **msg_buffer); + #ifdef __cplusplus } #endif + + #endif /* SWMM_OUTPUT_H_ */ diff --git a/src/outfile/include/swmm_output_enums.h b/src/outfile/include/swmm_output_enums.h index 15d574eca..e4ab35bf9 100644 --- a/src/outfile/include/swmm_output_enums.h +++ b/src/outfile/include/swmm_output_enums.h @@ -2,9 +2,11 @@ * swmm_output_enums.h * * Created on: October 18, 2019 + * Updated on: January 14, 2020 * * Author: Michael E. Tryby * US EPA - ORD/CESER + * */ @@ -91,8 +93,8 @@ typedef enum { SMO_flood_losses, // (flow units), SMO_outfall_flows, // (flow units), SMO_volume_stored, // (ft3 or m3), - SMO_evap_rate // (in/day or mm/day), - //p_evap_rate // (in/day or mm/day) + SMO_evap_rate, // (in/day or mm/day), + SMO_p_evap_rate // (in/day or mm/day) } SMO_systemAttribute; diff --git a/src/outfile/swmm_output.c b/src/outfile/swmm_output.c index 4b7c3b33f..57fa847d6 100644 --- a/src/outfile/swmm_output.c +++ b/src/outfile/swmm_output.c @@ -44,7 +44,6 @@ struct IDentry { }; typedef struct IDentry idEntry; - //----------------------------------------------------------------------------- // Shared variables //----------------------------------------------------------------------------- @@ -101,7 +100,6 @@ float *newFloatArray(int n); int *newIntArray(int n); char *newCharArray(int n); - int EXPORT_OUT_API SMO_init(SMO_Handle *p_handle) // Purpose: Initialized pointer for the opaque SMO_Handle. // @@ -717,7 +715,7 @@ int EXPORT_OUT_API SMO_getSystemAttribute(SMO_Handle p_handle, int periodIndex, // { int errorcode = 0; - float temp; + float *temp; data_t *p_data; p_data = (data_t *)p_handle; @@ -726,11 +724,13 @@ int EXPORT_OUT_API SMO_getSystemAttribute(SMO_Handle p_handle, int periodIndex, errorcode = -1; else if (periodIndex < 0 || periodIndex >= p_data->Nperiods) errorcode = 422; + else if + MEMCHECK(temp = newFloatArray(1)) errorcode = 411; else { // don't need to loop since there's only one system - temp = getSystemValue(p_data, periodIndex, attr); + temp[0] = getSystemValue(p_data, periodIndex, attr); - *outValueArray = &temp; + *outValueArray = temp; *length = 1; } diff --git a/src/run/CMakeLists.txt b/src/run/CMakeLists.txt index f203e386c..28325ba82 100644 --- a/src/run/CMakeLists.txt +++ b/src/run/CMakeLists.txt @@ -2,6 +2,7 @@ # CMakeLists.txt - CMake configuration file for swmm-solver/run # # Created: July 11, 2019 +# Updated: Jan 14, 2021 # # Modified by: Michael E. Tryby # US EPA ORD/NRMRL diff --git a/src/run/main.c b/src/run/main.c index 8eefd3ac1..dee6418d2 100644 --- a/src/run/main.c +++ b/src/run/main.c @@ -1,16 +1,14 @@ /* - * main.c - Main stub for the command line version of EPA SWMM 5.1 - * - * Created on: October 9, 2020 - * Updated on: - * - * Author: Michael E. Tryby - * US EPA - ORD/CESER - * - */ - -// System includes + * main.c - Main stub for the command line version of EPA SWMM 5.1 + * + * Created on: October 9, 2020 + * Updated on: + * + * Author: See CONTRIBUTORS + */ + #include +#include #include #include @@ -25,6 +23,19 @@ #define BAR_LEN 50l #define MSG_LEN 84 +#define FMT_USAGE \ +"\nUsage:\n \ + \trunswmm \n\n" + +#define FMT_HELP \ +"\n\nOWA Stormwater Management Model (SWMM5) Help\n\n \ + Commands:\n \ + \t--help (-h) Help Docs\n \ + \t--version (-v) Build Version\n \ + \nUsage:\n \ + \t swmm5 \n\n" + + static long Start; @@ -76,9 +87,7 @@ int main(int argc, char *argv[]) // f3 = name of binary output file if saved (or blank if not saved). // { - // --- check for proper number of command line arguments if (argc == 4) { - // --- extract file names from command line arguments char *inputFile = argv[1]; char *reportFile = argv[2]; @@ -87,13 +96,12 @@ int main(int argc, char *argv[]) binaryFile = argv[3]; Start = current_time_millis(); - // --- run SWMM swmm_run_cb(inputFile, reportFile, binaryFile, &progress_bar); long stop = current_time_millis(); char time[TIMER_LEN + 1] = {'\0'}; - printf("\n\n... EPA-SWMM completed in %s", format_time(time, stop - Start)); + printf("\n\n... SWMM completed in %s", format_time(time, stop - Start)); char errMsg[128]; int msgLen = 127; @@ -109,37 +117,26 @@ int main(int argc, char *argv[]) } else if (argc == 2) { - // --- extract first argument char *arg1 = argv[1]; - if (strcmp(arg1, "--help") == 0 || strcmp(arg1, "-h") == 0) { - // Help - printf("\n\nEPA Stormwater Management Model (SWMM5) Help\n\n"); - printf("Commands:\n"); - printf("\t--help (-h) Help Docs\n"); - printf("\t--version (-v) Build Version\n"); - printf("\nUsage:\n"); - printf("\t swmm5 \n\n"); - } - else if (strcmp(arg1, "--version") == 0 || strcmp(arg1, "-v") == 0) { - int version = swmm_getVersion(); - int vMajor = version / 10000; - int vMinor = (version - 10000 * vMajor) / 1000; - int vRelease = (version - 10000 * vMajor - 1000 * vMinor); + if (strcmp(arg1, "--help") == 0 || strcmp(arg1, "-h") == 0) + printf(FMT_HELP); - // Output version number + else if (strcmp(arg1, "--version") == 0 || strcmp(arg1, "-v") == 0) { printf("\nVersion:\n"); - printf("\tEPA-SWMM %d.%d.%0d\n\n", vMajor, vMinor, vRelease); + printf("\tOWA-SWMM v%s (Build %.10s)\n\n", swmm_getSemVersion(), + swmm_getBuildId()); } + else { printf("\nError:\n"); printf("\tUnknown Argument (See Help --help)\n\n"); } } + else { - printf("\nUsage:\n"); - printf("\trunswmm \n\n"); + printf(FMT_USAGE); } return 0; -} +} \ No newline at end of file diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index b3f344107..e10fa4a9a 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -14,6 +14,9 @@ find_package(OpenMP C ) +# Generate version header +include(../../extern/version.cmake) + # configure file groups set(SWMM_PUBLIC_HEADERS @@ -28,29 +31,29 @@ file(GLOB RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.c *.h ) + if(BUILD_DEF) - # Build library with def file interface for backward compatibility + # Builds library with def file interface for backward compatibility set_source_files_properties(${PROJECT_SOURCE_DIR}/bindings/swmm5.def PROPERTIES_HEADER_FILE_ONLY TRUE ) - add_library(swmm5 - SHARED + add_library(swmm5 ${SWMM_SOURCES} ${PROJECT_SOURCE_DIR/bindings/swmm5.def} $ ) else() - - add_library(swmm5 - SHARED + # Performs standard library build + add_library(swmm5 ${SWMM_SOURCES} $ ) endif() +# Sets MSVC compiler flags target_compile_options(swmm5 PUBLIC "$<$:" @@ -85,6 +88,29 @@ target_include_directories(swmm5 ${CMAKE_CURRENT_SOURCE_DIR}/.. ) +include(GenerateExportHeader) +generate_export_header(swmm5 + BASE_NAME toolkit + EXPORT_MACRO_NAME EXPORT_TOOLKIT + EXPORT_FILE_NAME toolkit_export.h + STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC +) + +file(COPY ${CMAKE_CURRENT_BINARY_DIR}/toolkit_export.h + DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/include +) + + +set_target_properties(swmm5 + PROPERTIES + MACOSX_RPATH TRUE + SKIP_BUILD_RPATH FALSE + BUILD_WITH_INSTALL_RPATH FALSE + INSTALL_RPATH "${PACKAGE_RPATH}" + INSTALL_RPATH_USE_LINK_PATH TRUE +) + + install(TARGETS swmm5 EXPORT swmm5Targets RUNTIME DESTINATION "${TOOL_DIST}" LIBRARY DESTINATION "${LIBRARY_DIST}" diff --git a/src/solver/Roadmap.txt b/src/solver/Roadmap.txt new file mode 100644 index 000000000..11952fad7 --- /dev/null +++ b/src/solver/Roadmap.txt @@ -0,0 +1,189 @@ +A Roadmap to the SWMM 5 Engine Source Code +========================================== + +The SWMM 5 computational engine consists of 49 C-code files plus several +header files. The engine can be compiled either as a Dynamic Link Library +(DLL) under Windows or as a stand-alone console application under both +Windows and Linux, depending on which of the #define DLL and #define CLE +declarations at the top of swmm5.c is commented out. + +The following header files contain definitions that are used throughout the +code and should be consulted if the meaning of a variable, a data structure, +or a constant is unclear: + +enums.h defines various enumerated (symbolic) constants. + +objects.h defines the major classes of data objects used by SWMM 5. + +consts.h defines useful numerical constants. + +text.h defines various text strings used throughout the code. + +macros.h defines several macros used throughout the code. + +globals.h declares global variables that are referenced in many + SWMM 5 code modules. + +funcs.h contains prototypes of functions that can be called from any + module of SWMM 5 that #includes funcs.h. + +-------------------------------------------------------------------------- + +The following modules form the main core of the SWMM 5 engine: + +swmm5.c contains functions that provide supervisory control over the + program. + +project.c contains functions that create and destroy all project data, + establish default values, and look up objects by ID name. + +input.c reads a project's data from an input file. + +runoff.c computes runoff quantity and quality from the project's + subcatchments. + +routing.c routes runoff and external inflows through the project's + drainage system network of nodes and links. + +massbal.c performs mass balance calculations for runoff and routing. + +stats.c collects summary statistics on flow rates, water depths, + solution iterations, and variable time steps for a + simulation. + +statsrpt.c writes summary simulation results to a status report. + +output.c writes/reads runoff and routing results to/from a binary + output file. + +report.c prepares a status report of simulation results and, for the + command line version of SWMM 5, reports complete results for + selected subcatchments, nodes, and links. + +inputrpt.c writes a summary of a project's input data to the status report. + +------------------------------------------------------------------------------- + +The following collection of modules are used to perform runoff calculations: + +rain.c places data from external rainfall files into a single rainfall + interface file. + +gage.c provides rainfall data, either from an interface file or from an + internal time series, for runoff calculations. + +climate.c provides temperature, evaporation, and wind speed data to the + simulation. + +snow.c computes snow fall accumulation, snow removal operations, and + snow melt for a project's subcatchments. + +infil.c performs infiltration calculations on a project's subcatchments. + +gwater.c computes groundwater fluxes and updates groundwater depths over + the project's study area. + +subcatch.c computes rainfall runoff, pollutant buildup and washoff, and + street sweeping over individual subcatchments. + +landuse.c evaluates pollutant buildup and washoff functions for a project's + various types of land uses. + +lid.c evaluates the hydrologic performance of Low Impact Development + practices utilized within subcatchment areas. + +lidproc.c computes the hydrologic performance of individual LID units. + +------------------------------------------------------------------------------- + +These modules are used for flow and water quality routing: + +flowrout.c implements top-level control of flow routing through a project's + drainage network. + +inflow.c provides direct time series inflows and recurring dry weather + inflows to the drainage system's nodes at each step of the + simulation. + +rdii.c computes rainfall dependent infiltration/inflow at selected nodes + of the drainage network. + +kinwave.c performs kinematic wave flow routing calculations at each time + step of the simulation. + +dynwave.c performs dynamic wave flow routing calculations at each time + step of the simulation + +dwflow.c solves the dynamic wave flow continuity and momentum equations in + a single conduit over a single time step. + +controls.c implements rule-based control actions on pumps and regulators + as the simulation unfolds. + +qualrout.c performs routing of water quality constituents through the + study area's drainage system. + +treatmnt.c computes pollutant removal at specific nodes of the drainage + system where user-defined treatment functions have been + assigned. + +node.c contains functions used to compute the properties and behavior + of the drainage system's nodes which include junctions, flow + dividers, storage units, and outfalls. + +link.c contains functions used to compute the properties and behavior + of the drainage system's links which include conduits, pumps, + orifices, weirs, and outlets. + +forcmain.c computes friction losses in force mains that use either the + Hazen-Williams or Darcy-Weisbach equations in place of the + Manning equation for pressurized flow. + +culvert.c computes flow reduction in culvert-type conduits due to + inlet control using equations from the FHWA HEC-5 circular. + +------------------------------------------------------------------------------- + +The following modules provide various support functions for SWMM 5: + +datetime.c functions for manipulating dates and times. + +error.c error reporting functions. + +findroot.c equation root finding functions. + +hash.c functions that implement hash tables for fast object retrieval. + +hotstart.c saves or reads the state of the drainage system to or from a + hot start file. + +iface.c functions for reading from and writing to routing interface + files. + +keywords.c defines lists of keywords that appear as part of a SWMM 5 + input file. + +mathexpr.c functions that parse and evaluate user-supplied mathematical + expressions for pollutant removal at treatment nodes. + +mempool.c functions that provide a memory pool used to store object + ID names. + +odesolve.c implementation of a fifth-order Runge-Kutta ordinary + differential equation solver. + +shape.c functions that compute the geometric cross-section properties + of closed conduits with user-defined shapes. + +table.c functions used for accessing lookup tables that contain + SWMM 5's curve data and time series data. + +toposort.c functions used to topologically sort the links of a drainage + network and detect any closed cyclic loops. + +transect.c functions that create geometric tables for irregular shaped + cross section transects. + +xsect.c functions that compute geometric properties of conduit cross + sections. + \ No newline at end of file diff --git a/src/solver/swmm5.def b/src/solver/bindings/swmm5.def similarity index 100% rename from src/solver/swmm5.def rename to src/solver/bindings/swmm5.def diff --git a/src/solver/consts.h b/src/solver/consts.h index 6df094e7a..62bf52747 100644 --- a/src/solver/consts.h +++ b/src/solver/consts.h @@ -6,6 +6,7 @@ // Date: 03/20/14 (Build 5.1.001) // 08/01/16 (Build 5.1.011) // 05/10/18 (Build 5.1.013) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman // // Various Constants @@ -14,14 +15,6 @@ //------------------ // General Constants //------------------ - -// Update VERSION and SEMVERSION Simultaneously -#define VERSION 51013 // Eventually will be deprecated. -#define SEMVERSION_MAJOR "5" // Major Semantic Version -#define SEMVERSION_MINOR "1" // Minor Semantic Version -#define SEMVERSION_PATCH "13" // Patch Semantic Version -#define SEMVERSION_LEN 20 // Version String Len - #define MAGICNUMBER 516114522 #define EOFMARK 0x1A // Use 0x04 for UNIX systems #define MAXTITLE 3 // Max. # title lines diff --git a/src/solver/dwflow.c b/src/solver/dwflow.c index 420a6898d..de096ad38 100644 --- a/src/solver/dwflow.c +++ b/src/solver/dwflow.c @@ -7,6 +7,7 @@ // 03/19/15 (Build 5.1.008) // 03/14/17 (Build 5.1.012) // 05/10/18 (Build 5.1.013) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman (EPA) // M. Tryby (EPA) // R. Dickinson (CDM) @@ -23,6 +24,11 @@ // Build 5.1.013: // - Preissmann slot surcharge option implemented. // - Changed sign of uniform loss rate term (dq6) in flow updating equation. +// +// Build 5.1.014: +// - Conduit evap. and seepage loss initialized to 0 in dwflow_findConduitFlow. +// - Most current flow (qLast) used instead of previous time period flow +// (qOld) in call to link_getLossRate. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -96,6 +102,8 @@ void dwflow_findConduitFlow(int j, int steps, double omega, double dt) barrels = Conduit[k].barrels; qOld = Link[j].oldFlow / barrels; qLast = Conduit[k].q1; + Conduit[k].evapLossRate = 0.0; //(5.1.014) + Conduit[k].seepLossRate = 0.0; //(5.1.014) // --- get most current heads at upstream and downstream ends of conduit n1 = Link[j].node1; @@ -226,7 +234,7 @@ void dwflow_findConduitFlow(int j, int steps, double omega, double dt) } // --- 6. term for evap and seepage losses per unit length - dq6 = link_getLossRate(j, qOld, dt) * 2.5 * dt * v / link_getLength(j); + dq6 = link_getLossRate(j, qLast) * 2.5 * dt * v / link_getLength(j); //(5.1.014) // --- combine terms to find new conduit flow denom = 1.0 + dq1 + dq5; diff --git a/src/solver/dynwave.c b/src/solver/dynwave.c index 40b6a71a6..294adc873 100644 --- a/src/solver/dynwave.c +++ b/src/solver/dynwave.c @@ -45,6 +45,10 @@ // - Storage nodes allowed to pressurize if their surcharge depth > 0. // - Minimum flow needed to compute a Courant time step modified. // +// Build 5.1.014: +// - updateNodeFlows() modified to subtract conduit evap. and seepage losses +// from downstream node inflow instead of upstream node outflow. +// //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -541,18 +545,19 @@ void updateNodeFlows(int i) k = Link[i].subIndex; uniformLossRate = Conduit[k].evapLossRate + Conduit[k].seepLossRate; barrels = Conduit[k].barrels; + uniformLossRate *= barrels; //(5.1.014) } // --- update total inflow & outflow at upstream/downstream nodes if ( q >= 0.0 ) { - Node[n1].outflow += q + uniformLossRate; - Node[n2].inflow += q; + Node[n1].outflow += q; //(5.1.014) + Node[n2].inflow += q - uniformLossRate; //(5.1.014) } else { - Node[n1].inflow -= q; - Node[n2].outflow -= q - uniformLossRate; + Node[n1].inflow -= q + uniformLossRate; //(5.1.014) + Node[n2].outflow -= q; //(5.1.014) } // --- add surf. area contributions to upstream/downstream nodes diff --git a/src/solver/flowrout.c b/src/solver/flowrout.c index 7b2503d40..b50b12787 100644 --- a/src/solver/flowrout.c +++ b/src/solver/flowrout.c @@ -7,6 +7,7 @@ // 09/15/14 (Build 5.1.007) // 03/19/15 (Build 5.1.008) // 03/14/17 (Build 5.1.012) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman (EPA) // M. Tryby (EPA) // @@ -25,6 +26,9 @@ // - Overflow computed in updateStorageState() must be non-negative. // - Terminal storage nodes now updated corectly. // +// Build 5.1.014: +// - Arguments to function link_getLossRate changed. +// //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -766,7 +770,7 @@ int steadyflow_execute(int j, double* qin, double* qout, double tStep) else { // --- adjust flow for evap and infil losses - q -= link_getLossRate(j, q, tStep); + q -= link_getLossRate(j, q); //(5.1.014) // --- flow can't exceed full flow if ( q > Link[j].qFull ) diff --git a/src/solver/funcs.h b/src/solver/funcs.h index ce480964e..4199e54c3 100644 --- a/src/solver/funcs.h +++ b/src/solver/funcs.h @@ -8,6 +8,7 @@ // 04/02/15 (Build 5.1.008) // 08/05/15 (Build 5.1.010) // 05/10/18 (Build 5.1.013) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman (EPA) // M. Tryby (EPA) // @@ -27,6 +28,9 @@ // Build 5.1.013: // - Additional arguments added to function stats_updateSubcatchStats. // +// Build 5.1.014: +// - Arguments to link_getLossRate function changed. +// //----------------------------------------------------------------------------- void project_open(char *f1, char *f2, char *f3); @@ -336,9 +340,7 @@ void node_initState(int node); void node_initInflow(int node, double tStep); void node_setOldHydState(int node); void node_setOldQualState(int node); - void node_setOutletDepth(int node, double yNorm, double yCrit, double z); -void node_setDividerCutoff(int node, int link); double node_getSurfArea(int node, double depth); double node_getDepth(int node, double volume); @@ -415,7 +417,7 @@ double link_getYnorm(int link, double q); double link_getVelocity(int link, double q, double y); double link_getFroude(int link, double v, double y); double link_getPower(int link); -double link_getLossRate(int link, double q, double tStep); +double link_getLossRate(int link, double q); //(5.1.014) char link_getFullState(double a1, double a2, double aFull); void link_getResults(int link, double wt, float x[]); @@ -519,4 +521,3 @@ void writecon(char *s); // writes string to console DateTime getDateTime(double elapsedMsec); // convert elapsed time to date void getElapsedTime(DateTime aDate, // convert elapsed date int* days, int* hrs, int* mins); -void getSemVersion(char* semver); // get semantic version diff --git a/src/solver/globals.h b/src/solver/globals.h index 1d7c9207e..b3d2ca403 100644 --- a/src/solver/globals.h +++ b/src/solver/globals.h @@ -97,7 +97,8 @@ EXTERN int SweepEnd, // Day of year when sweeping ends MaxTrials, // Max. trials for DW routing NumThreads, // Number of parallel threads used - NumEvents; // Number of detailed events + NumEvents, // Number of detailed events + ExtPollutFlag; // Enable external pollutant injection //InSteadyState; // System flows remain constant EXTERN double diff --git a/src/solver/include/swmm5.h b/src/solver/include/swmm5.h index 906332005..7753a0553 100644 --- a/src/solver/include/swmm5.h +++ b/src/solver/include/swmm5.h @@ -1,14 +1,15 @@ -/** @file swmm5.h - @see http://github.com/openwateranalytics/stormwater-management-model - - swmm5.h - @brief Prototypes for SWMM5 functions exported to swmm5.dll. - @date 03/24/14 (Build 5.1.001) - @date 08/01/16 (Build 5.1.011) - @version 5.1 - @authors L. Rossman, OpenWaterAnalytics members: - see AUTHORS. -*/ +//----------------------------------------------------------------------------- +// swmm5.h +// +// Project: EPA SWMM5 +// Version: 5.1 +// Date: 03/24/14 (Build 5.1.001) +// 08/01/16 (Build 5.1.011) +// Author: L. Rossman +// +// Prototypes for SWMM5 functions exported to swmm5.dll. +// +//----------------------------------------------------------------------------- #ifndef SWMM5_H #define SWMM5_H @@ -51,10 +52,10 @@ int swmm_IsStartedFlag(void); // --- use "C" linkage for C++ programs -#ifdef __cplusplus -extern "C" { -#endif +#ifdef __cplusplus +extern "C" { +#endif /** @brief Opens SWMM input file, reads in network data, runs, and closes @@ -116,8 +117,8 @@ int DLLEXPORT swmm_getMassBalErr(float* runoffErr, float* flowErr, float* qualEr int DLLEXPORT swmm_close(void); /** - @brief Get Legacy SWMM version number - @return Version + @brief Get SWMM version number + @return Version as integer */ int DLLEXPORT swmm_getVersion(void); @@ -126,9 +127,8 @@ int DLLEXPORT swmm_getError(char* errMsg, int msgLen); int DLLEXPORT swmm_getWarnings(void); - -#ifdef __cplusplus -} // matches the linkage specification from above */ +#ifdef __cplusplus +} // matches the linkage specification from above */ #endif #endif diff --git a/src/solver/include/toolkit.h b/src/solver/include/toolkit.h index 6861f64b0..7a0bdf250 100644 --- a/src/solver/include/toolkit.h +++ b/src/solver/include/toolkit.h @@ -1,51 +1,46 @@ -/** @file toolkit.h - @see http://github.com/openwateranalytics/stormwater-management-model - - toolkit.h - @brief Exportable Functions for Toolkit API. - @date 08/30/2016 (First Contribution) - @authors B. McDonnell (EmNet LLC), OpenWaterAnalytics members: see AUTHORS. +/* + * toolkit.h - OWA SWMM Toolkit API + * + * Created on: Aug 30, 2016 + * Updated on: + * + * Author: See CONTRIBUTORS + * + * Note: + * Originally developed by Bryant McDonnell + */ +#ifndef TOOLKIT_H +#define TOOLKIT_H -*/ -#ifndef TOOLKITAPI_H -#define TOOLKITAPI_H -#ifdef WINDOWS -#ifdef __MINGW32__ -#define DLLEXPORT __declspec(dllexport) __cdecl -#else -#define DLLEXPORT __declspec(dllexport) __stdcall -#endif -#else -#define DLLEXPORT -#endif - -#ifdef __cplusplus -extern "C" { -#endif #define _CRT_SECURE_NO_DEPRECATE - #include "toolkit_enums.h" #include "toolkit_structs.h" +#include "toolkit_export.h" -// /** -// @brief Get full semantic version number -// @param[out] semver sematic version (char array) -// */ -// void DLLEXPORT swmm_getSemVersion(char* semver); +#ifdef __cplusplus +extern "C" { +#endif + /** - @brief Get full semantic version number info - @param[out] major sematic version major number - @param[out] minor sematic version minor number - @param[out] patch sematic version patch number - @return error code + @brief Get full semantic version number + @param[out] Pointer to version number string + @returns error code */ -int DLLEXPORT swmm_getVersionInfo(char **major, char **minor, char **patch); +EXPORT_TOOLKIT const char *swmm_getSemVersion(); + +/** + @brief Get Build Id + @param[out] Pointer to build id string + @returns error code +*/ +EXPORT_TOOLKIT const char *swmm_getBuildId(); + /** @brief Opens SWMM input file, reads in network data, runs, and closes @@ -55,7 +50,7 @@ int DLLEXPORT swmm_getVersionInfo(char **major, char **minor, char **patch); @param pointer to callback function (for printing progress) @return error code */ -int DLLEXPORT swmm_run_cb(const char *f1, const char *f2, const char *f3, +EXPORT_TOOLKIT int swmm_run_cb(const char *f1, const char *f2, const char *f3, void (*callback) (double *)); /** @@ -64,7 +59,7 @@ int DLLEXPORT swmm_run_cb(const char *f1, const char *f2, const char *f3, @param[out] errorMsg The error string represented by the code @return Error code */ -int DLLEXPORT swmm_getAPIError(int errorCode, char **errorMsg); +EXPORT_TOOLKIT int swmm_getAPIError(int errorCode, char **errorMsg); /** @brief Finds the index of an object given its ID. @@ -73,7 +68,7 @@ int DLLEXPORT swmm_getAPIError(int errorCode, char **errorMsg); @param[out] index The objects index @return Error code */ -int DLLEXPORT swmm_project_findObject(SM_ObjectType type, char *id, int *index); +EXPORT_TOOLKIT int swmm_project_findObject(SM_ObjectType type, char *id, int *index); /** @brief Gets Simulation Unit @@ -81,7 +76,7 @@ int DLLEXPORT swmm_project_findObject(SM_ObjectType type, char *id, int *index); @param[out] value Option value @return Error code */ -int DLLEXPORT swmm_getSimulationUnit(SM_Units type, int *value); +EXPORT_TOOLKIT int swmm_getSimulationUnit(SM_Units type, int *value); /** @brief Gets Simulation Analysis Setting @@ -89,7 +84,7 @@ int DLLEXPORT swmm_getSimulationUnit(SM_Units type, int *value); @param[out] value Option value @return Error code */ -int DLLEXPORT swmm_getSimulationAnalysisSetting(SM_SimOption type, int *value); +EXPORT_TOOLKIT int swmm_getSimulationAnalysisSetting(SM_SimOption type, int *value); /** @brief Gets Simulation Analysis Setting @@ -97,7 +92,7 @@ int DLLEXPORT swmm_getSimulationAnalysisSetting(SM_SimOption type, int *value); @param[out] value Option value @return Error code */ -int DLLEXPORT swmm_getSimulationParam(SM_SimSetting type, double *value); +EXPORT_TOOLKIT int swmm_getSimulationParam(SM_SimSetting type, double *value); /** @brief Gets Object Count @@ -105,7 +100,7 @@ int DLLEXPORT swmm_getSimulationParam(SM_SimSetting type, double *value); @param[out] count Option value @return Error code */ -int DLLEXPORT swmm_countObjects(SM_ObjectType type, int *count); +EXPORT_TOOLKIT int swmm_countObjects(SM_ObjectType type, int *count); /** @brief Gets Object ID @@ -114,7 +109,7 @@ int DLLEXPORT swmm_countObjects(SM_ObjectType type, int *count); @param[out] id The string ID of object. @return Error code */ -int DLLEXPORT swmm_getObjectId(SM_ObjectType type, int index, char **id); +EXPORT_TOOLKIT int swmm_getObjectId(SM_ObjectType type, int index, char **id); /** @brief Gets Object Index @@ -123,7 +118,7 @@ int DLLEXPORT swmm_getObjectId(SM_ObjectType type, int index, char **id); @param[out] index of the Object @return errcode Error Code */ -int DLLEXPORT swmm_getObjectIndex(SM_ObjectType type, char *id, int *index); +EXPORT_TOOLKIT int swmm_getObjectIndex(SM_ObjectType type, char *id, int *index); /** @brief Get the type of node with specified index. @@ -132,7 +127,7 @@ int DLLEXPORT swmm_getObjectIndex(SM_ObjectType type, char *id, int *index); id must be pre-allocated by the caller. @return Error code */ -int DLLEXPORT swmm_getNodeType(int index, SM_NodeType *Ntype); +EXPORT_TOOLKIT int swmm_getNodeType(int index, SM_NodeType *Ntype); /** @brief Get the type of link with specified index. @@ -140,7 +135,7 @@ int DLLEXPORT swmm_getNodeType(int index, SM_NodeType *Ntype); @param[out] Ltype The type code for the link (@ref SM_LinkType). @return Error code */ -int DLLEXPORT swmm_getLinkType(int index, SM_LinkType *Ltype); +EXPORT_TOOLKIT int swmm_getLinkType(int index, SM_LinkType *Ltype); /** @brief Get the link Connection Node Indeces. If the conduit has a @@ -151,7 +146,7 @@ int DLLEXPORT swmm_getLinkType(int index, SM_LinkType *Ltype); @param[out] Node2 The downstream node index. @return Error code */ -int DLLEXPORT swmm_getLinkConnections(int index, int *node1, int *node2); +EXPORT_TOOLKIT int swmm_getLinkConnections(int index, int *node1, int *node2); /** @brief Get the link flow direction (see @ref swmm_getLinkType() for notes. @@ -159,7 +154,7 @@ int DLLEXPORT swmm_getLinkConnections(int index, int *node1, int *node2); @param[out] value The link flow direction. @return Error code */ -int DLLEXPORT swmm_getLinkDirection(int index, signed char *value); +EXPORT_TOOLKIT int swmm_getLinkDirection(int index, signed char *value); /** @brief Get the Subcatchment connection. Subcatchments can load to a @@ -169,7 +164,7 @@ int DLLEXPORT swmm_getLinkDirection(int index, signed char *value); @param[out] out_index The object index @return Error code */ -int DLLEXPORT swmm_getSubcatchOutConnection(int index, SM_ObjectType *type, int *out_index); +EXPORT_TOOLKIT int swmm_getSubcatchOutConnection(int index, SM_ObjectType *type, int *out_index); /** @brief Get the number of lid units on a subcatchment. @@ -177,7 +172,7 @@ int DLLEXPORT swmm_getSubcatchOutConnection(int index, SM_ObjectType *type, int @param[out] value The number of lid units on a subcatchment @return Error code */ -int DLLEXPORT swmm_getLidUCount(int index, int *value); +EXPORT_TOOLKIT int swmm_getLidUCount(int index, int *value); /** @brief Get a property value for a specified lid unit on a specified subcatchment @@ -187,7 +182,7 @@ int DLLEXPORT swmm_getLidUCount(int index, int *value); @param[out] value The value of the lid unit's property @return Error code */ -int DLLEXPORT swmm_getLidUParam(int index, int lidIndex, SM_LidUProperty param, double *value); +EXPORT_TOOLKIT int swmm_getLidUParam(int index, int lidIndex, SM_LidUProperty param, double *value); /** @brief Set a property value for a specified lid unit on a specified subcatchment @@ -197,7 +192,7 @@ int DLLEXPORT swmm_getLidUParam(int index, int lidIndex, SM_LidUProperty param, @param value The new value of the lid unit's property @return Error code */ -int DLLEXPORT swmm_setLidUParam(int index, int lidIndex, SM_LidUProperty param, double value); +EXPORT_TOOLKIT int swmm_setLidUParam(int index, int lidIndex, SM_LidUProperty param, double value); /** @brief Get the lid option for a specified lid unit on a specified subcatchment @@ -207,7 +202,7 @@ int DLLEXPORT swmm_setLidUParam(int index, int lidIndex, SM_LidUProperty param, @param[out] value The value of the option for the lid unit @return Error code */ -int DLLEXPORT swmm_getLidUOption(int index, int lidIndex, SM_LidUOptions param, int *value); +EXPORT_TOOLKIT int swmm_getLidUOption(int index, int lidIndex, SM_LidUOptions param, int *value); /** @brief Set the lid option for a specified lid unit on a specified subcatchment @@ -217,7 +212,7 @@ int DLLEXPORT swmm_getLidUOption(int index, int lidIndex, SM_LidUOptions param, @param value The new value of the option for the lid unit @return Error code */ -int DLLEXPORT swmm_setLidUOption(int index, int lidIndex, SM_LidUOptions param, int value); +EXPORT_TOOLKIT int swmm_setLidUOption(int index, int lidIndex, SM_LidUOptions param, int value); /** @brief Get the lid control surface immediate overflow condition @@ -225,7 +220,7 @@ int DLLEXPORT swmm_setLidUOption(int index, int lidIndex, SM_LidUOptions param, @param[out] condition The value of surface immediate overflow condition @return Error code */ -int DLLEXPORT swmm_getLidCOverflow(int lidControlIndex, int *condition); +EXPORT_TOOLKIT int swmm_getLidCOverflow(int lidControlIndex, int *condition); /** @brief Get a property value for specified lid control @@ -235,7 +230,7 @@ int DLLEXPORT swmm_getLidCOverflow(int lidControlIndex, int *condition); @param[out] value The value of lid control's property @return Error code */ -int DLLEXPORT swmm_getLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double *value); +EXPORT_TOOLKIT int swmm_getLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double *value); /** @brief Set a property value for specified lid control @@ -245,7 +240,7 @@ int DLLEXPORT swmm_getLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_ @param value The new value for the lid control's property @return Error code */ -int DLLEXPORT swmm_setLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double value); +EXPORT_TOOLKIT int swmm_setLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double value); /** @brief Get the lid unit water balance simulated value at current time @@ -256,7 +251,7 @@ int DLLEXPORT swmm_setLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_ @param[out] result The result for the specified lid unit @return Error code */ -int DLLEXPORT swmm_getLidUFluxRates(int index, int lidIndex, SM_LidLayer layerIndex, double *result); +EXPORT_TOOLKIT int swmm_getLidUFluxRates(int index, int lidIndex, SM_LidLayer layerIndex, double *result); /** @brief Get the lid group of a specified subcatchment result at current time @@ -265,7 +260,7 @@ int DLLEXPORT swmm_getLidUFluxRates(int index, int lidIndex, SM_LidLayer layerIn @param[out] result The result for the specified lid group @return Error code */ -int DLLEXPORT swmm_getLidGResult(int index, SM_LidResult type, double *result); +EXPORT_TOOLKIT int swmm_getLidGResult(int index, SM_LidResult type, double *result); /** @brief Get the lid unit of a specified subcatchment result at current time @@ -275,7 +270,7 @@ int DLLEXPORT swmm_getLidGResult(int index, SM_LidResult type, double *result); @param[out] result The result for the specified lid unit @return Error code */ -int DLLEXPORT swmm_getLidUResult(int index, int lidIndex, SM_LidResult type, double *result); +EXPORT_TOOLKIT int swmm_getLidUResult(int index, int lidIndex, SM_LidResult type, double *result); /** @brief Get a property value for specified node. @@ -284,7 +279,7 @@ int DLLEXPORT swmm_getLidUResult(int index, int lidIndex, SM_LidResult type, dou @param[out] value The value of the node's property @return Error code */ -int DLLEXPORT swmm_getNodeParam(int index, SM_NodeProperty param, double *value); +EXPORT_TOOLKIT int swmm_getNodeParam(int index, SM_NodeProperty param, double *value); /** @brief Set a property value for specified node. @@ -293,7 +288,7 @@ int DLLEXPORT swmm_getNodeParam(int index, SM_NodeProperty param, double *value) @param value The new value of the node's property @return Error code */ -int DLLEXPORT swmm_setNodeParam(int index, SM_NodeProperty param, double value); +EXPORT_TOOLKIT int swmm_setNodeParam(int index, SM_NodeProperty param, double value); /** @brief Get a property value for specified link. @@ -302,7 +297,7 @@ int DLLEXPORT swmm_setNodeParam(int index, SM_NodeProperty param, double value); @param[out] value The value of the link's property @return Error code */ -int DLLEXPORT swmm_getLinkParam(int index, SM_LinkProperty param, double *value); +EXPORT_TOOLKIT int swmm_getLinkParam(int index, SM_LinkProperty param, double *value); /** @brief Set a property value for specified link. @@ -311,7 +306,7 @@ int DLLEXPORT swmm_getLinkParam(int index, SM_LinkProperty param, double *value) @param value The new value of the link's property @return Error code */ -int DLLEXPORT swmm_setLinkParam(int index, SM_LinkProperty param, double value); +EXPORT_TOOLKIT int swmm_setLinkParam(int index, SM_LinkProperty param, double value); /** @brief Get a property value for specified subcatchment. @@ -320,7 +315,7 @@ int DLLEXPORT swmm_setLinkParam(int index, SM_LinkProperty param, double value); @param[out] value The value of the subcatchment's property @return Error code */ -int DLLEXPORT swmm_getSubcatchParam(int index, SM_SubcProperty param, double *value); +EXPORT_TOOLKIT int swmm_getSubcatchParam(int index, SM_SubcProperty param, double *value); /** @brief Set a property value for specified subcatchment. @@ -329,7 +324,7 @@ int DLLEXPORT swmm_getSubcatchParam(int index, SM_SubcProperty param, double *va @param value The new value of the subcatchment's property @return Error code */ -int DLLEXPORT swmm_setSubcatchParam(int index, SM_SubcProperty param, double value); +EXPORT_TOOLKIT int swmm_setSubcatchParam(int index, SM_SubcProperty param, double value); /** @brief Get the current simulation datetime information. @@ -342,7 +337,7 @@ int DLLEXPORT swmm_setSubcatchParam(int index, SM_SubcProperty param, double val @param[out] second The seconds @return Error code */ -int DLLEXPORT swmm_getSimulationDateTime(SM_TimePropety type, int *year, int *month, +EXPORT_TOOLKIT int swmm_getSimulationDateTime(SM_TimePropety type, int *year, int *month, int *day, int *hour, int *minute, int *second); @@ -357,7 +352,7 @@ int DLLEXPORT swmm_getSimulationDateTime(SM_TimePropety type, int *year, int *mo @param second The second @return Error code */ -int DLLEXPORT swmm_setSimulationDateTime(SM_TimePropety type, int year, int month, +EXPORT_TOOLKIT int swmm_setSimulationDateTime(SM_TimePropety type, int year, int month, int day, int hour, int minute, int second); @@ -371,7 +366,7 @@ int DLLEXPORT swmm_setSimulationDateTime(SM_TimePropety type, int year, int mont @param[out] second The seconds @return Error code */ -int DLLEXPORT swmm_getCurrentDateTime(int *year, int *month, int *day, +EXPORT_TOOLKIT int swmm_getCurrentDateTime(int *year, int *month, int *day, int *hour, int *minute, int *second); /** @@ -381,7 +376,7 @@ int DLLEXPORT swmm_getCurrentDateTime(int *year, int *month, int *day, @param[out] result The result of the node's property @return Error code */ -int DLLEXPORT swmm_getNodeResult(int index, SM_NodeResult type, double *result); +EXPORT_TOOLKIT int swmm_getNodeResult(int index, SM_NodeResult type, double *result); /** @brief Gets pollutant values for a specified node. @@ -390,16 +385,37 @@ int DLLEXPORT swmm_getNodeResult(int index, SM_NodeResult type, double *result); @param[out] PollutArray result array @return Error code */ -int DLLEXPORT swmm_getNodePollut(int index, SM_NodePollut type, double **pollutArray, int *length); +EXPORT_TOOLKIT int swmm_getNodePollut(int index, SM_NodePollut type, double **pollutArray, int *length); /** - @brief Get a result value for specified link. + @brief Sets pollutant values for a specified node. + @param index The index of a node + @param pollutant_index Pollutant index to set + @param pollutant_value Pollutant value to set + @return Error code +*/ +EXPORT_TOOLKIT int swmm_setNodePollut(int index, SM_NodePollut type, int pollutant_index, double pollutant_value); + +/** + @brief Sets pollutant values for a specified node. + @param index The index of a node + @param type The property type code (See @ref SM_NodePollut) + @param pollutant_index Pollutant index to set + @param pollutant_value Pollutant value to set + @return Error code +*/ + +EXPORT_TOOLKIT int swmm_setLinkPollut(int index, SM_LinkPollut type, int pollutant_index, double pollutant_value); + +/** + @brief Sets pollutant values for a specified link. @param index The index of a link - @param type The property type code (See @ref SM_LinkResult) - @param[out] result The result of the link's property + @param type The property type code (See @ref SM_LinkPollut) + @param pollutant_index Pollutant index to set + @param pollutant_value Pollutant value to set @return Error code */ -int DLLEXPORT swmm_getLinkResult(int index, SM_LinkResult type, double *result); +EXPORT_TOOLKIT int swmm_getLinkResult(int index, SM_LinkResult type, double *result); /** @brief Gets pollutant values for a specified link. @@ -408,7 +424,7 @@ int DLLEXPORT swmm_getLinkResult(int index, SM_LinkResult type, double *result); @param[out] PollutArray result array @return Error code */ -int DLLEXPORT swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutArray, int *length); +EXPORT_TOOLKIT int swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutArray, int *length); /** @brief Get a result value for specified subcatchment. @@ -417,7 +433,7 @@ int DLLEXPORT swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutA @param[out] result The result of the subcatchment's property @return Error code */ -int DLLEXPORT swmm_getSubcatchResult(int index, SM_SubcResult type, double *result); +EXPORT_TOOLKIT int swmm_getSubcatchResult(int index, SM_SubcResult type, double *result); /** @brief Gets pollutant values for a specified subcatchment. @@ -426,7 +442,7 @@ int DLLEXPORT swmm_getSubcatchResult(int index, SM_SubcResult type, double *resu @param[out] PollutArray result array @return Error code */ -int DLLEXPORT swmm_getSubcatchPollut(int index, SM_SubcPollut type, double **pollutArray, int *length); +EXPORT_TOOLKIT int swmm_getSubcatchPollut(int index, SM_SubcPollut type, double **pollutArray, int *length); /** @brief Get precipitation rates for a gage. @@ -435,7 +451,7 @@ int DLLEXPORT swmm_getSubcatchPollut(int index, SM_SubcPollut type, double **pol @param[out] GageArray precipitation rate @return Error code */ -int DLLEXPORT swmm_getGagePrecip(int index, SM_GagePrecip type, double *result); +EXPORT_TOOLKIT int swmm_getGagePrecip(int index, SM_GagePrecip type, double *result); /** @brief Get a node statistics. @@ -444,7 +460,7 @@ int DLLEXPORT swmm_getGagePrecip(int index, SM_GagePrecip type, double *result); pre-allocated by the caller. @return Error code */ -int DLLEXPORT swmm_getNodeStats(int index, SM_NodeStats *nodeStats); +EXPORT_TOOLKIT int swmm_getNodeStats(int index, SM_NodeStats *nodeStats); /** @brief Get the cumulative inflow for a node. @@ -452,7 +468,7 @@ int DLLEXPORT swmm_getNodeStats(int index, SM_NodeStats *nodeStats); @param[out] value The total inflow. @return Error code */ -int DLLEXPORT swmm_getNodeTotalInflow(int index, double *value); +EXPORT_TOOLKIT int swmm_getNodeTotalInflow(int index, double *value); /** @brief Get a storage statistics. @@ -461,7 +477,7 @@ int DLLEXPORT swmm_getNodeTotalInflow(int index, double *value); pre-allocated by the caller. @return Error code */ -int DLLEXPORT swmm_getStorageStats(int index, SM_StorageStats *storageStats); +EXPORT_TOOLKIT int swmm_getStorageStats(int index, SM_StorageStats *storageStats); /** @brief Get outfall statistics. @@ -472,7 +488,7 @@ int DLLEXPORT swmm_getStorageStats(int index, SM_StorageStats *storageStats); pollutants array. @return Error code */ -int DLLEXPORT swmm_getOutfallStats(int index, SM_OutfallStats *outfallStats); +EXPORT_TOOLKIT int swmm_getOutfallStats(int index, SM_OutfallStats *outfallStats); // /** // @brief Free outfall statistics structure. @@ -480,7 +496,7 @@ int DLLEXPORT swmm_getOutfallStats(int index, SM_OutfallStats *outfallStats); // pollutants array. // @return Error code // */ -// void DLLEXPORT swmm_freeOutfallStats(SM_OutfallStats *outfallStats); +// void EXPORT_TOOLKIT_API swmm_freeOutfallStats(SM_OutfallStats *outfallStats); /** @brief Get link statistics. @@ -489,7 +505,7 @@ int DLLEXPORT swmm_getOutfallStats(int index, SM_OutfallStats *outfallStats); pre-allocated by the caller. @return Error code */ -int DLLEXPORT swmm_getLinkStats(int index, SM_LinkStats *linkStats); +EXPORT_TOOLKIT int swmm_getLinkStats(int index, SM_LinkStats *linkStats); /** @brief Get pump statistics. @@ -498,7 +514,7 @@ int DLLEXPORT swmm_getLinkStats(int index, SM_LinkStats *linkStats); pre-allocated by the caller. @return Error code */ -int DLLEXPORT swmm_getPumpStats(int index, SM_PumpStats *pumpStats); +EXPORT_TOOLKIT int swmm_getPumpStats(int index, SM_PumpStats *pumpStats); /** @brief Get subcatchment statistics. @@ -509,7 +525,7 @@ int DLLEXPORT swmm_getPumpStats(int index, SM_PumpStats *pumpStats); pollutants array. @return Error code */ -int DLLEXPORT swmm_getSubcatchStats(int index, SM_SubcatchStats *subcatchStats); +EXPORT_TOOLKIT int swmm_getSubcatchStats(int index, SM_SubcatchStats *subcatchStats); /** @brief Get system routing totals. @@ -517,7 +533,7 @@ int DLLEXPORT swmm_getSubcatchStats(int index, SM_SubcatchStats *subcatchStats); pre-allocated by the caller. @return Error code */ -int DLLEXPORT swmm_getSystemRoutingTotals(SM_RoutingTotals *routingTotals); +EXPORT_TOOLKIT int swmm_getSystemRoutingTotals(SM_RoutingTotals *routingTotals); /** @brief Get system runoff totals. @@ -525,7 +541,7 @@ int DLLEXPORT swmm_getSystemRoutingTotals(SM_RoutingTotals *routingTotals); pre-allocated by the caller. @return Error code */ -int DLLEXPORT swmm_getSystemRunoffTotals(SM_RunoffTotals *runoffTotals); +EXPORT_TOOLKIT int swmm_getSystemRunoffTotals(SM_RunoffTotals *runoffTotals); /** @brief Set a link setting (pump, orifice, or weir). Setting for an orifice @@ -535,7 +551,7 @@ int DLLEXPORT swmm_getSystemRunoffTotals(SM_RunoffTotals *runoffTotals); @param setting The new setting for the link. @return Error code */ -int DLLEXPORT swmm_setLinkSetting(int index, double setting); +EXPORT_TOOLKIT int swmm_setLinkSetting(int index, double setting); /** @brief Set an inflow rate to a node. The inflow rate is held constant @@ -544,7 +560,7 @@ int DLLEXPORT swmm_setLinkSetting(int index, double setting); @param flowrate The new node inflow rate. @return Error code */ -int DLLEXPORT swmm_setNodeInflow(int index, double flowrate); +EXPORT_TOOLKIT int swmm_setNodeInflow(int index, double flowrate); /** @brief Set outfall stage. @@ -552,7 +568,7 @@ int DLLEXPORT swmm_setNodeInflow(int index, double flowrate); @param stage The outfall node stage (head). @return Error code */ -int DLLEXPORT swmm_setOutfallStage(int index, double stage); +EXPORT_TOOLKIT int swmm_setOutfallStage(int index, double stage); /** @brief Set a total precipitation intensity to the gage. @@ -560,18 +576,20 @@ int DLLEXPORT swmm_setOutfallStage(int index, double stage); @param total_precip The new total precipitation intensity. @return Error code */ -int DLLEXPORT swmm_setGagePrecip(int index, double total_precip); +EXPORT_TOOLKIT int swmm_setGagePrecip(int index, double total_precip); /** @brief Helper function to free memory array allocated in SWMM. @param array The pointer to the array @return Void. */ -void DLLEXPORT swmm_freeMemory(void *memory); +EXPORT_TOOLKIT void swmm_freeMemory(void *memory); + #ifdef __cplusplus } // matches the linkage specification from above */ #endif -#endif + +#endif // TOOLKIT_H diff --git a/src/solver/include/toolkit_enums.h b/src/solver/include/toolkit_enums.h index 25e5ef73f..9b54f7b2d 100644 --- a/src/solver/include/toolkit_enums.h +++ b/src/solver/include/toolkit_enums.h @@ -4,9 +4,7 @@ * Created on: November 13, 2020 * Updated on: * - * Author: Michael E. Tryby - * US EPA - ORD/CESER - * + * Author: See CONTRIBUTORS */ @@ -132,12 +130,15 @@ typedef enum { SM_NODEFLOOD = 4, /**< Flooding Rate */ SM_NODEDEPTH = 5, /**< Node Depth */ SM_NODEHEAD = 6, /**< Node Head */ - SM_LATINFLOW = 7 /**< Lateral Inflow Rate */ + SM_LATINFLOW = 7, /**< Lateral Inflow Rate */ + SM_HRT = 8 /**< HRT */ } SM_NodeResult; /// Node pollutant result property codes typedef enum { SM_NODEQUAL = 0, /**< Current Node Quality */ + SM_NODECIN = 1, /**< Inflow Concentration */ + SM_NODEREACTORC = 2 /**< Reactor Concentation */ } SM_NodePollut; /// Link result property codes @@ -156,6 +157,7 @@ typedef enum { typedef enum { SM_LINKQUAL = 0, /**< Current Link Quality */ SM_TOTALLOAD = 1, /**< Total Quality Mass Loading */ + SM_LINKREACTORC = 2 /**< Reactor Concentration */ } SM_LinkPollut; /// Subcatchment result property codes diff --git a/src/solver/kinwave.c b/src/solver/kinwave.c index d13662b68..c0fdf6fce 100644 --- a/src/solver/kinwave.c +++ b/src/solver/kinwave.c @@ -5,6 +5,7 @@ // Version: 5.1 // Date: 03/20/14 (Build 5.1.001) // 03/19/15 (Build 5.1.008) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman (EPA) // M. Tryby (EPA) // @@ -13,6 +14,9 @@ // Build 5.1.008: // - Conduit inflow passed to function that computes conduit losses. // +// Build 5.1.014: +// - Arguments to function link_getLossRate changed. +// //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -98,7 +102,7 @@ int kinwave_execute(int j, double* qinflow, double* qoutflow, double tStep) qin = (*qinflow) / Conduit[k].barrels / Qfull; // --- compute evaporation and infiltration loss rate - q3 = link_getLossRate(j, qin*Qfull, tStep) / Qfull; + q3 = link_getLossRate(j, qin*Qfull) / Qfull; //(5.1.014) // --- normalize previous areas a1 = Conduit[k].a1 / Afull; diff --git a/src/solver/lid.c b/src/solver/lid.c index 9deea8243..e7f6ef82d 100644 --- a/src/solver/lid.c +++ b/src/solver/lid.c @@ -12,6 +12,7 @@ // 08/01/16 (Build 5.1.011) // 03/14/17 (Build 5.1.012) // 05/10/18 (Build 5.1.013) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman (US EPA) // // This module handles all data processing involving LID (Low Impact @@ -72,6 +73,10 @@ // control curve for underdrain flow. // - Support added for unclogging permeable pavement at fixed intervals. // - Support added for pollutant removal in underdrain flow. +// +// Build 5.1.014: +// - Fixed bug in creating LidProcs when there are no subcatchments. +// - Fixed bug in adding underdrain pollutant loads to mass balances. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -246,10 +251,10 @@ void lid_create(int lidCount, int subcatchCount) return; } } - + //... initialize LID groups for (j = 0; j < GroupCount; j++) LidGroups[j] = NULL; - + //... create LID objects if ( LidCount == 0 ) return; LidProcs = (TLidProc *) calloc(LidCount, sizeof(TLidProc)); @@ -1481,7 +1486,7 @@ void lid_addDrainLoads(int j, double c[], double tStep) //... update system mass balance totals massbal_updateLoadingTotals(BMP_REMOVAL_LOAD, p, r*w); if (isRunoffLoad) - massbal_updateLoadingTotals(RUNOFF_LOAD, p, w*(1.0-r)); + massbal_updateLoadingTotals(RUNOFF_LOAD, p, w*(1.0 - r)); } // process next LID unit in the group diff --git a/src/solver/lidproc.c b/src/solver/lidproc.c index a7ffba73e..249442509 100644 --- a/src/solver/lidproc.c +++ b/src/solver/lidproc.c @@ -12,6 +12,7 @@ // 08/01/16 (Build 5.1.011) // 03/14/17 (Build 5.1.012) // 05/10/18 (Build 5.1.013) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman (US EPA) // // This module computes the hydrologic performance of an LID (Low Impact @@ -59,6 +60,10 @@ // to control underdrain flow. // - Support added for regenerating pavement permeability at fixed intervals. // +// Build 5.1.014: +// - Fixed failure to initialize all LID layer moisture volumes to 0 before +// computing LID unit performance in lidproc_getOutflow. +// //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -276,7 +281,11 @@ double lidproc_getOutflow(TLidUnit* lidUnit, TLidProc* lidProc, double inflow, x[STOR] = theLidUnit->storageDepth; x[PAVE] = theLidUnit->paveDepth; - //... initialize layer flux rates and moisture limits + //... initialize layer moisture volumes, flux rates and moisture limits + SurfaceVolume = 0.0; + PaveVolume = 0.0; + SoilVolume = 0.0; + StorageVolume = 0.0; SurfaceInflow = inflow; SurfaceInfil = 0.0; SurfaceEvap = 0.0; diff --git a/src/solver/link.c b/src/solver/link.c index c2e618291..3abc2f5f8 100644 --- a/src/solver/link.c +++ b/src/solver/link.c @@ -10,6 +10,7 @@ // 08/01/16 (Build 5.1.011) // 03/14/17 (Build 5.1.012) // 05/10/18 (Build 5.1.013) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman (EPA) // M. Tryby (EPA) // @@ -45,6 +46,10 @@ // - Support added for head-dependent weir coefficient curves. // - Adjustment of regulator link crest offset to match downstream node invert // now only done for Dynamic Wave flow routing. +// +// Build 5.1.014: +// - Conduit evap. and seepage losses initialized to 0 in conduit_initState() +// and not allowed to exceed current flow rate in conduit_getLossRate(). //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -97,7 +102,7 @@ static double conduit_getLength(int j); static double conduit_getLengthFactor(int j, int k, double roughness); static double conduit_getSlope(int j); static double conduit_getInflow(int j); -static double conduit_getLossRate(int j, double q, double tstep); +static double conduit_getLossRate(int j, double q); //(5.1.014) static int pump_readParams(int j, int k, char* tok[], int ntoks); static void pump_validate(int j, int k); @@ -865,7 +870,7 @@ double link_getPower(int j) //============================================================================= -double link_getLossRate(int j, double q, double tStep) +double link_getLossRate(int j, double q) //(5.1.014) // // Input: j = link index // q = flow rate (ft3/sec) @@ -875,7 +880,7 @@ double link_getLossRate(int j, double q, double tStep) // evaporation and seepage. // { - if ( Link[j].type == CONDUIT ) return conduit_getLossRate(j, q, tStep); + if ( Link[j].type == CONDUIT ) return conduit_getLossRate(j, q); //(5.1.014) else return 0.0; } @@ -1277,6 +1282,8 @@ void conduit_initState(int j, int k) { Link[j].newDepth = link_getYnorm(j, Link[j].q0 / Conduit[k].barrels); Link[j].oldDepth = Link[j].newDepth; + Conduit[k].evapLossRate = 0.0; //(5.1.014) + Conduit[k].seepLossRate = 0.0; //(5.1.014) } //============================================================================= @@ -1295,12 +1302,12 @@ double conduit_getInflow(int j) //============================================================================= -//// This function was modified for relese 5.1.013. //// //(5.1.013) +//// This function was modified for relese 5.1.014. //// //(5.1.014) -double conduit_getLossRate(int j, double q, double tStep) +double conduit_getLossRate(int j, double q) // // Input: j = link index -// tStep = time step (sec) +// q = current link flow rate (cfs) // Output: returns rate of evaporation & seepage losses (ft3/sec) // Purpose: computes volumetric rate of water evaporation & seepage // from a conduit (per barrel). @@ -1310,7 +1317,6 @@ double conduit_getLossRate(int j, double q, double tStep) double depth = 0.5 * (Link[j].oldDepth + Link[j].newDepth); double length; double topWidth; - double maxLossRate; double evapLossRate = 0.0, seepLossRate = 0.0, totalLossRate = 0.0; @@ -1342,17 +1348,13 @@ double conduit_getLossRate(int j, double q, double tStep) // --- compute total loss rate totalLossRate = evapLossRate + seepLossRate; - // --- total loss rate cannot exceed current volume - if ( totalLossRate > 0.0 ) + // --- total loss rate cannot exceed flow rate + q = ABS(q); + if (totalLossRate > q) { - maxLossRate = 0.5 * (Link[j].oldVolume + Link[j].newVolume) / tStep; - maxLossRate = MIN(maxLossRate, fabs(q)); - if ( totalLossRate > maxLossRate ) - { - evapLossRate = evapLossRate * maxLossRate / totalLossRate; - seepLossRate = seepLossRate * maxLossRate / totalLossRate; - totalLossRate = maxLossRate; - } + evapLossRate = evapLossRate * q / totalLossRate; + seepLossRate = seepLossRate * q / totalLossRate; + totalLossRate = q; } } diff --git a/src/solver/node.c b/src/solver/node.c index b783ff1d3..b74909d8c 100644 --- a/src/solver/node.c +++ b/src/solver/node.c @@ -8,6 +8,7 @@ // 04/02/15 (Build 5.1.008) // 08/05/15 (Build 5.1.010) // 05/10/18 (Build 5.1.013) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman // // Conveyance system node functions. @@ -27,6 +28,9 @@ // Build 5.1.013: // - A surcharge depth can now be applied to storage nodes. // - A negative inflow is now assigned to an Outfall node with backflow. +// +// Build 5.1.014: +// - Fixed bug in storage_losses() that affected storage exfiltration. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE diff --git a/src/solver/objects.h b/src/solver/objects.h index ef4a23be2..96e09e158 100644 --- a/src/solver/objects.h +++ b/src/solver/objects.h @@ -485,6 +485,7 @@ typedef struct char* ID; // node ID int type; // node type code int subIndex; // index of node's sub-category + int* extPollutFlag; // external pollutant flag char rptFlag; // reporting flag double invertElev; // invert elevation (ft) double initDepth; // initial storage level (ft) @@ -502,6 +503,7 @@ typedef struct double inflow; // total inflow (cfs) double outflow; // total outflow (cfs) double losses; // evap + exfiltration loss (ft3) + double hrt; // hydraulic retention time double oldVolume; // previous volume (ft3) double newVolume; // current volume (ft3) double fullVolume; // max. storage available (ft3) @@ -512,6 +514,9 @@ typedef struct double newLatFlow; // current lateral inflow (cfs) double* oldQual; // previous quality state double* newQual; // current quality state + double* extQual; // external quality state + double* inQual; // inflow quality state + double* reactorQual; // concentration in the mixed reactor double oldFlowInflow; // previous flow inflow double oldNetInflow; // previous net inflow } TNode; @@ -634,6 +639,7 @@ typedef struct char* ID; // link ID int type; // link type code int subIndex; // index of link's sub-category + int* extPollutFlag; // external pollutant flag char rptFlag; // reporting flag int node1; // start node index int node2; // end node index @@ -664,6 +670,8 @@ typedef struct double* oldQual; // previous quality state double* newQual; // current quality state double* totalLoad; // total quality mass loading + double* extQual; // external quality state + double* reactorQual; // concentration in the mixed reactor int flowClass; // flow classification double dqdh; // change in flow w.r.t. head (ft2/sec) signed char direction; // flow direction flag diff --git a/src/solver/output.c b/src/solver/output.c index 186a3979d..7eca52e7c 100644 --- a/src/solver/output.c +++ b/src/solver/output.c @@ -7,6 +7,7 @@ // 03/19/15 (Build 5.1.008) // 08/05/15 (Build 5.1.010) // 05/10/18 (Build 5.1.013) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman (EPA) // // Binary output file access functions. @@ -24,14 +25,18 @@ // - Support added for saving average node & link routing results to // binary file in each reporting period. // +// Build 5.1.014: +// - Incorrect loop limit fixed in function output_saveAvgResults. +// //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE #include #include #include -#include "headers.h" +#include "headers.h" +#include "version.h" // Definition of 4-byte integer, 4-byte real and 8-byte real types #define INT4 int @@ -178,7 +183,7 @@ int output_open() fseek(Fout.file, 0, SEEK_SET); k = MAGICNUMBER; fwrite(&k, sizeof(INT4), 1, Fout.file); // Magic number - k = VERSION; + k = get_version_legacy(); fwrite(&k, sizeof(INT4), 1, Fout.file); // Version number k = FlowUnits; fwrite(&k, sizeof(INT4), 1, Fout.file); // Flow units @@ -936,7 +941,7 @@ void output_saveAvgResults(FILE* file) } // --- add each link's volume to total system storage - for (i = 0; i < Nobjects[NODE]; i++) + for (i = 0; i < Nobjects[LINK]; i++) //(5.1.014) { SysResults[SYS_STORAGE] += (REAL4)(Link[i].newVolume * UCF(VOLUME)); } diff --git a/src/solver/project.c b/src/solver/project.c index 5e9b8e751..70b5a8c56 100644 --- a/src/solver/project.c +++ b/src/solver/project.c @@ -1037,6 +1037,10 @@ void createObjects() { Node[j].oldQual = (double *) calloc(Nobjects[POLLUT], sizeof(double)); Node[j].newQual = (double *) calloc(Nobjects[POLLUT], sizeof(double)); + Node[j].extQual = (double *) calloc(Nobjects[POLLUT], sizeof(double)); + Node[j].inQual = (double *) calloc(Nobjects[POLLUT], sizeof(double)); + Node[j].reactorQual = (double *) calloc(Nobjects[POLLUT], sizeof(double)); + Node[j].extPollutFlag = (int *) calloc(Nobjects[POLLUT], sizeof(int)); Node[j].extInflow = NULL; Node[j].dwfInflow = NULL; Node[j].rdiiInflow = NULL; @@ -1046,7 +1050,10 @@ void createObjects() { Link[j].oldQual = (double *) calloc(Nobjects[POLLUT], sizeof(double)); Link[j].newQual = (double *) calloc(Nobjects[POLLUT], sizeof(double)); + Link[j].extQual = (double *) calloc(Nobjects[POLLUT], sizeof(double)); Link[j].totalLoad = (double *) calloc(Nobjects[POLLUT], sizeof(double)); + Link[j].reactorQual = (double *) calloc(Nobjects[POLLUT], sizeof(double)); + Link[j].extPollutFlag = (int *) calloc(Nobjects[POLLUT], sizeof(int)); } // --- allocate memory for land use buildup/washoff functions diff --git a/src/solver/qualrout.c b/src/solver/qualrout.c index 7c16e45af..fd94ccd60 100644 --- a/src/solver/qualrout.c +++ b/src/solver/qualrout.c @@ -101,25 +101,27 @@ void qualrout_execute(double tStep) // { int i, j; + int p; double qIn, vAvg; - + // --- find mass flow each link contributes to its downstream node for ( i = 0; i < Nobjects[LINK]; i++ ) findLinkMassFlow(i, tStep); // --- find new water quality concentration at each node for (j = 0; j < Nobjects[NODE]; j++) { + // --- get node inflow and average volume qIn = Node[j].inflow; vAvg = (Node[j].oldVolume + Node[j].newVolume) / 2.0; // --- save inflow concentrations if treatment applied - if ( Node[j].treatment ) + if ( Node[j].treatment || ExtPollutFlag == 1) { if ( qIn < ZERO ) qIn = 0.0; treatmnt_setInflow(qIn, Node[j].newQual); } - + // --- find new quality at the node if ( Node[j].type == STORAGE || Node[j].oldVolume > FUDGE ) { @@ -128,11 +130,15 @@ void qualrout_execute(double tStep) else findNodeQual(j); // --- apply treatment to new quality values - if ( Node[j].treatment ) treatmnt_treat(j, qIn, vAvg, tStep); + if ( Node[j].treatment || ExtPollutFlag == 1) treatmnt_treat(j, qIn, vAvg, tStep); } // --- find new water quality in each link for ( i = 0; i < Nobjects[LINK]; i++ ) findLinkQual(i, tStep); + + // --- default to swmm treatment + if (ExtPollutFlag == 1){ExtPollutFlag = 0;} + } //============================================================================= @@ -254,7 +260,8 @@ void findLinkQual(int i, double tStep) vEvap, // volume lost to evaporation (ft3) vLosses, // evap. + seepage volume loss (ft3) fEvap, // evaporation concentration factor - barrels; // number of barrels in conduit + barrels, // number of barrels in conduit + lossExtQual; // loss value for external quality // --- identify index of upstream node j = Link[i].node1; @@ -310,7 +317,7 @@ void findLinkQual(int i, double tStep) // --- start with concen. at start of time step c1 = Link[i].oldQual[p]; - // --- update mass balance accounting for seepage loss + // --- update mass balance accounting for seepage loss massbal_addSeepageLoss(p, qSeep*c1); // --- increase concen. by evaporation factor @@ -329,9 +336,25 @@ void findLinkQual(int i, double tStep) massbal_addToFinalStorage(p, c2 * v2); c2 = 0.0; } - - // --- assign new concen. to link - Link[i].newQual[p] = c2; + + // --- set reactor qual for external pollutant handling + Link[i].reactorQual[p] = c2; + + if (Link[i].extPollutFlag[p] == 0) + { + // --- assign new concen. to link + Link[i].newQual[p] = c2; + } + // --- update mass balance and set external pollutant + else if( Link[i].extPollutFlag[p] == 1) + { + // --- mass balance update + lossExtQual = c2 - Link[i].extQual[p]; + lossExtQual = lossExtQual * v1/ tStep; + massbal_addReactedMass(p, lossExtQual); + Link[i].newQual[p] = Link[i].extQual[p]; + Link[i].extPollutFlag[p] = 0; + } } } @@ -452,6 +475,7 @@ void findStorageQual(int j, double tStep) // --- assign new concen. to node Node[j].newQual[p] = c2; + Node[j].reactorQual[p] = c2; } } @@ -498,4 +522,4 @@ double getReactedQual(int p, double c, double v1, double tStep) massbal_addReactedMass(p, lossRate); return c2; } - \ No newline at end of file + diff --git a/src/solver/rain.c b/src/solver/rain.c index 734bccce3..873031e74 100644 --- a/src/solver/rain.c +++ b/src/solver/rain.c @@ -7,6 +7,7 @@ // 08/05/15 (Build 5.1.010) // 08/22/16 (Build 5.1.011) // 05/10/18 (Build 5.1.013) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman // // Places rainfall data from external files into a SWMM rainfall @@ -48,6 +49,9 @@ // // Release 5.1.013: // - Variable x properly initialized with float value in readNwsOnlineValue(). +// +// Release 5.1.014: +// - Fixed indexing bug in rainFileConflict() function. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE diff --git a/src/solver/rdii.c b/src/solver/rdii.c index d9d7412f1..d94962489 100644 --- a/src/solver/rdii.c +++ b/src/solver/rdii.c @@ -7,6 +7,7 @@ // 04/04/14 (Build 5.1.003) // 04/14/14 (Build 5.1.004) // 09/15/14 (Build 5.1.007) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman (EPA) // R. Dickinson (CDM) // @@ -19,6 +20,8 @@ // - Ignore RDII option implemented. // - Rainfall climate adjustment implemented. // +// Build 5.1.014: +// - Fixes bug related to isUsed property of a unit hydrograph's rain gage. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE diff --git a/src/solver/report.c b/src/solver/report.c index 03437c4d5..07598b98a 100644 --- a/src/solver/report.c +++ b/src/solver/report.c @@ -10,6 +10,7 @@ // 08/01/16 (Build 5.1.011) // 03/14/17 (Build 5.1.012) // 05/10/18 (Build 5.1.013) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman (EPA) // // Report writing functions. @@ -40,6 +41,8 @@ // - Name of surcharge method reported in report_writeOptions(). // - Missing format specifier added to fprintf() in report_writeErrorCode. // +// Build 5.1.014: +// - Fixed bug in confusing keywords with ID names in report_readOptions(). //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -47,7 +50,10 @@ #include #include #include + #include "headers.h" +#include "version.h" + #define WRITE(x) (report_writeLine((x))) #define LINE_10 "----------" @@ -237,11 +243,9 @@ void report_writeLogo() // Purpose: writes report header lines to report file. // { - char SEMVERSION[SEMVERSION_LEN]; - getSemVersion(SEMVERSION); - sprintf(Msg, \ - "\n EPA STORM WATER MANAGEMENT MODEL - VERSION 5.1 (Build %s)", SEMVERSION); + "\n OWA STORM WATER MANAGEMENT MODEL - VERSION v%s (OWA %.10s)", + VERSION, BUILD_ID); fprintf(Frpt.file, "%s", Msg); fprintf(Frpt.file, FMT09); @@ -815,7 +819,7 @@ void report_writeFlowError(TRoutingTotals *totals) //============================================================================= -void report_writeQualError(TRoutingTotals QualTotals[]) +void report_writeQualError(TRoutingTotals* QualTotals) // // Input: totals = accumulated quality routing totals for each pollutant // Output: none diff --git a/src/solver/roadway.c b/src/solver/roadway.c index 4530f4fa3..0237ea96d 100644 --- a/src/solver/roadway.c +++ b/src/solver/roadway.c @@ -24,7 +24,10 @@ #include #include "headers.h" -enum RoadSurface {PAVED = 1, GRAVEL = 2}; +enum RoadSurface { + PAVED = 1, + GRAVEL = 2 +}; //----------------------------------------------------------------------------- // Constants @@ -39,7 +42,7 @@ enum RoadSurface {PAVED = 1, GRAVEL = 2}; static const int N_Cr_Low_Paved = 4; static const double Cr_Low_Paved[4][2] = { {0.0, 2.85}, {0.2, 2.95}, {0.7, 3.03}, {4.0, 3.05}}; - + static const int N_Cr_Low_Gravel = 8; static const double Cr_Low_Gravel[8][2] = { {0.0, 2.5}, {0.5, 2.7}, {1.0, 2.8}, {1.5, 2.9}, {2.0, 2.98}, @@ -187,4 +190,3 @@ double getY(double x, const double table[][2], const int n) } return table[n-1][1]; } - diff --git a/src/solver/runoff.c b/src/solver/runoff.c index 3571a0b7d..a7a6f5d83 100644 --- a/src/solver/runoff.c +++ b/src/solver/runoff.c @@ -8,6 +8,7 @@ // 03/19/15 (Build 5.1.008) // 08/01/16 (Build 5.1.011) // 03/14/17 (Build 5.1.012) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman // M. Tryby // @@ -29,6 +30,9 @@ // // Build 5.1.012: // - Runoff wet time step no longer kept aligned with reporting times. +// +// Build 5.1.014: +// - Fixed street sweeping bug. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE diff --git a/src/solver/surfqual.c b/src/solver/surfqual.c index 9dc6965cc..6f0dfc4f4 100644 --- a/src/solver/surfqual.c +++ b/src/solver/surfqual.c @@ -4,6 +4,7 @@ // Project: EPA SWMM5 // Version: 5.1 // Date: 03/19/15 (Build 5.1.008) +// 03/01/20 (Build 5.1.014) // Author: L. Rossman // // Subcatchment water quality functions. @@ -13,6 +14,8 @@ // subcatch.c. // - Support for separate accounting of LID drain flows included. // +// Build 5.1.014: +// - Fixed bug in computing effective BMP removal by LIDs. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE diff --git a/src/solver/swmm5.c b/src/solver/swmm5.c index 0be2b4364..517436d62 100644 --- a/src/solver/swmm5.c +++ b/src/solver/swmm5.c @@ -112,6 +112,7 @@ #include "text.h" // listing of all text strings #define EXTERN // defined as 'extern' in headers.h #include "globals.h" // declaration of all global variables +#include "version.h" #include "swmm5.h" // declaration of exportable functions // callable from other programs @@ -290,6 +291,9 @@ int DLLEXPORT swmm_start(int saveResults) NonConvergeCount = 0; IsStartedFlag = TRUE; + // --- initialize external pollutant control + ExtPollutFlag = 0; + // --- initialize global continuity errors RunoffError = 0.0; GwaterError = 0.0; @@ -603,18 +607,16 @@ int DLLEXPORT swmm_getMassBalErr(float* runoffErr, float* flowErr, //============================================================================= -int DLLEXPORT swmm_getVersion(void) +int DLLEXPORT swmm_getVersion(void) // // Input: none -// Output: returns SWMM engine version number +// Output: returns SWMM engine version number in legacy format // Purpose: retrieves version number of current SWMM engine which // uses a format of xyzzz where x = major version number, // y = minor version number, and zzz = build number. // -// NOTE: Each New Release should be updated in consts.h -// THIS FUNCTION WILL EVENTUALLY BE DEPRECATED { - return VERSION; + return get_version_legacy(); } //============================================================================= @@ -891,16 +893,3 @@ int swmm_IsStartedFlag() // TRUE if a simulation has been started return IsStartedFlag; } - - -void getSemVersion(char* semver) -// -// Output: Returns Semantic Version -// Purpose: retrieves the current semantic version -// -// NOTE: Each New Release should be updated in consts.h -{ - snprintf(semver, SEMVERSION_LEN, "%s.%s.%s", - SEMVERSION_MAJOR, SEMVERSION_MINOR, SEMVERSION_PATCH); -} -//============================================================================= diff --git a/src/solver/text.h b/src/solver/text.h index 6f3100613..f8224a77c 100644 --- a/src/solver/text.h +++ b/src/solver/text.h @@ -20,16 +20,18 @@ // Text strings //----------------------------------------------------------------------------- -#define FMT01 \ - "\tswmm5 \n" +//#include "consts.h" + +//#define FMT01 \ +// "\tswmm5 \n" #define FMT03 " There are errors.\n" #define FMT04 " There are warnings.\n" #define FMT05 "\n" #define FMT06 "\n o Retrieving project data" #define FMT07 "\n o Writing output report" -#define FMT08 \ - "\n EPA STORM WATER MANAGEMENT MODEL - VERSION 5.1 (Build 5.1.013)" //(5.1.013) +//#define FMT08 \ +// "\n EPA STORM WATER MANAGEMENT MODEL - VERSION 5.1 (Build "SEMVERSION_MAJOR"."SEMVERSION_MINOR"."SEMVERSION_PATCH")" //(5.1.014) #define FMT09 \ "\n --------------------------------------------------------------" #define FMT10 "\n" @@ -47,7 +49,7 @@ #define FMT21 " Total elapsed time: " // Warning messages -#define WARN01 "WARNING 01: wet weather time step reduced to recording interval for Rain Gage" +#define WARN01 "WARNING 01: wet weather time step reduced to recording interval for Rain Gage" #define WARN02 "WARNING 02: maximum depth increased for Node" #define WARN03 "WARNING 03: negative offset ignored for Link" #define WARN04 "WARNING 04: minimum elevation drop used for Conduit" @@ -239,7 +241,7 @@ #define w_CUSTOM "CUSTOM" #define w_FORCE_MAIN "FORCE_MAIN" #define w_H_W "H-W" -#define w_D_W "D-W" +#define w_D_W "D-W" // Link Offset Options #define w_ELEVATION "ELEVATION" @@ -256,7 +258,7 @@ // Flow Volume Units #define w_MGAL "10^6 gal" #define w_MLTRS "10^6 ltr" -#define w_GAL "gal" +#define w_GAL "gal" #define w_LTR "ltr" // Ponded Depth Units diff --git a/src/solver/toolkit.c b/src/solver/toolkit.c index 4976c7474..50c2f7b79 100644 --- a/src/solver/toolkit.c +++ b/src/solver/toolkit.c @@ -1,20 +1,24 @@ -/** @file toolkit.c - @see http://github.com/openwateranalytics/stormwater-management-model +/* + * toolkit.c - OWA SWMM Toolkit API + * + * Created on: Aug 30, 2016 + * Updated on: + * + * Author: See CONTRIBUTORS + * + * Note: + * Originally developed by Bryant McDonnell + */ - toolkit.c - @brief Exportable Functions for Toolkit API. - @date 08/30/2016 (First Contribution) - @authors B. McDonnell (EmNet LLC), OpenWaterAnalytics members: see AUTHORS. - - -*/ #define _CRT_SECURE_NO_DEPRECATE #include #include +#include #include "headers.h" +#include "version.h" #include "shared/cstr_helper.h" #include "swmm5.h" @@ -35,38 +39,33 @@ int stats_getSubcatchStat(int index, TSubcatchStats **subcatchStats); // Utilty Function Declarations -double* newDoubleArray(int n); - +double *newDoubleArray(int n); -// void DLLEXPORT swmm_getSemVersion(char* semver) -// // -// // Output: Returns Semantic Version -// // Purpose: retrieves the current semantic version -// // -// // NOTE: Each New Release should be updated in consts.h -// { -// getSemVersion(semver); -// } -int DLLEXPORT swmm_getVersionInfo(char** major, char** minor, char** patch) +EXPORT_TOOLKIT const char *swmm_getSemVersion() // -// Output: Returns Semantic Version Info +// Output: Returns Semantic Version // Purpose: retrieves the current semantic version // -// NOTE: Each New Release should be updated in consts.h { - cstr_duplicate(major, SEMVERSION_MAJOR); - cstr_duplicate(minor, SEMVERSION_MINOR); - cstr_duplicate(patch, SEMVERSION_PATCH); - return 0; + return VERSION; +} + +EXPORT_TOOLKIT const char *swmm_getBuildId() +// +// Output: Returns Build Id +// Purpose: retrieves the current build id +// +{ + return BUILD_ID; } //----------------------------------------------------------------------------- // Extended API Functions //----------------------------------------------------------------------------- -int DLLEXPORT swmm_run_cb(const char* f1, const char* f2, const char* f3, +EXPORT_TOOLKIT int swmm_run_cb(const char* f1, const char* f2, const char* f3, void (*callback) (double *)) // // Input: f1 = name of input file @@ -135,7 +134,7 @@ int DLLEXPORT swmm_run_cb(const char* f1, const char* f2, const char* f3, } -int DLLEXPORT swmm_getAPIError(int errorCode, char **errorMsg) +EXPORT_TOOLKIT int swmm_getAPIError(int errorCode, char **errorMsg) /// /// Input: errorCode = error code /// Output: errmessage String @@ -148,7 +147,7 @@ int DLLEXPORT swmm_getAPIError(int errorCode, char **errorMsg) } -int DLLEXPORT swmm_project_findObject(SM_ObjectType type, char *id, int *index) +EXPORT_TOOLKIT int swmm_project_findObject(SM_ObjectType type, char *id, int *index) { int error_code_index = 0; @@ -163,7 +162,7 @@ int DLLEXPORT swmm_project_findObject(SM_ObjectType type, char *id, int *index) return error_getCode(error_code_index); } -int DLLEXPORT swmm_getSimulationDateTime(SM_TimePropety type, int *year, int *month, int *day, +EXPORT_TOOLKIT int swmm_getSimulationDateTime(SM_TimePropety type, int *year, int *month, int *day, int *hour, int *minute, int *second) /// /// Input: type = time type to return @@ -204,7 +203,7 @@ int DLLEXPORT swmm_getSimulationDateTime(SM_TimePropety type, int *year, int *mo return error_getCode(error_code_index); } -int DLLEXPORT swmm_setSimulationDateTime(SM_TimePropety type, int year, int month, +EXPORT_TOOLKIT int swmm_setSimulationDateTime(SM_TimePropety type, int year, int month, int day, int hour, int minute, int second) /// @@ -266,7 +265,7 @@ int DLLEXPORT swmm_setSimulationDateTime(SM_TimePropety type, int year, int mont return error_getCode(error_code_index); } -int DLLEXPORT swmm_getSimulationUnit(SM_Units type, int *value) +EXPORT_TOOLKIT int swmm_getSimulationUnit(SM_Units type, int *value) /// /// Input: type = simulation unit type /// Output: enum representation of units @@ -298,7 +297,7 @@ int DLLEXPORT swmm_getSimulationUnit(SM_Units type, int *value) return error_getCode(error_code_index); } -int DLLEXPORT swmm_getSimulationAnalysisSetting(SM_SimOption type, int *value) +EXPORT_TOOLKIT int swmm_getSimulationAnalysisSetting(SM_SimOption type, int *value) /// /// Input: type = analysis type /// Output: setting True or False @@ -339,7 +338,7 @@ int DLLEXPORT swmm_getSimulationAnalysisSetting(SM_SimOption type, int *value) return error_getCode(error_code_index); } -int DLLEXPORT swmm_getSimulationParam(SM_SimSetting type, double *value) +EXPORT_TOOLKIT int swmm_getSimulationParam(SM_SimSetting type, double *value) /// /// Input: type = analysis type /// Output: Simulation Parameter @@ -411,7 +410,7 @@ int DLLEXPORT swmm_getSimulationParam(SM_SimSetting type, double *value) return error_getCode(error_code_index); } -int DLLEXPORT swmm_countObjects(SM_ObjectType type, int *count) +EXPORT_TOOLKIT int swmm_countObjects(SM_ObjectType type, int *count) /// /// Input: type = object type (Based on SM_ObjectType enum) /// Output: count = pointer to integer @@ -431,7 +430,7 @@ int DLLEXPORT swmm_countObjects(SM_ObjectType type, int *count) return error_getCode(error_code_index); } -int DLLEXPORT swmm_getObjectIndex(SM_ObjectType type, char *id, int *index) +EXPORT_TOOLKIT int swmm_getObjectIndex(SM_ObjectType type, char *id, int *index) /// /// Input: type = object type (Based on SM_ObjectType enum) /// char* = ID name @@ -450,7 +449,7 @@ int DLLEXPORT swmm_getObjectIndex(SM_ObjectType type, char *id, int *index) return error_getCode(error_code_index); } -int DLLEXPORT swmm_getObjectId(SM_ObjectType type, int index, char **id) +EXPORT_TOOLKIT int swmm_getObjectId(SM_ObjectType type, int index, char **id) /// /// Input: type = object type (Based on SM_ObjectType enum) /// index = Index of desired ID @@ -516,7 +515,7 @@ int DLLEXPORT swmm_getObjectId(SM_ObjectType type, int index, char **id) return error_getCode(error_code_index); } -int DLLEXPORT swmm_getNodeType(int index, SM_NodeType *Ntype) +EXPORT_TOOLKIT int swmm_getNodeType(int index, SM_NodeType *Ntype) /// /// Input: index = Index of desired ID /// Ntype = Node type (Based on enum SM_NodeType) @@ -540,7 +539,7 @@ int DLLEXPORT swmm_getNodeType(int index, SM_NodeType *Ntype) return error_getCode(error_code_index); } -int DLLEXPORT swmm_getLinkType(int index, SM_LinkType *Ltype) +EXPORT_TOOLKIT int swmm_getLinkType(int index, SM_LinkType *Ltype) /// /// Input: index = Index of desired ID /// Ltype = Link type (Based on enum SM_LinkType) @@ -564,7 +563,7 @@ int DLLEXPORT swmm_getLinkType(int index, SM_LinkType *Ltype) return error_getCode(error_code_index); } -int DLLEXPORT swmm_getLinkConnections(int index, int *Node1, int *Node2) +EXPORT_TOOLKIT int swmm_getLinkConnections(int index, int *Node1, int *Node2) /// /// Input: index = Index of desired ID /// Output: Node1 and Node2 indeces @@ -592,7 +591,7 @@ int DLLEXPORT swmm_getLinkConnections(int index, int *Node1, int *Node2) return error_getCode(error_code_index); } -int DLLEXPORT swmm_getLinkDirection(int index, signed char *value) +EXPORT_TOOLKIT int swmm_getLinkDirection(int index, signed char *value) /// /// Input: index = Index of desired ID /// Output: Link Direction (Only changes is slope < 0) @@ -618,7 +617,7 @@ int DLLEXPORT swmm_getLinkDirection(int index, signed char *value) return error_getCode(error_code_index); } -int DLLEXPORT swmm_getNodeParam(int index, SM_NodeProperty param, double *value) +EXPORT_TOOLKIT int swmm_getNodeParam(int index, SM_NodeProperty param, double *value) /// /// Input: index = Index of desired ID /// param = Parameter desired (Based on enum SM_NodeProperty) @@ -658,7 +657,7 @@ int DLLEXPORT swmm_getNodeParam(int index, SM_NodeProperty param, double *value) return error_getCode(error_code_index); } -int DLLEXPORT swmm_setNodeParam(int index, SM_NodeProperty param, double value) +EXPORT_TOOLKIT int swmm_setNodeParam(int index, SM_NodeProperty param, double value) /// /// Input: index = Index of desired ID /// param = Parameter desired (Based on enum SM_NodeProperty) @@ -704,7 +703,7 @@ int DLLEXPORT swmm_setNodeParam(int index, SM_NodeProperty param, double value) return error_getCode(error_code_index); } -int DLLEXPORT swmm_getLinkParam(int index, SM_LinkProperty param, double *value) +EXPORT_TOOLKIT int swmm_getLinkParam(int index, SM_LinkProperty param, double *value) /// /// Input: index = Index of desired ID /// param = Parameter desired (Based on enum SM_LinkProperty) @@ -748,7 +747,7 @@ int DLLEXPORT swmm_getLinkParam(int index, SM_LinkProperty param, double *value) return error_getCode(error_code_index); } -int DLLEXPORT swmm_setLinkParam(int index, SM_LinkProperty param, double value) +EXPORT_TOOLKIT int swmm_setLinkParam(int index, SM_LinkProperty param, double value) /// /// Input: index = Index of desired ID /// param = Parameter desired (Based on enum SM_LinkProperty) @@ -806,7 +805,7 @@ int DLLEXPORT swmm_setLinkParam(int index, SM_LinkProperty param, double value) } -int DLLEXPORT swmm_getSubcatchParam(int index, SM_SubcProperty param, double *value) +EXPORT_TOOLKIT int swmm_getSubcatchParam(int index, SM_SubcProperty param, double *value) /// /// Input: index = Index of desired ID /// param = Parameter desired (Based on enum SM_SubcProperty) @@ -846,7 +845,7 @@ int DLLEXPORT swmm_getSubcatchParam(int index, SM_SubcProperty param, double *va return error_getCode(error_code_index); } -int DLLEXPORT swmm_setSubcatchParam(int index, SM_SubcProperty param, double value) +EXPORT_TOOLKIT int swmm_setSubcatchParam(int index, SM_SubcProperty param, double value) /// /// Input: index = Index of desired ID /// param = Parameter desired (Based on enum SM_SubcProperty) @@ -897,7 +896,7 @@ int DLLEXPORT swmm_setSubcatchParam(int index, SM_SubcProperty param, double val return error_getCode(error_code_index); } -int DLLEXPORT swmm_getSubcatchOutConnection(int index, SM_ObjectType *type, int *out_index) +EXPORT_TOOLKIT int swmm_getSubcatchOutConnection(int index, SM_ObjectType *type, int *out_index) /// /// Input: index = Index of desired ID /// (Subcatchments can load to Node or another Subcatchment) @@ -941,7 +940,7 @@ int DLLEXPORT swmm_getSubcatchOutConnection(int index, SM_ObjectType *type, int } -int DLLEXPORT swmm_getLidUCount(int index, int *value) +EXPORT_TOOLKIT int swmm_getLidUCount(int index, int *value) // Input: index = Index of desired subcatchment // Output: int = number of lid units for subcatchment // Return: number of lid units for subcatchment @@ -968,7 +967,7 @@ int DLLEXPORT swmm_getLidUCount(int index, int *value) } -int DLLEXPORT swmm_getLidUParam(int index, int lidIndex, SM_LidUProperty param, double *value) +EXPORT_TOOLKIT int swmm_getLidUParam(int index, int lidIndex, SM_LidUProperty param, double *value) // // Input: index = Index of desired subcatchment // lidIndex = Index of desired lid unit (subcatchment allow for multiple lid units) @@ -1022,7 +1021,7 @@ int DLLEXPORT swmm_getLidUParam(int index, int lidIndex, SM_LidUProperty param, } -int DLLEXPORT swmm_setLidUParam(int index, int lidIndex, SM_LidUProperty param, double value) +EXPORT_TOOLKIT int swmm_setLidUParam(int index, int lidIndex, SM_LidUProperty param, double value) // // Input: index = Index of desired subcatchment // lidIndex = Index of desired lid unit (subcatchment allow for multiple lid units) @@ -1087,7 +1086,7 @@ int DLLEXPORT swmm_setLidUParam(int index, int lidIndex, SM_LidUProperty param, } -int DLLEXPORT swmm_getLidUOption(int index, int lidIndex, SM_LidUOptions param, int *value) +EXPORT_TOOLKIT int swmm_getLidUOption(int index, int lidIndex, SM_LidUOptions param, int *value) // // Input: index = Index of desired subcatchment // lidIndex = Index of desired lid unit (subcatchment allow for multiple lid units) @@ -1139,7 +1138,7 @@ int DLLEXPORT swmm_getLidUOption(int index, int lidIndex, SM_LidUOptions param, } -int DLLEXPORT swmm_setLidUOption(int index, int lidIndex, SM_LidUOptions param, int value) +EXPORT_TOOLKIT int swmm_setLidUOption(int index, int lidIndex, SM_LidUOptions param, int value) // // Input: index = Index of desired subcatchment // lidIndex = Index of desired lid unit (subcatchment allow for multiple lid units) @@ -1237,7 +1236,7 @@ int DLLEXPORT swmm_setLidUOption(int index, int lidIndex, SM_LidUOptions param, } -int DLLEXPORT swmm_getLidCOverflow(int lidControlIndex, int *condition) +EXPORT_TOOLKIT int swmm_getLidCOverflow(int lidControlIndex, int *condition) // // Input: lidControlIndex = Index of desired lid control // Output: condition = value to be output @@ -1269,7 +1268,7 @@ int DLLEXPORT swmm_getLidCOverflow(int lidControlIndex, int *condition) return error_getCode(error_code_index); } -int DLLEXPORT swmm_getLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double *value) +EXPORT_TOOLKIT int swmm_getLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double *value) // // Input: lidControlIndex = Index of desired lid control // layerIndex = Index of desired lid control layer (Based on enum SM_LidLayer) @@ -1452,7 +1451,7 @@ int DLLEXPORT swmm_getLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_ } -int DLLEXPORT swmm_setLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double value) +EXPORT_TOOLKIT int swmm_setLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double value) // // Input: lidControlIndex = Index of desired lid control // layerIndex = Index of desired lid control layer (Based on enum SM_LidLayers) @@ -1797,7 +1796,7 @@ int DLLEXPORT swmm_setLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_ // Active Simulation Results API //------------------------------- -int DLLEXPORT swmm_getCurrentDateTime(int *year, int *month, int *day, +EXPORT_TOOLKIT int swmm_getCurrentDateTime(int *year, int *month, int *day, int *hour, int *minute, int *second) /// /// Input: timetype = time type to return @@ -1832,7 +1831,7 @@ int DLLEXPORT swmm_getCurrentDateTime(int *year, int *month, int *day, } -int DLLEXPORT swmm_getNodeResult(int index, SM_NodeResult type, double *result) +EXPORT_TOOLKIT int swmm_getNodeResult(int index, SM_NodeResult type, double *result) /// /// Input: index = Index of desired ID /// type = Result Type (SM_NodeResult) @@ -1874,16 +1873,18 @@ int DLLEXPORT swmm_getNodeResult(int index, SM_NodeResult type, double *result) + Node[index].invertElev) * UCF(LENGTH); break; case SM_LATINFLOW: *result = Node[index].newLatFlow * UCF(FLOW); break; + case SM_HRT: + *result = Storage[Node[index].subIndex].hrt; break; default: error_code_index = ERR_API_OUTBOUNDS; break; } } return error_getCode(error_code_index); } -int DLLEXPORT swmm_getNodePollut(int index, SM_NodePollut type, double **pollutArray, int *length) +EXPORT_TOOLKIT int swmm_getNodePollut(int index, SM_NodePollut type, double **pollutArray, int *length) /// /// Input: index = Index of desired ID -/// type = Result Type (SM_NodePollut) +/// type = Result Type (SM_NodePollut or SM_NODECIN or SM_NODEREACTORC) /// Output: PollutArray pointer (pollutant data desired, byref) /// Return: API Error /// Purpose: Gets Node Simulated Water Quality Value at Current Time @@ -1909,6 +1910,8 @@ int DLLEXPORT swmm_getNodePollut(int index, SM_NodePollut type, double **pollutA else { + *length = Nobjects[POLLUT]; + switch (type) { case SM_NODEQUAL: @@ -1916,9 +1919,24 @@ int DLLEXPORT swmm_getNodePollut(int index, SM_NodePollut type, double **pollutA for (p = 0; p < Nobjects[POLLUT]; p++) { result[p] = Node[index].newQual[p]; - } + } + *pollutArray = result; + } break; + case SM_NODECIN: + { + for (p=0; p < Nobjects[POLLUT]; p++) + { + result[p] = Node[index].inQual[p]; + } + *pollutArray = result; + } break; + case SM_NODEREACTORC: + { + for (p=0; p < Nobjects[POLLUT]; p++) + { + result[p] = Node[index].reactorQual[p]; + } *pollutArray = result; - *length = Nobjects[POLLUT]; } break; default: error_code_index = ERR_API_OUTBOUNDS; break; } @@ -1926,7 +1944,52 @@ int DLLEXPORT swmm_getNodePollut(int index, SM_NodePollut type, double **pollutA return error_getCode(error_code_index); } -int DLLEXPORT swmm_getLinkResult(int index, SM_LinkResult type, double *result) +EXPORT_TOOLKIT int swmm_setNodePollut(int index, SM_NodePollut type, int pollutant_index, double pollutant_value) +/// +/// Input: index = Index of desired ID +/// type = SM_NODEQUAL - Set's node's qual and allows accounting for loss and mixing calculation +/// pollutant_index = Index of desired polluant +/// pollutant_value = Value of the pollutant +/// Return: API Error +/// Purpose: Set pollutant concentration in nodes at the current time step +{ + int error_code_index = 0; + + // Check if Open + if(swmm_IsOpenFlag() == FALSE) + { + error_code_index = ERR_API_INPUTNOTOPEN; + } + // Check if object index is within bounds + else if (index < 0 || index >= Nobjects[NODE]) + { + error_code_index = ERR_API_OBJECT_INDEX; + } + else + { + if (ExtPollutFlag == 0) + { + ExtPollutFlag = 1; + } + if (pollutant_index <= Nobjects[POLLUT]) + { + switch(type) + { + case SM_NODEQUAL: + { + Node[index].extQual[pollutant_index] = pollutant_value; + Node[index].extPollutFlag[pollutant_index] = 1; + } break; + default: error_code_index = ERR_API_OUTBOUNDS; break; + } + + } + } + return error_getCode(error_code_index); +} + + +EXPORT_TOOLKIT int swmm_getLinkResult(int index, SM_LinkResult type, double *result) /// /// Input: index = Index of desired ID /// type = Result Type (SM_LinkResult) @@ -1952,7 +2015,7 @@ int DLLEXPORT swmm_getLinkResult(int index, SM_LinkResult type, double *result) switch (type) { case SM_LINKFLOW: - *result = Link[index].newFlow * UCF(FLOW) ; break; + *result = Link[index].newFlow * (double) Link[index].direction * UCF(FLOW); break; case SM_LINKDEPTH: *result = Link[index].newDepth * UCF(LENGTH); break; case SM_LINKVOL: @@ -1973,7 +2036,7 @@ int DLLEXPORT swmm_getLinkResult(int index, SM_LinkResult type, double *result) return error_getCode(error_code_index); } -int DLLEXPORT swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutArray, int *length) +EXPORT_TOOLKIT int swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutArray, int *length) /// /// Input: index = Index of desired ID /// type = Result Type (SM_LinkPollut) @@ -2002,6 +2065,8 @@ int DLLEXPORT swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutA else { + *length = Nobjects[POLLUT]; + switch (type) { case SM_LINKQUAL: @@ -2009,9 +2074,8 @@ int DLLEXPORT swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutA for (p = 0; p < Nobjects[POLLUT]; p++) { result[p] = Link[index].newQual[p]; - } + } *pollutArray = result; - *length = Nobjects[POLLUT]; } break; case SM_TOTALLOAD: { @@ -2024,7 +2088,14 @@ int DLLEXPORT swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutA } } *pollutArray = result; - *length = Nobjects[POLLUT]; + } break; + case SM_LINKREACTORC: + { + for (p = 0; p < Nobjects[POLLUT]; p++) + { + result[p] = Link[index].reactorQual[p]; + } + *pollutArray = result; } break; default: error_code_index = ERR_API_OUTBOUNDS; break; } @@ -2032,7 +2103,51 @@ int DLLEXPORT swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutA return error_getCode(error_code_index); } -int DLLEXPORT swmm_getSubcatchResult(int index, SM_SubcResult type, double* result) + +EXPORT_TOOLKIT int swmm_setLinkPollut(int index, SM_LinkPollut type, int pollutant_index, double pollutant_value) +/// +/// Input: index = Index of the desired Link ID +/// type = SM_LINKQUAL - Sets link's qual and allows accounting for loss and mixing calculation +/// pollutant_index = index of pollutant to set +/// pollutant_value = concentration to set +/// Return: API error +/// Purponse: Set pollutant concentration in links +{ + int error_code_index = 0; + + // Check if Open + if(swmm_IsOpenFlag() == FALSE) + { + error_code_index = ERR_API_INPUTNOTOPEN; + } + // Check if object index is within bounds + else if (index < 0 || index >= Nobjects[LINK]) + { + error_code_index = ERR_API_OBJECT_INDEX; + } + else + { + if (ExtPollutFlag == 0) + { + ExtPollutFlag = 1; + } + if (pollutant_index <= Nobjects[POLLUT]) + { + switch(type) + { + case SM_LINKQUAL: + { + Link[index].extQual[pollutant_index] = pollutant_value; + Link[index].extPollutFlag[pollutant_index] = 1; + } break; + default: error_code_index = ERR_API_OUTBOUNDS; break; + } + } + } + return error_getCode(error_code_index); +} + +EXPORT_TOOLKIT int swmm_getSubcatchResult(int index, SM_SubcResult type, double* result) /// /// Input: index = Index of desired ID /// type = Result Type (SM_SubcResult) @@ -2075,7 +2190,7 @@ int DLLEXPORT swmm_getSubcatchResult(int index, SM_SubcResult type, double* resu return error_getCode(error_code_index); } -int DLLEXPORT swmm_getSubcatchPollut(int index, SM_SubcPollut type, double **pollutArray, int *length) +EXPORT_TOOLKIT int swmm_getSubcatchPollut(int index, SM_SubcPollut type, double **pollutArray, int *length) /// /// Input: index = Index of desired ID /// type = Result Type (SM_SubcPollut) @@ -2156,7 +2271,7 @@ int DLLEXPORT swmm_getSubcatchPollut(int index, SM_SubcPollut type, double **pol return error_getCode(error_code_index); } -int DLLEXPORT swmm_getGagePrecip(int index, SM_GagePrecip type, double* result) +EXPORT_TOOLKIT int swmm_getGagePrecip(int index, SM_GagePrecip type, double* result) /// /// Input: index = Index of desired ID /// type = Result type @@ -2198,7 +2313,7 @@ int DLLEXPORT swmm_getGagePrecip(int index, SM_GagePrecip type, double* result) } -int DLLEXPORT swmm_getNodeStats(int index, SM_NodeStats *nodeStats) +EXPORT_TOOLKIT int swmm_getNodeStats(int index, SM_NodeStats *nodeStats) /// /// Output: Node Stats Structure (SM_NodeStats) /// Return: API Error @@ -2227,7 +2342,7 @@ int DLLEXPORT swmm_getNodeStats(int index, SM_NodeStats *nodeStats) return error_getCode(error_index); } -int DLLEXPORT swmm_getNodeTotalInflow(int index, double* value) +EXPORT_TOOLKIT int swmm_getNodeTotalInflow(int index, double* value) /// /// Input: Node Index /// Output: Node Total inflow Volume. @@ -2250,7 +2365,7 @@ int DLLEXPORT swmm_getNodeTotalInflow(int index, double* value) return error_getCode(error_index); } -int DLLEXPORT swmm_getStorageStats(int index, SM_StorageStats *storageStats) +EXPORT_TOOLKIT int swmm_getStorageStats(int index, SM_StorageStats *storageStats) /// /// Output: Storage Node Stats Structure (SM_StorageStats) /// Return: API Error @@ -2283,7 +2398,7 @@ int DLLEXPORT swmm_getStorageStats(int index, SM_StorageStats *storageStats) return error_getCode(error_index); } -int DLLEXPORT swmm_getOutfallStats(int index, SM_OutfallStats *outfallStats) +EXPORT_TOOLKIT int swmm_getOutfallStats(int index, SM_OutfallStats *outfallStats) { int error_index = 0; @@ -2313,7 +2428,7 @@ int DLLEXPORT swmm_getOutfallStats(int index, SM_OutfallStats *outfallStats) } -int DLLEXPORT swmm_getLinkStats(int index, SM_LinkStats *linkStats) +EXPORT_TOOLKIT int swmm_getLinkStats(int index, SM_LinkStats *linkStats) /// /// Output: Link Stats Structure (SM_LinkStats) /// Return: API Error @@ -2343,7 +2458,7 @@ int DLLEXPORT swmm_getLinkStats(int index, SM_LinkStats *linkStats) } -int DLLEXPORT swmm_getPumpStats(int index, SM_PumpStats *pumpStats) +EXPORT_TOOLKIT int swmm_getPumpStats(int index, SM_PumpStats *pumpStats) /// /// Output: Pump Link Stats Structure (SM_PumpStats) /// Return: API Error @@ -2377,7 +2492,7 @@ int DLLEXPORT swmm_getPumpStats(int index, SM_PumpStats *pumpStats) } -int DLLEXPORT swmm_getSubcatchStats(int index, SM_SubcatchStats *subcatchStats) +EXPORT_TOOLKIT int swmm_getSubcatchStats(int index, SM_SubcatchStats *subcatchStats) /// /// Output: Subcatchment Stats Structure (SM_SubcatchStats) /// Return: API Error @@ -2407,7 +2522,7 @@ int DLLEXPORT swmm_getSubcatchStats(int index, SM_SubcatchStats *subcatchStats) } -int DLLEXPORT swmm_getSystemRoutingTotals(SM_RoutingTotals *routingTotals) +EXPORT_TOOLKIT int swmm_getSystemRoutingTotals(SM_RoutingTotals *routingTotals) /// /// Output: System Routing Totals Structure (SM_RoutingTotals) /// Return: API Error @@ -2432,7 +2547,7 @@ int DLLEXPORT swmm_getSystemRoutingTotals(SM_RoutingTotals *routingTotals) return error_getCode(error_index); } -int DLLEXPORT swmm_getSystemRunoffTotals(SM_RunoffTotals *runoffTotals) +EXPORT_TOOLKIT int swmm_getSystemRunoffTotals(SM_RunoffTotals *runoffTotals) /// /// Output: System Runoff Totals Structure (SM_RunoffTotals) /// Return: API Error @@ -2457,7 +2572,7 @@ int DLLEXPORT swmm_getSystemRunoffTotals(SM_RunoffTotals *runoffTotals) return error_getCode(error_index); } -int DLLEXPORT swmm_getLidUFluxRates(int index, int lidIndex, SM_LidLayer layerIndex, double* result) +EXPORT_TOOLKIT int swmm_getLidUFluxRates(int index, int lidIndex, SM_LidLayer layerIndex, double* result) // // Input: index = Index of desired subcatchment // lidIndex = Index of desired lid control (subcatchment allow for multiple lids) @@ -2508,7 +2623,7 @@ int DLLEXPORT swmm_getLidUFluxRates(int index, int lidIndex, SM_LidLayer layerIn return error_getCode(error_code_index); } -int DLLEXPORT swmm_getLidGResult(int index, SM_LidResult type, double* result) +EXPORT_TOOLKIT int swmm_getLidGResult(int index, SM_LidResult type, double* result) // // Input: index = index of desired subcatchment // type = type of result data desired @@ -2557,7 +2672,7 @@ int DLLEXPORT swmm_getLidGResult(int index, SM_LidResult type, double* result) return error_getCode(error_code_index); } -int DLLEXPORT swmm_getLidUResult(int index, int lidIndex, SM_LidResult type, double* result) +EXPORT_TOOLKIT int swmm_getLidUResult(int index, int lidIndex, SM_LidResult type, double* result) // // Input: index = Index of desired subcatchment // lidIndex = Index of desired lid control (subcatchment allow for multiple lids) @@ -2660,7 +2775,7 @@ int DLLEXPORT swmm_getLidUResult(int index, int lidIndex, SM_LidResult type, dou // Setters API //------------------------------- -int DLLEXPORT swmm_setLinkSetting(int index, double setting) +EXPORT_TOOLKIT int swmm_setLinkSetting(int index, double setting) /// /// Input: index = Index of desired ID /// value = New Target Setting @@ -2703,7 +2818,7 @@ int DLLEXPORT swmm_setLinkSetting(int index, double setting) } -int DLLEXPORT swmm_setNodeInflow(int index, double flowrate) +EXPORT_TOOLKIT int swmm_setNodeInflow(int index, double flowrate) /// /// Input: index = Index of desired ID /// value = New Inflow Rate @@ -2764,7 +2879,7 @@ int DLLEXPORT swmm_setNodeInflow(int index, double flowrate) return error_getCode(error_code_index); } -int DLLEXPORT swmm_setOutfallStage(int index, double stage) +EXPORT_TOOLKIT int swmm_setOutfallStage(int index, double stage) /// /// Input: index = Index of desired outfall /// stage = New outfall stage (head) @@ -2799,7 +2914,7 @@ int DLLEXPORT swmm_setOutfallStage(int index, double stage) return error_getCode(error_code_index); } -int DLLEXPORT swmm_setGagePrecip(int index, double total_precip) +EXPORT_TOOLKIT int swmm_setGagePrecip(int index, double total_precip) /// /// Input: index = Index of desired ID /// total_precip = rainfall intensity to be set @@ -2837,6 +2952,15 @@ int DLLEXPORT swmm_setGagePrecip(int index, double total_precip) return error_getCode(error_code_index); } +EXPORT_TOOLKIT void swmm_freeMemory(void *memory) +// +// Purpose: Frees memory allocated by API calls +// +{ + free(memory); +} + + //------------------------------- // Utility Functions //------------------------------- @@ -2848,22 +2972,3 @@ double* newDoubleArray(int n) { return (double*) malloc((n)*sizeof(double)); } - - -//void DLLEXPORT freeArray(void** array) -/// -/// Helper function used to free array allocated memory by API. -/// -//{ -// FREE(*array); -// *array = NULL; -//} - - -void DLLEXPORT swmm_freeMemory(void *memory) -// -// Purpose: Frees memory allocated by API calls -// -{ - free(memory); -} diff --git a/src/solver/treatmnt.c b/src/solver/treatmnt.c index 0843b5f96..1b1491e49 100644 --- a/src/solver/treatmnt.c +++ b/src/solver/treatmnt.c @@ -208,7 +208,7 @@ void treatmnt_treat(int j, double q, double v, double tStep) double cOut; // concentration after treatment double massLost; // mass lost by treatment per time step TTreatment* treatment; // pointer to treatment object - + // --- set locally shared variables for node j if ( Node[j].treatment == NULL ) return; ErrCode = 0; @@ -216,7 +216,6 @@ void treatmnt_treat(int j, double q, double v, double tStep) Dt = tStep; // current time step Q = q; // current inflow rate V = v; // current node volume - // --- initialze each removal to indicate no value for ( p = 0; p < Nobjects[POLLUT]; p++) R[p] = -1.0; @@ -228,7 +227,10 @@ void treatmnt_treat(int j, double q, double v, double tStep) if ( treatment->equation == NULL ) R[p] = 0.0; // --- no removal for removal-type expression when there is no inflow - else if ( treatment->treatType == REMOVAL && q <= ZERO ) R[p] = 0.0; + else if ( treatment->treatType == REMOVAL && q <= ZERO ) R[p] = 0.0; + + // --- check for external treatment + else if ( Node[j].extPollutFlag[p] == 1) R[p] = 0.0; // --- otherwise evaluate the treatment expression to find R[p] else getRemoval(p); @@ -239,16 +241,16 @@ void treatmnt_treat(int j, double q, double v, double tStep) { report_writeErrorMsg(ERR_CYCLIC_TREATMENT, Node[J].ID); } - + // --- update nodal concentrations and mass balances else for ( p = 0; p < Nobjects[POLLUT]; p++ ) { - if ( R[p] == 0.0 ) continue; + if ( R[p] == 0.0 && Node[j].extPollutFlag[p] != 1) continue; treatment = &Node[j].treatment[p]; // --- removal-type treatment equations get applied to inflow stream - if ( treatment->treatType == REMOVAL ) + if ( treatment->treatType == REMOVAL && Node[j].extPollutFlag[p] != 1) { // --- if no pollutant in inflow then cOut is current nodal concen. if ( Cin[p] == 0.0 ) cOut = Node[j].newQual[p]; @@ -261,16 +263,30 @@ void treatmnt_treat(int j, double q, double v, double tStep) cOut = MIN(cOut, Node[j].newQual[p]); } + // --- water quality set externally + else if( Node[j].extPollutFlag[p] == 1) + { + cOut = Node[j].extQual[p]; + } + // --- concentration-type equations get applied to nodal concentration else { cOut = (1.0 - R[p]) * Node[j].newQual[p]; } + + // --- store inflow concentration for the timestep + Node[j].inQual[p] = Cin[p]; - // --- mass lost must account for any initial mass in storage + // --- mass lost must account for any initial mass in storage massLost = (Cin[p]*q*tStep + Node[j].oldQual[p]*Node[j].oldVolume - - cOut*(q*tStep + Node[j].oldVolume)) / tStep; - massLost = MAX(0.0, massLost); + cOut*(q*tStep + Node[j].oldVolume)) / tStep; + + // --- mass can be gained in external treatment + if (Node[j].extPollutFlag[p] != 1) massLost = MAX(0.0, massLost); + + // --- reset the flag to default to swmm treatment + if (Node[j].extPollutFlag[p] == 1) Node[j].extPollutFlag[p] = 0; // --- add mass loss to mass balance totals and revise nodal concentration massbal_addReactedMass(p, massLost); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4cbe5698c..17f17d546 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,12 +2,14 @@ # CMakeLists.txt - CMake configuration file for swmm-solver/tests # # Created: Jul 7, 2020 +# Updated: Jan 14, 2021 # # Author: Michael E. Tryby # US EPA ORD/CESER # + #Prep ourselves for compiling with boost include(../extern/boost.cmake) diff --git a/tests/outfile/test_output.cpp b/tests/outfile/test_output.cpp index e0b901bd6..1d44400ad 100644 --- a/tests/outfile/test_output.cpp +++ b/tests/outfile/test_output.cpp @@ -1,7 +1,7 @@ /* ****************************************************************************** Project: OWA SWMM - Version: 5.1.13 + Version: 5.1.14 Module: test_output.cpp Description: tests for output library functions Authors: see AUTHORS @@ -257,7 +257,7 @@ BOOST_FIXTURE_TEST_CASE(test_getSubcatchSeries, Fixture) { const int ref_dim = 10; float ref_array[ref_dim] = { 0.0f, 1.2438242f, 2.5639679f, 4.524055f, 2.5115132f, 0.69808137f, - 0.040894926f, 0.011605669f, 0.00509294f, 0.0027438672f}; + 0.040894926f, 0.011605669f, 0.00509294f, 0.0027438672f}; std::vector ref_vec; ref_vec.assign(ref_array, ref_array + 10); @@ -274,7 +274,7 @@ BOOST_FIXTURE_TEST_CASE(test_getSubcatchResult, Fixture) { const int ref_dim = 10; float ref_array[ref_dim] = { - 0.5f, 0.0f, 0.0f, 0.125f, 1.2438242f, + 0.5f, 0.0f, 0.0f, 0.125f, 1.2438242f, 0.0f, 0.0f, 0.0f, 33.481991f, 6.6963983f}; std::vector ref_vec; @@ -292,8 +292,8 @@ BOOST_FIXTURE_TEST_CASE(test_getNodeResult, Fixture) { const int ref_dim = 8; float ref_array[ref_dim] = { - 0.296234f, 995.296204f, 0.0f, 1.302650f, 1.302650f, 0.0f, - 15.361463f, 3.072293f}; + 0.296234f, 995.296204f, 0.0f, 1.302650f, 1.302650f, 0.0f, + 15.361463f, 3.072293f}; std::vector ref_vec; ref_vec.assign(ref_array, ref_array + ref_dim); @@ -310,8 +310,8 @@ BOOST_FIXTURE_TEST_CASE(test_getLinkResult, Fixture) { const int ref_dim = 7; float ref_array[ref_dim] = { - 4.631762f, 1.0f, 5.8973422f, 314.15927f, 1.0f, 19.070757f, - 3.8141515f}; + 4.631762f, 1.0f, 5.8973422f, 314.15927f, 1.0f, 19.070757f, + 3.8141515f}; std::vector ref_vec; ref_vec.assign(ref_array, ref_array + ref_dim); @@ -329,7 +329,7 @@ BOOST_FIXTURE_TEST_CASE(test_getSystemResult, Fixture) { const int ref_dim = 14; float ref_array[ref_dim] = { 70.0f, 0.1f, 0.0f, 0.19042271f, 14.172027f, 0.0f, 0.0f, 0.0f, - 0.0f, 14.172027f, 0.55517411f, 13.622702f, 2913.0793f, 0.0f}; + 0.0f, 14.172027f, 0.55517411f, 13.622702f, 2913.0793f, 0.0f}; std::vector ref_vec; ref_vec.assign(ref_array, ref_array + ref_dim); diff --git a/tests/solver/CMakeLists.txt b/tests/solver/CMakeLists.txt index ae987411e..da8a5d375 100644 --- a/tests/solver/CMakeLists.txt +++ b/tests/solver/CMakeLists.txt @@ -48,7 +48,7 @@ target_compile_features(test_solver PUBLIC cxx_generalized_initializers ) - + target_link_libraries(test_solver ${Boost_LIBRARIES} swmm5 diff --git a/tests/solver/data/link_constantinflow.inp b/tests/solver/data/link_constantinflow.inp new file mode 100644 index 000000000..77a1123d0 --- /dev/null +++ b/tests/solver/data/link_constantinflow.inp @@ -0,0 +1,165 @@ +[TITLE] +;;Project Title/Notes +Example 6 +Circular Culvert with Roadway Overtopping +and Upstream Storage + +[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 06/08/2015 +START_TIME 00:00:00 +REPORT_START_DATE 06/08/2015 +REPORT_START_TIME 00:00:00 +END_DATE 06/08/2015 +END_TIME 05:00:00 +SWEEP_START 01/01 +SWEEP_END 12/31 +DRY_DAYS 0 +REPORT_STEP 00:00:01 +WET_STEP 00:00:01 +DRY_STEP 00:00:01 +ROUTING_STEP 1 +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 12.557 +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 + +[JUNCTIONS] +;;Name Elevation MaxDepth InitDepth SurDepth Aponded +;;-------------- ---------- ---------- ---------- ---------- ---------- +J1 860 0 0 0 0 +Outlet 868 0 0 0 0 + +[OUTFALLS] +;;Name Elevation Type Stage Data Gated Route To +;;-------------- ---------- ---------- ---------------- -------- ---------------- +TailWater 855 FIXED 859.5 NO + +[STORAGE] +;;Name Elev. MaxDepth InitDepth Shape Curve Name/Params N/A Fevap Psi Ksat IMD +;;-------------- -------- ---------- ---------- ---------- ---------------------------- -------- -------- -------- -------- +Inlet 878 9 0 TABULAR StorageCurve 0 0 + +[CONDUITS] +;;Name From Node To Node Length Roughness InOffset OutOffset InitFlow MaxFlow +;;-------------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- +C1 Outlet J1 400 0.01 0 0 0 0 +C2 J1 TailWater 400 0.01 0 0 0 0 +Culvert Inlet Outlet 200 0.014 0 0 0 0 + +[WEIRS] +;;Name From Node To Node Type CrestHt Qcoeff Gated EndCon EndCoeff Surcharge RoadWidth RoadSurf Coeff. Curve +;;-------------- ---------------- ---------------- ------------ ---------- ---------- -------- -------- ---------- ---------- ---------- ---------- ---------------- +Roadway Inlet Outlet ROADWAY 9 3.33 NO 0 0 NO 40 GRAVEL + +[XSECTIONS] +;;Link Shape Geom1 Geom2 Geom3 Geom4 Barrels Culvert +;;-------------- ------------ ---------------- ---------- ---------- ---------- ---------- ---------- +C1 CIRCULAR 3 0 0 0 1 +C2 CIRCULAR 3 0 0 0 1 +Culvert CIRCULAR 3 0 0 0 2 4 +Roadway RECT_OPEN 50 200 0 0 + +[LOSSES] +;;Link Kentry Kexit Kavg Flap Gate Seepage +;;-------------- ---------- ---------- ---------- ---------- ---------- + +[POLLUTANTS] +;;Name Units Crain Cgw Crdii Kdecay SnowOnly Co-Pollutant Co-Frac Cdwf Cinit +;;-------------- ------ ---------- ---------- ---------- ---------- ---------- ---------------- ---------- ---------- ---------- +P1 MG/L 0.0 0.0 0.0 0.0 NO * 0.0 0.0 0.0 + +[INFLOWS] +;;Node Constituent Time Series Type Mfactor Sfactor Baseline Pattern +;;-------------- ---------------- ---------------- -------- -------- -------- -------- -------- +Inlet FLOW "" FLOW 1.0 1.0 10.0 +Inlet P1 "" CONCENTRATION 1.0 1.0 10.0 + +[CURVES] +;;Name Type X-Value Y-Value +;;-------------- ---------- ---------- ---------- +StorageCurve Storage 0 0 +StorageCurve 2 9583 +StorageCurve 4 33977 +StorageCurve 6 72310 +StorageCurve 8 136778 + +[TIMESERIES] +;;Name Date Time Value +;;-------------- ---------- ---------- ---------- +Inflow 0 0 +Inflow .125 9 +Inflow .25 10 +Inflow .375 11 +Inflow .5 13 +Inflow .625 17 +Inflow .75 28 +Inflow .875 40 +Inflow 1 80 +Inflow 1.125 136 +Inflow 1.25 190 +Inflow 1.375 220 +Inflow 1.5 220 +Inflow 1.625 201 +Inflow 1.75 170 +Inflow 1.875 140 +Inflow 2 120 +Inflow 2.125 98 +Inflow 2.25 82 +Inflow 2.375 70 +Inflow 2.5 60 +Inflow 2.625 53 +Inflow 2.75 47 +Inflow 2.875 41 + +[REPORT] +;;Reporting Options +INPUT NO +CONTROLS NO +SUBCATCHMENTS ALL +NODES ALL +LINKS ALL + +[TAGS] + +[MAP] +DIMENSIONS 1408.9383 6118.83065 6238.6797 7216.52835 +UNITS None + +[COORDINATES] +;;Node X-Coord Y-Coord +;;-------------- ------------------ ------------------ +J1 5131.441 6259.528 +Outlet 4206.542 6357.994 +TailWater 6019.146 6168.726 +Inlet 1628.472 6476.537 + +[VERTICES] +;;Link X-Coord Y-Coord +;;-------------- ------------------ ------------------ +Roadway 2311.068 7166.633 +Roadway 3762.491 7151.463 diff --git a/tests/solver/data/link_flow_dir.inp b/tests/solver/data/link_flow_dir.inp new file mode 100644 index 000000000..9600b1f51 --- /dev/null +++ b/tests/solver/data/link_flow_dir.inp @@ -0,0 +1,103 @@ +[TITLE] +;;Project Title/Notes +Example model with positive and negative sloped profiles +to test that flow direction is accounted for in link flow getter. + +[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/2022 +START_TIME 00:00:00 +REPORT_START_DATE 01/01/2022 +REPORT_START_TIME 00:00:00 +END_DATE 01/01/2022 +END_TIME 01:00:00 +SWEEP_START 01/01 +SWEEP_END 12/31 +DRY_DAYS 0 +REPORT_STEP 00:15:00 +WET_STEP 00:05:00 +DRY_STEP 01:00:00 +ROUTING_STEP 0:00:20 +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 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 + +[JUNCTIONS] +;;Name Elevation MaxDepth InitDepth SurDepth Aponded +;;-------------- ---------- ---------- ---------- ---------- ---------- +3 3 0 0 100 0 +4 3 0 0 100 0 + +[OUTFALLS] +;;Name Elevation Type Stage Data Gated Route To +;;-------------- ---------- ---------- ---------------- -------- ---------------- +1 0 FREE NO +2 0 FREE NO + +[CONDUITS] +;;Name From Node To Node Length Roughness InOffset OutOffset InitFlow MaxFlow +;;-------------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- +positive 3 1 100 0.013 0 0 0 0 +negative 2 4 100 0.013 0 0 0 0 + +[XSECTIONS] +;;Link Shape Geom1 Geom2 Geom3 Geom4 Barrels Culvert +;;-------------- ------------ ---------------- ---------- ---------- ---------- ---------- ---------- +positive CIRCULAR 1 0 0 0 1 +negative CIRCULAR 1 0 0 0 1 + +[INFLOWS] +;;Node Constituent Time Series Type Mfactor Sfactor Baseline Pattern +;;-------------- ---------------- ---------------- -------- -------- -------- -------- -------- +3 FLOW "" FLOW 1.0 1.0 5 +4 FLOW "" FLOW 1.0 1.0 5 + +[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 +;;-------------- ------------------ ------------------ +3 1626.773 9202.128 +4 3701.241 9148.936 +1 1635.638 7375.887 +2 3648.050 7304.965 + +[VERTICES] +;;Link X-Coord Y-Coord +;;-------------- ------------------ ------------------ + diff --git a/tests/solver/data/node_constantinflow_constanteffluent.inp b/tests/solver/data/node_constantinflow_constanteffluent.inp new file mode 100644 index 000000000..dd164967c --- /dev/null +++ b/tests/solver/data/node_constantinflow_constanteffluent.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/tests/solver/test_lid.hpp b/tests/solver/test_lid.hpp index baa5986f9..a5c690557 100644 --- a/tests/solver/test_lid.hpp +++ b/tests/solver/test_lid.hpp @@ -18,8 +18,10 @@ #include +extern "C" { #include "swmm5.h" #include "toolkit.h" +} #define ERR_NONE 0 diff --git a/tests/solver/test_pollut.cpp b/tests/solver/test_pollut.cpp index c6cabed90..e1c978f95 100644 --- a/tests/solver/test_pollut.cpp +++ b/tests/solver/test_pollut.cpp @@ -60,6 +60,8 @@ BOOST_FIXTURE_TEST_CASE(get_pollut_values, FixtureBeforeStep){ { // subcatchment buildup error = swmm_getSubcatchPollut(subc_ind, SM_BUILDUP, &buildup_array, &length); + // Check length is set correctly + BOOST_CHECK(length == 2); BOOST_REQUIRE(error == ERR_NONE); BOOST_CHECK_SMALL(buildup_array[TSS] - 31.906912, 0.0001); BOOST_CHECK_SMALL(buildup_array[Lead] - 0.0, 0.0001); @@ -148,5 +150,341 @@ BOOST_FIXTURE_TEST_CASE(get_pollut_values, FixtureBeforeStep){ swmm_end(); } +// Testing Node influent concentration- storage assets +BOOST_FIXTURE_TEST_CASE(get_node_pollutant_values_cin, FixtureBeforeStep_Pollut_Node){ + + int error, step_ind; + double* node_qual; + double elapsedTime = 0.0; + double total_pollutant = 0.0; + int length; + + // Pollutant IDs + int P1 = 0; + double cin = 10; + + step_ind = 0; + do + { + + // Get inflow concentration + error = swmm_getNodePollut(1, SM_NODECIN, &node_qual, &length); + // Check length is set correctly + BOOST_CHECK(length == 1); + BOOST_REQUIRE(error == ERR_NONE); + + // Check for constant influent + if (step_ind > 5) + BOOST_CHECK_CLOSE(cin, node_qual[P1], 0.001); + + // Route Model Forward + error = swmm_step(&elapsedTime); + step_ind+=1; + + }while (elapsedTime != 0 && !error); + BOOST_REQUIRE(error == ERR_NONE); + + swmm_end(); +} + +// Testing Reactor Concentration in Node +BOOST_FIXTURE_TEST_CASE(get_node_reactor_pollutant, FixtureBeforeStep_Pollut_Node){ + + int error, step_ind; + double* old_qual; + double* new_qual; + double elapsedTime = 0.0; + double total_pollutant = 0.0; + int length; + + // Pollutant IDs + int P1 = 0; + + step_ind = 0; + do + { + // Check for steady state after 1000 steps. + // 1000 is a aribitarly long time duration, it can be any value as long + // the system reaches a steady state + + // Get reactor concentration + error = swmm_getNodePollut(1, SM_NODEREACTORC, &new_qual, &length); + // Check length is set correctly + BOOST_CHECK(length == 1); + BOOST_REQUIRE(error == ERR_NONE); + + if (step_ind > 1000) + { + BOOST_CHECK_CLOSE(old_qual[P1], new_qual[P1], 0.001); + } + + old_qual = new_qual; + + // Route Model Forward + error = swmm_step(&elapsedTime); + step_ind+=1; + }while (elapsedTime != 0 && !error); + BOOST_REQUIRE(error == ERR_NONE); + swmm_end(); +} + +// Testing Reactor Concentration in Link +BOOST_FIXTURE_TEST_CASE(get_link_reactor_pollutant, FixtureBeforeStep_Pollut_Link){ + + int error, step_ind; + double* old_qual; + double* new_qual; + double elapsedTime = 0.0; + double total_pollutant = 0.0; + int length; + + // Pollutant IDs + int P1 = 0; + + step_ind = 0; + do + { + // Check for steady state after 1000 steps. + // 1000 is a aribitarly long time duration, it can be any value as long + // the system reaches a steady state + + // Get reactor concentration + error = swmm_getLinkPollut(1, SM_LINKREACTORC, &new_qual, &length); + // Check length is set correctly + BOOST_CHECK(length == 1); + BOOST_REQUIRE(error == ERR_NONE); + + if (step_ind > 1500) + { + BOOST_CHECK_CLOSE(old_qual[P1], new_qual[P1], 0.001); + } + + old_qual = new_qual; + + // Route Model Forward + error = swmm_step(&elapsedTime); + step_ind+=1; + }while (elapsedTime != 0 && !error); + BOOST_REQUIRE(error == ERR_NONE); + swmm_end(); +} + +// Testing Pollutant Setter - Node - Cumulative and mass balance +BOOST_FIXTURE_TEST_CASE(set_node_pollutant_cumulative_values, FixtureBeforeStep_Pollut_Node){ + + int error; + double* node_qual; + float runoff_error, flow_error, qual_error; + double elapsedTime = 0.0; + double total_pollutant = 0.0; + int length; + + // Pollutant IDs + int P1 = 0; + + do + { + // Set pollutant + error = swmm_setNodePollut(1, SM_NODEQUAL, P1, 0); + BOOST_REQUIRE(error == ERR_NONE); + // Route Model Forward + error = swmm_step(&elapsedTime); + // Get pollutant + error = swmm_getNodePollut(1, SM_NODEQUAL, &node_qual, &length); + BOOST_REQUIRE(error == ERR_NONE); + // Record cumulative pollutant + total_pollutant = total_pollutant + node_qual[P1]; + + }while (elapsedTime != 0 && !error); + BOOST_REQUIRE(error == ERR_NONE); + + // Cumulative must be 0.00 + BOOST_CHECK_SMALL(total_pollutant, 1.0e-06); + swmm_end(); + // check mass balance error less than 5% + swmm_getMassBalErr(&runoff_error, &flow_error, &qual_error); + BOOST_CHECK(abs(qual_error) <= 1.0); +} + +// Testing Pollutant Setter - Node - Stepwise and Mass balance less than inflow concentration of 10 +BOOST_FIXTURE_TEST_CASE(set_node_pollutant_stepwise_values, FixtureBeforeStep_Pollut_Node){ + + int error; + double* node_qual; + float runoff_error, flow_error, qual_error; + double elapsedTime = 0.0; + int length; + + // Pollutant IDs + int P1 = 0; + do + { + // Set pollutant + error = swmm_setNodePollut(1, SM_NODEQUAL, P1, 1.234); + BOOST_REQUIRE(error == ERR_NONE); + + // Route Model Forward + error = swmm_step(&elapsedTime); + + // Get pollutant + error = swmm_getNodePollut(1, SM_NODEQUAL, &node_qual, &length); + BOOST_REQUIRE(error == ERR_NONE); + + // Check + BOOST_CHECK_CLOSE(node_qual[P1], 1.234, 0.001); + + }while (elapsedTime != 0 && !error); + BOOST_REQUIRE(error == ERR_NONE); + swmm_end(); + + // check mass balance error less than 1% + swmm_getMassBalErr(&runoff_error, &flow_error, &qual_error); + BOOST_CHECK(abs(qual_error) <= 1.0); +} + + +// Testing Pollutant Setter - Node - Stepwise and Mass balance greater than inflow concentration of 10 +BOOST_FIXTURE_TEST_CASE(set_node_pollutant_stepwise_values_2, FixtureBeforeStep_Pollut_Node){ + + int error; + double* node_qual; + float runoff_error, flow_error, qual_error; + double elapsedTime = 0.0; + int length; + + // Pollutant IDs + int P1 = 0; + do + { + // Set pollutant + error = swmm_setNodePollut(1, SM_NODEQUAL, P1, 50.0); + BOOST_REQUIRE(error == ERR_NONE); + + // Route Model Forward + error = swmm_step(&elapsedTime); + + // Get pollutant + error = swmm_getNodePollut(1, SM_NODEQUAL, &node_qual, &length); + BOOST_REQUIRE(error == ERR_NONE); + + // Check + BOOST_CHECK_CLOSE(node_qual[P1], 50.0, 0.001); + + }while (elapsedTime != 0 && !error); + BOOST_REQUIRE(error == ERR_NONE); + swmm_end(); + + // check mass balance error less than 1% + swmm_getMassBalErr(&runoff_error, &flow_error, &qual_error); + BOOST_CHECK(abs(qual_error) <= 1.0); +} + + + +// Testing Pollutant Setter - Link - Stepwise - mass balance concentation less than 10 +BOOST_FIXTURE_TEST_CASE(set_link_pollutant_stepwise_values, FixtureBeforeStep_Pollut_Link){ + + int error, link_ind, node_ind; + int step = 0; + double* link_qual; + double* node_qual; + double elapsedTime = 0.0; + double node_inflow; + float runoff_error, flow_error, qual_error; + char linkid[] = "C1"; + char nodeid[] = "J1"; + int length; + + // Pollutant ID + int P1 = 0; + + error = swmm_getObjectIndex(SM_LINK, linkid, &link_ind); + BOOST_REQUIRE(error == ERR_NONE); + error = swmm_getObjectIndex(SM_NODE, nodeid, &node_ind); + BOOST_REQUIRE(error == ERR_NONE); + + do{ + if (step > 1000 && step < 2000){ + // Set pollutant in link and check the pollutant in the node + error = swmm_setLinkPollut(link_ind, SM_LINKQUAL, P1, 1.0); + BOOST_REQUIRE(error == ERR_NONE); + } + // Route Model Forward + error = swmm_step(&elapsedTime); + BOOST_REQUIRE(error == ERR_NONE); + if (step > 1500 && step < 2000) // Wait for water to reach node + { + // Get infows concentration in node + error = swmm_getNodePollut(node_ind, SM_NODEQUAL, &node_qual, &length); + BOOST_REQUIRE(error == ERR_NONE); + + error = swmm_getLinkPollut(link_ind, SM_LINKQUAL, &link_qual, &length); + + // Check + BOOST_CHECK_CLOSE(node_qual[P1], link_qual[P1], 0.01); + }step += 1; + + }while (elapsedTime != 0 && !error); + BOOST_REQUIRE(error == ERR_NONE); + swmm_end(); + + // check mass balance error less than 5% + swmm_getMassBalErr(&runoff_error, &flow_error, &qual_error); + BOOST_CHECK(abs(qual_error) <= 5.0); +} + + +// Testing Pollutant Setter - Link - Stepwise - mass balance concentation greater than 10 +BOOST_FIXTURE_TEST_CASE(set_link_pollutant_stepwise_values_2, FixtureBeforeStep_Pollut_Link){ + + int error, link_ind, node_ind; + int step = 0; + double* link_qual; + double* node_qual; + double elapsedTime = 0.0; + double node_inflow; + float runoff_error, flow_error, qual_error; + char linkid[] = "C1"; + char nodeid[] = "J1"; + int length; + + // Pollutant ID + int P1 = 0; + + error = swmm_getObjectIndex(SM_LINK, linkid, &link_ind); + BOOST_REQUIRE(error == ERR_NONE); + error = swmm_getObjectIndex(SM_NODE, nodeid, &node_ind); + BOOST_REQUIRE(error == ERR_NONE); + + do{ + if (step > 1000 & step < 2000){ + // Set pollutant in link and check the pollutant in the node + error = swmm_setLinkPollut(link_ind, SM_LINKQUAL, P1, 20.0); + BOOST_REQUIRE(error == ERR_NONE); + } + // Route Model Forward + error = swmm_step(&elapsedTime); + BOOST_REQUIRE(error == ERR_NONE); + + // Wait for water to reach node + if (step > 1500 & step < 2000){ + // Get infows concentration in node + error = swmm_getNodePollut(node_ind, SM_NODEQUAL, &node_qual, &length); + BOOST_REQUIRE(error == ERR_NONE); + + error = swmm_getLinkPollut(link_ind, SM_LINKQUAL, &link_qual, &length); + + // Check + BOOST_CHECK_CLOSE(node_qual[P1], link_qual[P1], 0.01); + }step += 1; + + }while (elapsedTime != 0 && !error); + BOOST_REQUIRE(error == ERR_NONE); + swmm_end(); + + swmm_getMassBalErr(&runoff_error, &flow_error, &qual_error); + BOOST_CHECK(abs(qual_error) <= 5.0); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/solver/test_solver.hpp b/tests/solver/test_solver.hpp index 1d52b21dc..c2617ae9b 100644 --- a/tests/solver/test_solver.hpp +++ b/tests/solver/test_solver.hpp @@ -14,12 +14,16 @@ #ifndef TEST_SOLVER_HPP #define TEST_SOLVER_HPP +extern "C" { #include "swmm5.h" #include "toolkit.h" - +} // Add shared data paths here #define DATA_PATH_INP "test_example1.inp" +#define DATA_PATH_INP_POLLUT_NODE "node_constantinflow_constanteffluent.inp" +#define DATA_PATH_INP_POLLUT_LINK "link_constantinflow.inp" +#define DATA_PATH_INP_LINK_DIR "link_flow_dir.inp" #define DATA_PATH_RPT "tmp.rpt" #define DATA_PATH_OUT "tmp.out" @@ -68,6 +72,37 @@ struct FixtureBeforeEnd{ } }; +struct FixtureBeforeStep_Pollut_Node{ + FixtureBeforeStep_Pollut_Node() { + swmm_open(DATA_PATH_INP_POLLUT_NODE, DATA_PATH_RPT, DATA_PATH_OUT); + swmm_start(0); + } + ~FixtureBeforeStep_Pollut_Node() { + swmm_close(); + } +}; + +struct FixtureBeforeStep_Pollut_Link{ + FixtureBeforeStep_Pollut_Link() { + swmm_open(DATA_PATH_INP_POLLUT_LINK, DATA_PATH_RPT, DATA_PATH_OUT); + swmm_start(0); + } + ~FixtureBeforeStep_Pollut_Link() { + swmm_close(); + } +}; + +struct FixtureBeforeStep_Flow_Dir{ + FixtureBeforeStep_Flow_Dir() { + swmm_open(DATA_PATH_INP_LINK_DIR, DATA_PATH_RPT, DATA_PATH_OUT); + swmm_start(0); + } + ~FixtureBeforeStep_Flow_Dir() { + swmm_close(); + } +}; + + // Declare shared test predicates here boost::test_tools::predicate_result check_cdd_double(std::vector& test, std::vector& ref, long cdd_tol); diff --git a/tests/solver/test_toolkit.cpp b/tests/solver/test_toolkit.cpp index 0ed1f013e..6ffd015c6 100644 --- a/tests/solver/test_toolkit.cpp +++ b/tests/solver/test_toolkit.cpp @@ -946,7 +946,43 @@ BOOST_FIXTURE_TEST_CASE(get_result_during_sim, FixtureBeforeStep){ swmm_end(); } +// Testing link flow direction is accounted for in link result getter +BOOST_FIXTURE_TEST_CASE(test_flow_dir_during_sim, FixtureBeforeStep_Flow_Dir){ + int error, step_ind; + int neg_lnk_ind, pos_lnk_ind; + double val; + double elapsedTime = 0.0; + + char neglnkid[] = "negative"; + char poslnkid[] = "positive"; + + error = swmm_getObjectIndex(SM_LINK, poslnkid, &pos_lnk_ind); + BOOST_REQUIRE(error == ERR_NONE); + error = swmm_getObjectIndex(SM_LINK, neglnkid, &neg_lnk_ind); + BOOST_REQUIRE(error == ERR_NONE); + + step_ind = 0; + + do + { + error = swmm_step(&elapsedTime); + + if (step_ind == 200) // (Jan 1, 1998 3:20am) + { + error = swmm_getLinkResult(pos_lnk_ind, SM_LINKFLOW, &val); + BOOST_REQUIRE(error == ERR_NONE); + BOOST_CHECK_CLOSE(val,5.0,0.001); + + error = swmm_getLinkResult(neg_lnk_ind, SM_LINKFLOW, &val); + BOOST_REQUIRE(error == ERR_NONE); + BOOST_CHECK_CLOSE(val,-5.0,0.001); + } + step_ind+=1; + }while (elapsedTime != 0 && !error); + BOOST_REQUIRE(error == ERR_NONE); + swmm_end(); +} // Testing Results Getters (Before End Simulation) // BOOST_FIXTURE_TEST_CASE(get_results_after_sim, FixtureBeforeEnd){ // int error;