Merge branch 'dev'
This commit is contained in:
65
.github/workflows/ccpp.yml
vendored
65
.github/workflows/ccpp.yml
vendored
@@ -1,19 +1,60 @@
|
||||
name: C/C++ CI
|
||||
name: linux
|
||||
|
||||
on: [push]
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 0 1 * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: setup_build_dir
|
||||
run: mkdir buildproducts
|
||||
- name: cmake
|
||||
working-directory: ./buildproducts
|
||||
run: cmake ..
|
||||
- name: make
|
||||
working-directory: ./buildproducts
|
||||
run: make
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup build directory
|
||||
run: mkdir buildproducts
|
||||
|
||||
- name: CMake
|
||||
working-directory: ./buildproducts
|
||||
run: |
|
||||
retry=0
|
||||
max_retries=3
|
||||
until cmake ..; do
|
||||
retry=$((retry+1))
|
||||
echo "Retry $retry/$max_retries..."
|
||||
if [ "$retry" -ge "$max_retries" ]; then
|
||||
echo "CMake configuration failed after $max_retries attempts."
|
||||
exit 1
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
|
||||
- name: Make
|
||||
working-directory: ./buildproducts
|
||||
run: |
|
||||
retry=0
|
||||
max_retries=3
|
||||
until make; do
|
||||
retry=$((retry+1))
|
||||
echo "Retry $retry/$max_retries..."
|
||||
if [ "$retry" -ge "$max_retries" ]; then
|
||||
echo "Make build failed after $max_retries attempts."
|
||||
exit 1
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
|
||||
- name: Copy header files to build directory
|
||||
run: |
|
||||
cp include/epanet2.h buildproducts/
|
||||
cp include/epanet2_2.h buildproducts/
|
||||
cp include/epanet2_enums.h buildproducts/
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: libepanet-output
|
||||
path: buildproducts/
|
||||
|
||||
60
.github/workflows/macos.yml
vendored
Normal file
60
.github/workflows/macos.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
name: macOS
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 0 1 * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup build directory
|
||||
run: mkdir buildproducts
|
||||
|
||||
- name: CMake
|
||||
working-directory: ./buildproducts
|
||||
run: |
|
||||
retry=0
|
||||
max_retries=3
|
||||
until cmake ..; do
|
||||
((retry++))
|
||||
echo "Retry $retry/$max_retries..."
|
||||
if [ "$retry" -ge "$max_retries" ]; then
|
||||
echo "CMake configuration failed after $max_retries attempts."
|
||||
exit 1
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
|
||||
- name: Make
|
||||
working-directory: ./buildproducts
|
||||
run: |
|
||||
retry=0
|
||||
max_retries=3
|
||||
until make; do
|
||||
((retry++))
|
||||
echo "Retry $retry/$max_retries..."
|
||||
if [ "$retry" -ge "$max_retries" ]; then
|
||||
echo "Make build failed after $max_retries attempts."
|
||||
exit 1
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
|
||||
- name: Copy header files to build directory
|
||||
run: |
|
||||
cp include/epanet2.h buildproducts/
|
||||
cp include/epanet2_2.h buildproducts/
|
||||
cp include/epanet2_enums.h buildproducts/
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: libepanet-output
|
||||
path: buildproducts/
|
||||
50
.github/workflows/win32.yml
vendored
Normal file
50
.github/workflows/win32.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: epanet2-win32
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 0 1 * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup build directory
|
||||
run: mkdir buildproducts
|
||||
|
||||
- name: CMake
|
||||
working-directory: ./buildproducts
|
||||
shell: pwsh
|
||||
run: |
|
||||
$retryCount = 0
|
||||
$maxRetries = 3
|
||||
do {
|
||||
cmake .. -A Win32 && cmake --build . --config Release
|
||||
if ($LASTEXITCODE -eq 0) { break }
|
||||
Write-Host "Retry $($retryCount + 1)/$maxRetries..."
|
||||
Start-Sleep -Seconds 10
|
||||
$retryCount++
|
||||
} while ($retryCount -lt $maxRetries)
|
||||
if ($retryCount -eq $maxRetries) {
|
||||
Write-Host "CMake build failed after $maxRetries attempts."
|
||||
exit 1
|
||||
}
|
||||
|
||||
- name: Copy header files to build directory
|
||||
run: |
|
||||
copy include\epanet2.h buildproducts\bin\Release
|
||||
copy include\epanet2_2.h buildproducts\bin\Release
|
||||
copy include\epanet2_enums.h buildproducts\bin\Release
|
||||
shell: cmd
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: epanet2-win32
|
||||
path: buildproducts\bin\Release
|
||||
51
.github/workflows/win64.yml
vendored
Normal file
51
.github/workflows/win64.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
name: epanet2-win64
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 0 1 * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup build directory
|
||||
run: mkdir buildproducts
|
||||
|
||||
- name: CMake
|
||||
working-directory: ./buildproducts
|
||||
shell: pwsh
|
||||
run: |
|
||||
$retryCount = 0
|
||||
$maxRetries = 3
|
||||
do {
|
||||
cmake .. -A x64 # Specify architecture for 64-bit
|
||||
cmake --build . --config Release
|
||||
if ($LASTEXITCODE -eq 0) { break }
|
||||
Write-Host "Retry $($retryCount + 1)/$maxRetries..."
|
||||
Start-Sleep -Seconds 10
|
||||
$retryCount++
|
||||
} while ($retryCount -lt $maxRetries)
|
||||
if ($retryCount -eq $maxRetries) {
|
||||
Write-Host "CMake build failed after $maxRetries attempts."
|
||||
exit 1
|
||||
}
|
||||
|
||||
- name: Copy header files to build directory
|
||||
run: |
|
||||
copy include\epanet2.h buildproducts\bin\Release
|
||||
copy include\epanet2_2.h buildproducts\bin\Release
|
||||
copy include\epanet2_enums.h buildproducts\bin\Release
|
||||
shell: cmd
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: epanet2-win64
|
||||
path: buildproducts\bin\Release
|
||||
65
AUTHORS
65
AUTHORS
@@ -1,27 +1,60 @@
|
||||
# Authors ordered by first contribution.
|
||||
# Authors ordered alphabetically.
|
||||
|
||||
Authors with Contributions in the Public Domain:
|
||||
|
||||
Lewis Rossman <LRossman@cinci.rr.com>
|
||||
Michael Tryby <tryby.michael@epa.gov>
|
||||
|
||||
Authors with Contributions Subject to Copyright (see LICENSE):
|
||||
Version 2.0
|
||||
Lewis Rossman <LRossman@cinci.rr.com>
|
||||
|
||||
Sam Hatchett <samhatchett@gmail.com>
|
||||
Feng Shang <fshang>
|
||||
James Uber <jim@citilogics.com>
|
||||
Tom Taxon <tntaxon@anl.gov>
|
||||
Hyoungmin Woo <hyoungmin.woo@gmail.com>
|
||||
Jinduan Chen <jinduan.uc@gmail.com>
|
||||
Yunier Soad <yunier.soad@gmail.com>
|
||||
Mike Kane <muke195@gmail.com>
|
||||
Authors with Contributions Subject to Copyright (see LICENSE):
|
||||
Except where noted.
|
||||
|
||||
Version 2.1
|
||||
Jinduan Chen <jinduan.uc@gmail.com>
|
||||
Maurizio Cingi <mrzcng2@gmail.com>
|
||||
Demetrios Eliades <eldemet@gmail.com>
|
||||
Will Furnass <will@thearete.co.uk>
|
||||
Steffen Macke <sdteffen@sdteffen.de>
|
||||
Milad Ghiami <milad.ghiami67@gmail.com>
|
||||
Sam Hatchett <samhatchett@gmail.com>
|
||||
Mike Kane <muke195@gmail.com>
|
||||
Marios Kyriakou <mariosmsk@gmail.com>
|
||||
Elad Salomons <selad@optiwater.com>
|
||||
Maurizio Cingi <mrzcng2@gmail.com>
|
||||
Bryant McDonnell <bemcdonnell@gmail.com>
|
||||
Steffen Macke <sdteffen@sdteffen.de>
|
||||
Angela Marchi <angela.marchi@adelaide.edu.au>
|
||||
Bryant McDonnell <bemcdonnell@gmail.com>
|
||||
Lew Rossman <LRossman@cinci.rr.com>
|
||||
Elad Salomons <selad@optiwater.com>
|
||||
Feng Shang <fengshang72@gmail.com>
|
||||
Yunier Soad <yunier.soad@gmail.com>
|
||||
Tom Taxon <tntaxon@anl.gov>
|
||||
Michael Tryby <tryby.michael@epa.gov> (Contributions in the Public Domain)
|
||||
James Uber <jim@citilogics.com>
|
||||
Hyoungmin Woo <hyoungmin.woo@gmail.com>
|
||||
|
||||
Version 2.2
|
||||
Demetrios Eliades <eldemet@gmail.com>
|
||||
Sam Hatchett <samhatchett@gmail.com>
|
||||
Abel Heinsbroek <mail@abelheinsbroek.nl>
|
||||
Marios Kyriakou <mariosmsk@gmail.com>
|
||||
Lewis Rossman <LRossman@cinci.rr.com>
|
||||
Elad Salomons <selad@optiwater.com>
|
||||
Markus Sunela <markus.sunela@fluidit.fi>
|
||||
Milad Ghiami <milad-ghiami@users.noreply.github.com>
|
||||
Michael Tryby <tryby.michael@epa.gov> (Contributions in the Public Domain)
|
||||
|
||||
Version 2.3
|
||||
Luke Butler <lukepbutler@gmail.com>
|
||||
Demetrios Eliades <eldemet@gmail.com>
|
||||
Sam Hatchett <samhatchett@gmail.com>
|
||||
Abel Heinsbroek <mail@abelheinsbroek.nl>
|
||||
Robert Janke <janke.robert@epa.gov>
|
||||
Marios Kyriakou <mariosmsk@gmail.com>
|
||||
Corey McNeish
|
||||
0tkl <tkl.zhaoqing@gmail.com>
|
||||
Lewis Rossman <LRossman@cinci.rr.com>
|
||||
Elad Salomons <selad@optiwater.com>
|
||||
Alex Sinske
|
||||
Sahand Tashak
|
||||
Yu Chun Tsao
|
||||
James Uber <jim@citilogics.com>
|
||||
Oscar Vegas Niño <ovegas141279@gmail.com>
|
||||
Dennis Zanutto <dennis.zanutto@kwrwater.nl>
|
||||
38
BUILDING.md
38
BUILDING.md
@@ -1,6 +1,9 @@
|
||||
# Building
|
||||
|
||||
The most straightforward way to build the EPANET files is by using `CMake` ([https://cmake.org/](https://cmake.org/)). `CMake` is a cross-platform build tool that generates platform native build systems that can be used with your compiler of choice. It uses a generator concept to represent different build tooling. `CMake` automatically detects the platform it is running on and generates the appropriate makefiles for the platform default compiler. Different generators can also be specified.
|
||||
|
||||
The project's `CMake` file (`CMakeLists.txt`) is located in its root directory and supports builds for Linux, Mac OS and Windows. To build the EPANET library and its command line executable using `CMake`, first open a console window and navigate to the project's root directory. Then enter the following commands:
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
@@ -10,10 +13,39 @@ cmake --build . --config Release
|
||||
|
||||
Note: under Windows, the third command should be `cmake .. -A Win32` for a 32-bit build or `cmake .. -A x64` for a 64-bit build when Microsoft Visual Studio is the default compiler.
|
||||
|
||||
For Windows the resulting EPANET toolkit library `epanet2.dll` and its command line executable `runepanet.exe` are placed in the `build\bin\Release` directory. The `build\lib\Release` directory will contain an `epanet2.lib` file which is needed to build C/C++ applications using the Windows version of the library. For Linux and Mac OS the EPANET toolkit shared library `libepanet2.so` appears in the `build/lib` directory and the command line executable `runepanet` is in the `build/bin` directory.
|
||||
For Windows the resulting EPANET toolkit library `epanet2.dll` and its command line executable `runepanet.exe` are placed in the `build\bin\Release` directory. The `build\lib\Release` directory will contain an `epanet2.lib` file which is needed to build C/C++ applications using the Windows version of the library. For Linux and Mac OS the EPANET toolkit shared library `libepanet2.so` appears in the `build/lib` directory and the command line executable `runepanet` is in the `build/bin` directory.
|
||||
|
||||
In addition, two Windows one-click-build scripts are included in the `win_build` directory:
|
||||
|
||||
1. `Makefile2.bat`: this script uses the `CMake` file and requires the build tools for Visual Studio available from [https://visualstudio.microsoft.com/downloads/](https://visualstudio.microsoft.com/downloads/). The Community version will work just fine. This script was tested with Visual Studio 2017 and 2019.
|
||||
2. `Makefile.bat`: this is the legacy build script compatible with Visual Studio 2010 which conforms with the C89 Standard which was the standard EPANET supported from earlier versions. This script requires the installation of Microsoft Windows SDK 7.1 ([https://www.microsoft.com/en-us/download/details.aspx?id=8279](https://www.microsoft.com/en-us/download/details.aspx?id=8279)) and will probably not run correctly on later versions of the SDK. `CMake` is not used in this script.
|
||||
|
||||
These two scripts build EPANET binaries for both the 32 and 64 bit Windows platforms, placing them in the `win_build\32bit` and `win_build\64bit` directories, respectively.
|
||||
|
||||
These two scripts build EPANET binaries for both the 32 and 64 bit Windows platforms, placing them in the `win_build\32bit` and `win_build\64bit` directories, respectively.
|
||||
|
||||
A tutorial on [building OWA EPANET from source on Windows](tools/BuildAndTest.md), including running unit tests and performing regression testing, is also avaiable.
|
||||
|
||||
## Alternative build with Conan
|
||||
Conan is an increasingly popular C/C++ package management suite. To build EPANET using Conan, use the following commands as a starting point:
|
||||
|
||||
```
|
||||
conan build . -s build_type=Release
|
||||
conan export-pkg . -s build_type=Release
|
||||
```
|
||||
|
||||
|
||||
# Testing
|
||||
|
||||
Unit tests have been written using the Boost Unit Testing Framework and other Boost libraries. The tests are compiled into individual executables that automatically perform checks on the EPANET toolkit and output libraries.
|
||||
|
||||
The CMake build system has been configured with a build option for building tests. When enabled (`-DBUILD_TESTS=ON`) the test executables are built and registered with the CTest test runner, the default value for the test build option is off. The location of Boost can also be defined with `-DBOOST_ROOT="%BOOST_ROOT%"` if required.
|
||||
|
||||
To build the test executables for the EPANET library, first open a console window and navigate to the project's root directory. Then enter the following commands:
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DBUILD_TESTS=ON ..
|
||||
cmake --build . --config Release
|
||||
cd tests
|
||||
ctest -C Release --output-on-failure
|
||||
```
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# CMakeLists.txt - CMake configuration file for EPANET 2.0
|
||||
# CMakeLists.txt - CMake configuration file for EPANET 2.3
|
||||
#
|
||||
# CMake is a cross-platform build tool. CMake generates platform native
|
||||
# build systems that can be used with your compiler of choice. CMake uses a
|
||||
@@ -25,21 +25,21 @@
|
||||
# CMake is available at https://cmake.org/download/
|
||||
#
|
||||
|
||||
cmake_minimum_required (VERSION 2.8.8)
|
||||
cmake_minimum_required (VERSION 3.8.0)
|
||||
|
||||
project(EPANET)
|
||||
|
||||
# Append local dir to module search path
|
||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
|
||||
option(BUILD_TESTS "Build tests (requires Boost)" OFF)
|
||||
option(BUILD_PY_LIB "Build library for Python wrapper" OFF)
|
||||
#option(BUILD_PY_LIB "Build library for Python wrapper" OFF)
|
||||
option(BUILD_COVERAGE "Build library for coverage" OFF)
|
||||
|
||||
|
||||
IF (NOT BUILD_PY_LIB)
|
||||
#IF (NOT BUILD_PY_LIB)
|
||||
add_subdirectory(run)
|
||||
ENDIF (NOT BUILD_PY_LIB)
|
||||
#ENDIF (NOT BUILD_PY_LIB)
|
||||
add_subdirectory(src/outfile)
|
||||
|
||||
IF (BUILD_TESTS)
|
||||
@@ -60,17 +60,14 @@ IF (BUILD_TESTS)
|
||||
add_subdirectory(tests/util)
|
||||
ENDIF (BUILD_TESTS)
|
||||
|
||||
|
||||
# Sets the output directory for executables and libraries.
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
|
||||
|
||||
# Sets the position independent code property for all targets
|
||||
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
|
||||
IF (APPLE)
|
||||
set(INSTALL_NAME_DIR @executable_path/../lib)
|
||||
set(CMAKE_MACOSX_RPATH 1)
|
||||
@@ -84,8 +81,6 @@ ENDIF (MSVC)
|
||||
# configure file groups
|
||||
file(GLOB EPANET_SOURCES RELATIVE ${PROJECT_SOURCE_DIR} src/*.c src/util/*.c)
|
||||
file(GLOB EPANET_LIB_ALL RELATIVE ${PROJECT_SOURCE_DIR} src/* src/util/*)
|
||||
# exclude epanet python API from the default build
|
||||
list(REMOVE_ITEM EPANET_LIB_ALL "src/epanet_py.c")
|
||||
source_group("Library" FILES ${EPANET_LIB_ALL})
|
||||
|
||||
# the shared library
|
||||
@@ -96,7 +91,13 @@ IF(MSVC AND "${CMAKE_VS_PLATFORM_NAME}" MATCHES "(Win32)")
|
||||
add_library(epanet2 SHARED ${EPANET_LIB_ALL} ${PROJECT_SOURCE_DIR}/include/epanet2.def)
|
||||
set_source_files_properties(${PROJECT_SOURCE_DIR}/include/epanet2.def PROPERTIES_HEADER_FILE_ONLY TRUE)
|
||||
ELSE(TRUE)
|
||||
add_library(epanet2 SHARED ${EPANET_LIB_ALL})
|
||||
add_library(epanet2 ${EPANET_LIB_ALL})
|
||||
ENDIF(MSVC AND "${CMAKE_VS_PLATFORM_NAME}" MATCHES "(Win32)")
|
||||
|
||||
target_include_directories(epanet2 PUBLIC ${PROJECT_SOURCE_DIR}/include)
|
||||
|
||||
install(TARGETS epanet2 DESTINATION .)
|
||||
install(TARGETS runepanet DESTINATION .)
|
||||
install(FILES ./include/epanet2.h DESTINATION .)
|
||||
install(FILES ./include/epanet2_2.h DESTINATION .)
|
||||
install(FILES ./include/epanet2_enums.h DESTINATION .)
|
||||
|
||||
6
LICENSE
6
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 (see AUTHORS)
|
||||
Copyright (c) 2019 (See AUTHORS)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -9,8 +9,8 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
The above copyright notice, list of authors, and this permission notice shall
|
||||
be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
||||
13
README.md
13
README.md
@@ -3,9 +3,10 @@ OWA-EPANET
|
||||
|
||||
## Build Status
|
||||
[](https://ci.appveyor.com/project/OpenWaterAnalytics/epanet)
|
||||
[](https://travis-ci.org/OpenWaterAnalytics/EPANET)
|
||||
|
||||
[](https://codecov.io/gh/OpenWaterAnalytics/EPANET)
|
||||
[](https://github.com/OpenWaterAnalytics/EPANET/actions/workflows/ccpp.yml)
|
||||
[](https://github.com/OpenWaterAnalytics/EPANET/actions/workflows/macos.yml)
|
||||
[](https://github.com/OpenWaterAnalytics/EPANET/actions/workflows/win32.yml)
|
||||
[](https://github.com/OpenWaterAnalytics/EPANET/actions/workflows/win64.yml)
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
@@ -17,7 +18,7 @@ Instructions for building the OWA-EPANET Toolkit's function library as well as i
|
||||
|
||||
## USAGE
|
||||
|
||||
See the [full documentation](http://wateranalytics.org/EPANET/) of the OWA-EPANET API, along with examples of how to use the toolkit for water distribution system analysis. Additional information may be found on this project's [Wiki](https://github.com/openwateranalytics/epanet/wiki).
|
||||
See the [full documentation](http://wateranalytics.org/EPANET/) of the OWA-EPANET API, along with examples of how to use the toolkit for water distribution system analysis. Additional information may be found on this project's [Wiki](https://github.com/OpenWaterAnalytics/EPANET/wiki).
|
||||
|
||||
## CONTRIBUTING
|
||||
|
||||
@@ -28,6 +29,6 @@ Everyone is welcome to participate in this project. Whether you are helping othe
|
||||
The **Open Water Analytics** (OWA) Community is an international group of EPANET developers and users, whose objective is to provide group interaction and coordinated development of the EPANET codebase, to ensure that important new user interface and algorithmic features are identified and that these features progress efficiently from prototype code to production implementations. OWA is actively maintaining OWA-EPANET, a community-supported branch of USEPA EPANET, since May 2014. The full list of individuals contributing to this project can be found [here](https://github.com/OpenWaterAnalytics/EPANET/blob/dev/AUTHORS).
|
||||
|
||||
## DISCLAIMER
|
||||
Although OWA is not formally affiliated with nor endorsed by USEPA, this project has been a collaborative effort between the two that builds upon and extends the USEPA’s legacy EPANET 2.0 code base. For the last "official" release of EPANET please go to the [USEPA website](http://www2.epa.gov/water-research/epanet).
|
||||
Although OWA is not formally affiliated with nor endorsed by USEPA, this project has been a collaborative effort between the two that builds upon and extends the USEPA’s legacy EPANET 2.0 code base. For the last "official" release of EPANET please go to the [USEPA website](https://www.epa.gov/water-research/epanet).
|
||||
|
||||
For more general community discussion, FAQ, and roadmapping of the project, please go to the [Community Forum](http://community/wateranalytics.org).
|
||||
For more general community discussion of the project, please go to [OWA Discussions](https://github.com/orgs/OpenWaterAnalytics/discussions).
|
||||
|
||||
138
ReleaseNotes2_3.md
Normal file
138
ReleaseNotes2_3.md
Normal file
@@ -0,0 +1,138 @@
|
||||
>
|
||||
## Release Notes for EPANET 2.3
|
||||
|
||||
This document describes the changes and updates that have been made in version 2.3 of EPANET.
|
||||
|
||||
### New Features
|
||||
|
||||
- A `EN_setcurvetype` function was added to allow API clients to set a curve's type (e.g., `EN_PUMP_CURVE,` `EN_VOLUME_CURVE,` etc.).
|
||||
|
||||
- A `EN_setvertex` function was added to allow API clients to change the coordinates of a single link vertex.
|
||||
|
||||
- Support has been added for FAVAD (Fixed And Variable Area Discharge) modeling of pipe leaks:
|
||||
- A new `[LEAKAGE]` section has been added to the input file format where each line contains the ID name of a pipe, its leak area in sq. mm per 100 length units, and its leak expansion rate in sq. mm per unit of pressure head.
|
||||
- `EN_LEAK_AREA` and `EN_LEAK_EXPAN` can be used with the functions `EN_getlinkvalue` and `EN_setlinkvalue` to retrieve and assign values for a pipe's leak area and expansion properties.
|
||||
- `EN_LINK_LEAKAGE` can be used with `EN_getlinkvalue` to retrieve a pipe's leakage rate at a given point in time.
|
||||
- `EN_LEAKAGEFLOW` can be used with `EN_getnodevalue` to retrieve the leakage demand generated at a node from all its connecting pipes at a given point in time.
|
||||
- `EN_LEAKAGELOSS` can be used with `EN_getstatistic` to retrieve the total leakage loss in the system at a given point in time as a percentage of total flow entering the system.
|
||||
|
||||
- Support has been added for reading the `[TAGS]` section of an EPANET input file. In addition:
|
||||
- A newly added `EN_settag` function will assign a Tag to a node or link.
|
||||
- A newly added `EN_gettag` function will retrieve a node or link's Tag.
|
||||
- The existing `EN_saveinpfile` will include saving all node and link tags to file.
|
||||
- A new Flow Balance Report has been added to end of a simulation run's Status Report that lists the various components of the system's total inflow and outflow over the simulation period. It also displays the ratio of outflow to inflow as a check on flow continuity.
|
||||
|
||||
- A new type of valve, a Positional Control Valve (PCV), was added. It uses a valve characteristic curve to relate its loss coefficient to a percentage open setting (parameter - `EN_PCV`).
|
||||
|
||||
- `EN_VALVE_CURVE` can now be used with the `EN_getcurvetype` and `EN_setcurvetype` to get or set the valve position curve.
|
||||
|
||||
- `EN_VALVE_TYPE` can now be used with `EN_getlinkvalue` and `EN_setlinkvalue` to get and set a valve's type. This is the preferred way to change just a valve's type rather than using `EN_setlinktype`.
|
||||
|
||||
- A new set of functions has been added to get information about upcoming time step events. Users will now see what type of event is going to cause the end of a time step to occur. See `EN_timetonextevent`.
|
||||
|
||||
- A new set of functions has been added to allow users to set a reporting callback function. The user-supplied function will receive all output normally directed to the report file.
|
||||
|
||||
- A `EN_EMITBACKFLOW` option was added that either allows emitters to have reverse flow through them (the default) or not.
|
||||
|
||||
- The functions `EN_getnodevalue` and `EN_getlinkvalue` now include the options `EN_NODE_INCONTROL` and `EN_LINK_INCONTROL` to determine whether a node or link appears in any simple or rule-based control.
|
||||
|
||||
- `EN_SET_CLOSED` and `EN_SET_OPEN` constants were added that can be used with `EN_setcontrol` to fix the status of pipes and valves to completely closed or completely open.
|
||||
|
||||
- `EN_STATUS_REPORT` can now be used with `EN_getoption` and `EN_setoption` to get or set the type of status report that EPANET will generate (`EN_NO_REPORT`, `EN_NORMAL_REPORT` or `EN_FULL_REPORT`).
|
||||
|
||||
- `EN_PRESS_UNITS` can now be used with `EN_getoption` and `EN_setoption` to get or set the pressure unit used in EPANET.
|
||||
|
||||
- Decoupled pressure units from the flow unit system, allowing them to be set independently to support mixed-unit conventions (e.g., using LPS for flow and PSI for pressure).
|
||||
|
||||
- The following constants can be used with EN_getnodevalue to retrieve the components of a node's total demand at a given point in time:
|
||||
- `EN_FULLDEMAND` - the consumer demand requested
|
||||
- `EN_DEMANDFLOW` - the consumer demand delivered
|
||||
- `EN_DEMANDDEFICIT` - the difference between the consumer demand requested and delivered
|
||||
- `EN_EMITTERFLOW` - the node's emitter flow
|
||||
- `EN_LEAKAGEFLOW` - the node's leakage flow
|
||||
- `EN_DEMAND` - the sum of the node's consumer demand, emitter flow, and leakage flow
|
||||
|
||||
- Additional API functions for enabling/disabling controls and rules were added (`EN_getcontrolenabled`, `EN_setcontrolenabled`, `EN_getruleenabled`, `EN_setruleenabled`). A new keyword `DISABLED` is added to the end of a control or rule statement in an EPANET input file to indicate that the control is disabled.
|
||||
|
||||
- The `EN_openX` function has been added to enable the opening of input files with formatting errors through the API. This allows users to continue using toolkit functions even when such errors are present.
|
||||
|
||||
- The `EN_getnodesvalues` and `EN_getlinksvalues` were added to retrieve a property value for all nodes or links in the network.
|
||||
|
||||
- Support was added for cubic meters per second (`EN_CMS`) flow units.
|
||||
|
||||
- A header file for binding C# to the Toolkit has been added.
|
||||
|
||||
- Support was added for Conan dependency manager.
|
||||
|
||||
### Feature Updates
|
||||
|
||||
- The check for at least two nodes, one tank/reservoir and no unconnected junction nodes was moved from `EN_open` to `EN_openH` and `EN_openQ` so that partial network data files could be opened by the toolkit.
|
||||
|
||||
- The indices of a General Purpose Valve (GPV) and a Positional Control Valve (PCV) were added to the list of editable Link Properties using the symbolic constant names `EN_GPV_CURVE` and `EN_PCV_CURVE`, respectively.
|
||||
|
||||
- The `EN_getlinkvalue` and `EN_setlinkvalue` functions were updated to get and set the values of `EN_GPV_CURVE` and `EN_PCV_CURVE`.
|
||||
|
||||
- Negative pressure values for `EN_SETTING` are now permitted in the `EN_setlinkvalue` function.
|
||||
|
||||
- The `EN_STARTTIME` parameter was added into the `EN_settimeparam` function.
|
||||
|
||||
- A `EN_DEMANDPATTERN` parameter was added as the index of the default time pattern used by demands with no specific pattern assigned. It can be set or retrieved with the `EN_setoption` and `EN_getoption` functions, respectively, and is saved to the file when the `EN_saveinpfile` function is called.
|
||||
|
||||
- The `EN_getaveragepatternvalue` function will now accept a pattern index of zero which represents the constant pattern assigned to junction demands by default.
|
||||
|
||||
- Improved updating and convergence tests were added to pressure-dependent demand analysis.
|
||||
|
||||
- Improved checks to prevent outflow from empty tanks or inflow to full (non-overflow) tanks, including the case where a link is connected to a pair of tanks, were added.
|
||||
|
||||
- The `EN_INITSETTING` option in function `EN_setlinkvalue` will now save the setting value so that if a new simulation is begun or if `EN_saveinpfile` is called the saved initial setting will remain in effect rather than whatever setting a simulation may have ended with.
|
||||
|
||||
- A new error code `263 - node is not a tank` is returned when `EN_settankdata` or `EN_setnodevalue` attempts to set a tank-only parameter for a non-tank node.
|
||||
|
||||
- Errors in node and link vertex coordinates are now ignored when reading an EPANET input file.
|
||||
|
||||
- Only non-zero demands are now included in the `[DEMANDS]` section of the input file produced by `EN_saveinpfile`.
|
||||
|
||||
- Setting the demand multiplier within the `[DEMANDS]` section of INP has been depreciated, please use `DEMAND MULTIPLIER` inside `[OPTIONS]` instead.
|
||||
|
||||
- Continuous barrier functions were added to constrain emitter flows to allowable values.
|
||||
|
||||
- The CI regression test protocol was modified by:
|
||||
- changing the absolute tolerance used to compare the closeness of test results to benchmark values from 0 to 0.0001
|
||||
- dropping the "correct decimal digits" test
|
||||
- dropping the check for identical status report content since it prevents accepting code changes that produce more accurate solutions in fewer iterations.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- The adjustment of a tank's minimum volume (`Vmin`) when its parameters are changed using `EN_setnodevalue` or `EN_settankdata` has been corrected.
|
||||
|
||||
- A pump whose status is set to CLOSED in the input file now also has its speed setting set to zero which allows a simple pressure control to activate the pump correctly.
|
||||
|
||||
- A failure to raise an error condition for a non-positive pipe roughness in the input file has been fixed.
|
||||
|
||||
- The calculation of head loss gradient for low flow conditions was corrected.
|
||||
|
||||
- A possible loss of network connectivity when evaluating a Pressure Sustaining Valve was prevented.
|
||||
|
||||
- Having the implied loss coefficient for an active Flow Control Valve be less than its fully opened value was prevented.
|
||||
|
||||
- An incorrect tank elevation value set using `EN_settankdata` with SI units has been fixed.
|
||||
|
||||
- An error is no longer raised when a minor loss coefficient of zero is assigned in `EN_setlinkvalue(ph, index, EN_MINORLOSS, 0)`.
|
||||
|
||||
- The incorrect display of unconnected nodes has been fixed.
|
||||
|
||||
- The function `EN_saveinpfile` was corrected for simple controls on GPV's by saving their status instead of the index of their head loss curve.
|
||||
|
||||
- The internal Qualflag variable is now adjusted when an EPANET input file has a QUALITY option not equal to NONE and a simulation duration of zero.
|
||||
|
||||
- An EPANET input file with simple timer control that has more than 9 input tokens no longer results in an incorrect hour setting.
|
||||
|
||||
- A possible parser error that could result in a Trace Node ID in an input file not being recognized was fixed.
|
||||
|
||||
- Updated the internal function `getclosedlink` in report.c to use a loop instead of recursion to prevent a stack overflow during the analysis of very large disconnections.
|
||||
|
||||
- Fixed a bug in EN_setnodevalue with EN_EMITTER option that could cause NaN results.
|
||||
|
||||
- A failure to close a temporary hydraulics file between successive simulations of an opened project was fixed.
|
||||
|
||||
- Corrupting the index of a water quality Trace Node when adding or deleting a node was fixed.
|
||||
42
conanfile.py
Normal file
42
conanfile.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from conan import ConanFile
|
||||
from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout
|
||||
|
||||
class EpanetConan(ConanFile):
|
||||
name = "epanet"
|
||||
version = "2.2"
|
||||
description = "EPANET is an industry-standard program for modeling the hydraulic and water quality behavior of water distribution system pipe networks."
|
||||
homepage = "https://github.com/OpenWaterAnalytics/EPANET"
|
||||
url = "https://github.com/OpenWaterAnalytics/EPANET"
|
||||
license = "MIT"
|
||||
|
||||
# Binary configuration
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
options = {"shared": [True, False], "fPIC": [True, False]}
|
||||
default_options = {"shared": False, "fPIC": True}
|
||||
|
||||
exports_sources = "CMakeLists.txt", "src/*", "include/*", "run/*"
|
||||
|
||||
def config_options(self):
|
||||
if self.settings.os == "Windows":
|
||||
del self.options.fPIC
|
||||
|
||||
def layout(self):
|
||||
cmake_layout(self)
|
||||
|
||||
def generate(self):
|
||||
tc = CMakeToolchain(self)
|
||||
tc.generate()
|
||||
|
||||
def build(self):
|
||||
cmake = CMake(self)
|
||||
cmake.configure()
|
||||
cmake.build()
|
||||
|
||||
def package(self):
|
||||
cmake = CMake(self)
|
||||
cmake.install()
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.libdirs = ["lib"]
|
||||
self.cpp_info.libs = ["epanet2"]
|
||||
self.cpp_info.includedirs = ["include"]
|
||||
15958
doc/DataFlow.eps
15958
doc/DataFlow.eps
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
<navindex>
|
||||
<tab type="mainpage" visible="yes" title=""/>
|
||||
<tab type="pages" visible="yes" title="" intro=""/>
|
||||
<tab type="modules" visible="yes" title="API Reference"
|
||||
<tab type="topics" visible="yes" title="API Reference"
|
||||
intro="These topics describe the Toolkit's functions, enumerations, and error/warning codes."/>
|
||||
<tab type="namespaces" visible="yes" title="">
|
||||
<tab type="namespacelist" visible="yes" title="" intro=""/>
|
||||
|
||||
5118
doc/Example2.eps
5118
doc/Example2.eps
File diff suppressed because it is too large
Load Diff
8420
doc/Network.eps
8420
doc/Network.eps
File diff suppressed because it is too large
Load Diff
1556
doc/doxyfile
1556
doc/doxyfile
File diff suppressed because it is too large
Load Diff
2681
doc/doxygen-awesome.css
Normal file
2681
doc/doxygen-awesome.css
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
h1 { font-size:1.5em; }
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
% Latex footer for doxygen 1.8.10
|
||||
%--- End generated contents ---
|
||||
|
||||
% Index
|
||||
\backmatter
|
||||
\newpage
|
||||
\phantomsection
|
||||
\clearemptydoublepage
|
||||
\addcontentsline{toc}{chapter}{Index}
|
||||
\printindex
|
||||
|
||||
\end{document}
|
||||
141
doc/header.tex
141
doc/header.tex
@@ -1,141 +0,0 @@
|
||||
% Latex header for doxygen 1.8.10
|
||||
\documentclass[twoside]{book}
|
||||
|
||||
% Packages required by doxygen
|
||||
\usepackage{fixltx2e}
|
||||
\usepackage{calc}
|
||||
\usepackage{doxygen}
|
||||
\usepackage[export]{adjustbox} % also loads graphicx
|
||||
\usepackage{graphicx}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage{makeidx}
|
||||
\usepackage{multicol}
|
||||
\usepackage{multirow}
|
||||
\PassOptionsToPackage{warn}{textcomp}
|
||||
\usepackage{textcomp}
|
||||
\usepackage[nointegrals]{wasysym}
|
||||
\usepackage[table]{xcolor}
|
||||
|
||||
% Font selection
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage[scaled=.90]{helvet}
|
||||
\usepackage{courier}
|
||||
\usepackage{amssymb}
|
||||
\usepackage{sectsty}
|
||||
\renewcommand{\familydefault}{\sfdefault}
|
||||
\allsectionsfont{%
|
||||
\fontseries{bc}\selectfont%
|
||||
\color{darkgray}%
|
||||
}
|
||||
\renewcommand{\DoxyLabelFont}{%
|
||||
\fontseries{bc}\selectfont%
|
||||
\color{darkgray}%
|
||||
}
|
||||
\newcommand{\+}{\discretionary{\mbox{\scriptsize$\hookleftarrow$}}{}{}}
|
||||
|
||||
% Page & text layout
|
||||
\usepackage{geometry}
|
||||
\geometry{%
|
||||
a4paper,%
|
||||
top=2.5cm,%
|
||||
bottom=2.5cm,%
|
||||
left=2.5cm,%
|
||||
right=2.5cm%
|
||||
}
|
||||
\tolerance=750
|
||||
\hfuzz=15pt
|
||||
\hbadness=750
|
||||
\setlength{\emergencystretch}{15pt}
|
||||
\setlength{\parindent}{0cm}
|
||||
\setlength{\parskip}{0.2cm}
|
||||
\makeatletter
|
||||
\renewcommand{\paragraph}{%
|
||||
\@startsection{paragraph}{4}{0ex}{-1.0ex}{1.0ex}{%
|
||||
\normalfont\normalsize\bfseries\SS@parafont%
|
||||
}%
|
||||
}
|
||||
\renewcommand{\subparagraph}{%
|
||||
\@startsection{subparagraph}{5}{0ex}{-1.0ex}{1.0ex}{%
|
||||
\normalfont\normalsize\bfseries\SS@subparafont%
|
||||
}%
|
||||
}
|
||||
\makeatother
|
||||
|
||||
% Headers & footers
|
||||
\usepackage{fancyhdr}
|
||||
\pagestyle{fancyplain}
|
||||
\fancyhead[LE]{\fancyplain{}{\bfseries\thepage}}
|
||||
\fancyhead[CE]{\fancyplain{}{}}
|
||||
\fancyhead[RE]{\fancyplain{}{\bfseries\leftmark}}
|
||||
\fancyhead[LO]{\fancyplain{}{\bfseries\rightmark}}
|
||||
\fancyhead[CO]{\fancyplain{}{}}
|
||||
\fancyhead[RO]{\fancyplain{}{\bfseries\thepage}}
|
||||
\fancyfoot[LE]{\fancyplain{}{}}
|
||||
\fancyfoot[CE]{\fancyplain{}{}}
|
||||
\fancyfoot[RE]{\fancyplain{}{\bfseries\scriptsize OWA-EPANET 2.2 \textcopyright 2019}}
|
||||
\fancyfoot[LO]{\fancyplain{}{\bfseries\scriptsize OWA-EPANET 2.2 \textcopyright 2019}}
|
||||
\fancyfoot[CO]{\fancyplain{}{}}
|
||||
\fancyfoot[RO]{\fancyplain{}{}}
|
||||
\renewcommand{\footrulewidth}{0.4pt}
|
||||
\renewcommand{\chaptermark}[1]{%
|
||||
\markboth{#1}{}%
|
||||
}
|
||||
\renewcommand{\sectionmark}[1]{%
|
||||
\markright{\thesection\ #1}%
|
||||
}
|
||||
|
||||
% Indices & bibliography
|
||||
\usepackage{natbib}
|
||||
\usepackage[titles]{tocloft}
|
||||
\setcounter{tocdepth}{1}
|
||||
\setcounter{secnumdepth}{5}
|
||||
\makeindex
|
||||
|
||||
% Hyperlinks (required, but should be loaded last)
|
||||
\usepackage{ifpdf}
|
||||
\ifpdf
|
||||
\usepackage[pdftex,pagebackref=true]{hyperref}
|
||||
\else
|
||||
\usepackage[ps2pdf,pagebackref=true]{hyperref}
|
||||
\fi
|
||||
\hypersetup{%
|
||||
colorlinks=true,%
|
||||
linkcolor=blue,%
|
||||
citecolor=blue,%
|
||||
unicode%
|
||||
}
|
||||
|
||||
% Custom commands
|
||||
\newcommand{\clearemptydoublepage}{%
|
||||
\newpage{\pagestyle{empty}\cleardoublepage}%
|
||||
}
|
||||
|
||||
|
||||
%===== C O N T E N T S =====
|
||||
|
||||
\begin{document}
|
||||
|
||||
% Titlepage & ToC
|
||||
\hypersetup{pageanchor=false,
|
||||
bookmarks=true,
|
||||
bookmarksnumbered=true,
|
||||
pdfencoding=unicode
|
||||
}
|
||||
\pagenumbering{roman}
|
||||
\begin{titlepage}
|
||||
\vspace*{7cm}
|
||||
\begin{center}%
|
||||
{\Large OWA-EPANET Toolkit\linebreak\linebreak 2.2}\\
|
||||
\vspace*{1cm}
|
||||
{\large January 2019}\\
|
||||
%\vspace*{0.5cm}
|
||||
%{\small Wed Jan 23 2019 17:57:36}\\
|
||||
\end{center}
|
||||
\end{titlepage}
|
||||
\clearemptydoublepage
|
||||
\tableofcontents
|
||||
\clearemptydoublepage
|
||||
\pagenumbering{arabic}
|
||||
\hypersetup{pageanchor=true}
|
||||
|
||||
%--- Begin generated contents ---
|
||||
17
doc/main.dox
17
doc/main.dox
@@ -6,7 +6,6 @@ EPANET is a program that performs extended period simulation of hydraulic and wa
|
||||
<table style = "border: 0px solid black">
|
||||
<tr><td style="vertical-align: top">
|
||||
@image html DistributionSystem.png
|
||||
@image latex DistributionSystem.eps
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
@@ -17,6 +16,7 @@ The OWA-EPANET Toolkit is an open-source version of the original EPANET Toolkit
|
||||
- allowing networks to be built completely from function calls instead of from an input file
|
||||
- allowing multiple projects to be analyzed in parallel in a thread-safe manner
|
||||
- adding the ability to use pressure dependent demands in hydraulic analyses
|
||||
- adding the ability to model fixed and variable area leakage in pipes
|
||||
- producing more robust results with regard to hydraulic convergence, low/zero flow conditions, and water quality mass balance
|
||||
- achieving faster run times for single period hydraulic analyses.
|
||||
|
||||
@@ -25,7 +25,7 @@ Before using the OWA-EPANET Toolkit one should be familiar with the way that EPA
|
||||
- @subpage DataFlow "Data Flow Diagram"
|
||||
- @subpage ToolkitVersions "Toolkit Versions"
|
||||
|
||||
More detailed information can be obtained from reading the <a href="https://nepis.epa.gov/Adobe/PDF/P1007WWU.pdf">EPANET 2 Users Manual</a>.
|
||||
More detailed information can be obtained from reading the <a href="https://epanet22.readthedocs.io/en/latest/index.html">EPANET 2 Users Manual</a>.
|
||||
|
||||
__Note:__ <a href="https://github.com/OpenWaterAnalytics">OWA (Open Water Analytics)</a> exists on GitHub as an open community for the exchange of information and ideas related to computing in the water & wastewater industries. Its activities and code projects are neither affiliated with nor endorsed by the USEPA.
|
||||
*/
|
||||
@@ -38,7 +38,6 @@ EPANET models a pipe network as a collection of links connected to nodes. The li
|
||||
<table style = "border: 0px solid black">
|
||||
<tr><td>
|
||||
@image html Network.png
|
||||
@image latex Network.eps
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
@@ -52,22 +51,21 @@ intervals of time
|
||||
- data curves that describe relationships between two quantities, such as head versus flow for pumps and
|
||||
volume versus water level for tanks
|
||||
- simple controls that adjust a link's setting (such as a pump's status) based on node pressure, tank
|
||||
level, elapsed time, ot time of day
|
||||
level, elapsed time, or time of day
|
||||
- rule-based controls that consist of one or more premises that if true result in one set of actions
|
||||
being taken and if false result in a different set of actions being taken
|
||||
- water quality sources that introduce a chemical constituent into the network at specified nodes.
|
||||
|
||||
An EPANET model also contains a number of analysis options that specify:
|
||||
- the project's flow units which in turn determines its unit system (US or SI)
|
||||
- the formula used to compute head loss
|
||||
- the formula used to compute pipe head loss as a function of flow rate
|
||||
- whether to use a demand driven or a pressure driven analysis
|
||||
- hydraulic convergence criteria
|
||||
- hydraulic convergence criteria and water quality tolerances
|
||||
- time steps used for hydraulic, water quality and reporting
|
||||
- the type of water quality analysis to perform (chemical reaction, source tracing or water age)
|
||||
- global values for chemical reaction coefficients that can be overridden for individual pipes
|
||||
- global values for energy usage parameters that can be overridden for individual pumps.
|
||||
|
||||
Please refer to the <a href="https://nepis.epa.gov/Adobe/PDF/P1007WWU.pdf">EPANET 2 Users Manual</a>
|
||||
Please refer to the <a href="https://epanet22.readthedocs.io/en/latest/index.html">EPANET 2 Users Manual</a>
|
||||
for more information on EPANET's data model.
|
||||
*/
|
||||
|
||||
@@ -79,7 +77,6 @@ The EPANET Toolkit contains separate code modules for network building, hydrauli
|
||||
<table style = "border: 0px solid black">
|
||||
<tr><td>
|
||||
@image html DataFlow.png
|
||||
@image latex DataFlow.eps
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
@@ -104,7 +101,7 @@ with single threaded applications.
|
||||
analyzed concurrently.
|
||||
|
||||
Both Toolkit versions utilize identical function names and argument lists with the following exceptions:
|
||||
- The `#include "epanet2.h"` directive must appear in all C/C++ code modules that use the single-threaded library while `#include "epanet2_2.h"` must be used for the multi-threaded library.
|
||||
- The <b>`#include epanet2.h`</b> directive must appear in all C/C++ code modules that use the single-threaded library while <b>`#include epanet2_2.h`</b> must be used for the multi-threaded library. (The "_2" portion of the latter file's name means it is the second of two header files provided and is not a minor release number.)
|
||||
- Function names in the single-threaded library begin with \b EN while those in the multi-threaded
|
||||
library begin with \b EN_ .
|
||||
- The multi-threaded functions contain an additional argument that references a particular network project
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
|
||||
<ul>
|
||||
$navpath
|
||||
<!-- <li class="footer">OWA-EPANET Toolkit 2.2 © 2019</li> -->
|
||||
<!-- <li class="footer">OWA-EPANET Toolkit 2.3 © 2025</li> -->
|
||||
</ul>
|
||||
</div>
|
||||
<!--END GENERATE_TREEVIEW-->
|
||||
|
||||
@@ -1,30 +1,21 @@
|
||||
|
||||
|
||||
## Generating Documentation for OWA-EPANET 2.2
|
||||
## Generating Documentation for OWA-EPANET 2.3
|
||||
|
||||
You must have [Doxygen](http://www.doxygen.nl) installed on your machine to generate documentation for the OWA-EPANET Toolkit. Assuming this is the case, open a terminal window, navigate to the project's `doc` directory and issue the command `doxygen`. This will generate HTML documentation placed in a sub-directory named `html`. From that directory you can launch the `index.html` file to view the full documentation in a web browser.
|
||||
|
||||
To generate a Windows compiled HTML Help file you must have [Microsoft's HTML Help Workshop](https://www.microsoft.com/en-us/download/details.aspx?id=21138) installed. You then need to edit the Doxygen configuration file `doxyfile` as follows:
|
||||
|
||||
1. Change the `GENERATE_HTMLHELP` setting to `YES`.
|
||||
|
||||
2. Enter the location where the Help Workshop system was installed next to the
|
||||
`HHC_LOCATION` setting.
|
||||
|
||||
After running Doxygen again the resulting Help file named `owa-epanet.chm` will appear in the `html` sub-directory.
|
||||
You must have [Doxygen](http://www.doxygen.nl) version 1.13 installed on your machine to generate documentation for the OWA-EPANET Toolkit. Assuming this is the case, open a terminal window, navigate to the project's `doc` directory and issue the command `doxygen`. This will generate HTML documentation placed in a sub-directory named `html`. From that directory you can launch the `index.html` file to view the full documentation in a web browser.
|
||||
|
||||
Doxygen uses the special comments placed in the project's `epanet2_2.h` and `epanet2_enums.h` header files to document EPANET's API. It also uses supplementary material contained in the following files of the project's `doc` directory to generate additional pages of documentation:
|
||||
|
||||
- `main.dox`: generates the *Overview* section.
|
||||
- `usage.dox`: generates the *Usage* section.
|
||||
- `toolkit-usage.dox`: generates the *Usage* section.
|
||||
- `toolkit-examples.dox` : generates the *Examples* section.
|
||||
- `toolkit-files.dox`: generates the *Toolkit Files* section.
|
||||
- `input-file.dox`: generates the *Input File* sub-section.
|
||||
- `toolkit-input.dox`: generates the *Input File* sub-section.
|
||||
- `toolkit-units.dox`: generates the *Measurement Units* section.
|
||||
- `modules.dox`: defines the contents of the *API Reference* section.
|
||||
- `toolkit-topics.dox`: defines the contents of the *API Reference* section.
|
||||
|
||||
Finally, a group of special Doxygen files are used to customize the format of the generated documentation. These include the following:
|
||||
- `doxyfile`: the main Doxygen configuration file
|
||||
- `DoxygenLayout.xml`: sets the title of the automatically generated *Modules* section to *API Reference* and hides the *Files* section in the tree view pane of the document.
|
||||
- `extrastylesheet.css`: reduces the size of the the h1 heading style.
|
||||
- `Doxyfile`: the Doxygen configuration file for HTML output
|
||||
- `DoxygenLayout.xml`: sets the title of the automatically generated *Topics* section to *API Reference* and hides the *Files* section in the tree view pane of the document.
|
||||
- `doxygen-awsome.css`: applies a custom theme provided by [doxygen-awesome](https://github.com/jothepro/doxygen-awesome-css) to produce a more modern visual style for HTML output.
|
||||
- `newfooter.html`: replaces the default Doxygen footer in HTML output with a custom one.
|
||||
|
||||
@@ -47,7 +47,6 @@ Below is a schematic of the network to be built.
|
||||
<table style = "border: 0px solid black">
|
||||
<tr><td>
|
||||
@image html Example2.png
|
||||
@image latex Example2.eps
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ The Prolog section of an EPANET binary output file contains the following data:
|
||||
| Water Quality Option - see @ref EN_QualityType | Integer | 4 |
|
||||
| Traced Node Index | Integer | 4 |
|
||||
| Flow Units Option | Integer | 4 |
|
||||
| Pressure Units Option:<br>0 = psi<br>1 = meters<br>2 = kPa | Integer | 4 |
|
||||
| Pressure Units Option:<br>0 = psi<br>1 = kPa<br>2 = meters<br>3 = bar<br>4 = feet | Integer | 4 |
|
||||
| Report Statistic Type - see @ref EN_StatisticType | Integer | 4 |
|
||||
| Reporting Start Time (sec) | Integer | 4 |
|
||||
| Reporting Time Step (sec) | Integer | 4 |
|
||||
@@ -157,7 +157,8 @@ Developers need to issue an include directive for either `epanet2.h` or `epanet2
|
||||
Several additional function declaration files that provide bindings for other programming languages are included with the Toolkit package:
|
||||
- <b>`epanet2.bas`</b> for Visual Basic for Applications and Visual Basic 6
|
||||
- <b>`epanet2.vb`</b> for Visual Basic .NET
|
||||
- <b>`epanet2.pas`</b> for Delphi Pascal, Free Pascal or Lazarus.
|
||||
- <b>`epanet2.pas`</b> for Delphi Pascal, Free Pascal or Lazarus.
|
||||
- <b>`epanet2.cs`</b> for C#
|
||||
|
||||
These bindings only support the single-threaded version of the Toolkit.
|
||||
*/
|
||||
|
||||
@@ -9,11 +9,12 @@ The file is organized by sections where each section begins with a keyword enclo
|
||||
|@subpage TitlePage "[Title]" |@subpage CurvesPage "[Curves]" |@subpage QualPage "[Quality]" |@subpage OptionsPage "[Options]"|@subpage BackdropPage "[Backdrop]" |
|
||||
|@subpage JuncsPage "[Junctions]"|@subpage PatsPage "[Patterns]" |@subpage ReactsPage "[Reactions]"|@subpage TimesPage "[Times]" |@subpage CoordsPage "[Coordinates]" |
|
||||
|@subpage ResvPage "[Reservoirs]"|@subpage EnergyPage "[Energy]" |@subpage SourcesPage "[Sources]" |@subpage ReportPage "[Report]" |@subpage VertexPage "[Vertices]" |
|
||||
|@subpage TanksPage "[Tanks]" |@subpage StatusPage "[Status]" |@subpage MixingPage "[Mixing]" | |@subpage LabelsPage "[Labels]" |
|
||||
|@subpage TanksPage "[Tanks]" |@subpage StatusPage "[Status]" |@subpage MixingPage "[Mixing]" |@subpage TagsPage "[Tags]" |@subpage LabelsPage "[Labels]" |
|
||||
|@subpage PipesPage "[Pipes]" |@subpage CtrlsPage "[Controls]" | | | |
|
||||
|@subpage PumpsPage "[Pumps]" |@subpage RulesPage "[Rules]" | | | |
|
||||
|@subpage ValvesPage "[Valves]" |@subpage DmndsPage "[Demands]" | | | |
|
||||
|@subpage EmitsPage "[Emitters]" | | | | |
|
||||
|@subpage EmitsPage "[Emitters]" |@subpage LeaksPage "[Leakage]" | | | |
|
||||
|
||||
|
||||
The order of sections is not important. However, whenever a node or link is referred to in a section it must have already been defined in the [JUNCTIONS], [RESERVOIRS], [TANKS], [PIPES], [PUMPS], or [VALVES] sections. Thus it is recommended that these sections be placed first.
|
||||
|
||||
@@ -40,7 +41,7 @@ One line for each control which can be of the form:
|
||||
|
||||
<b> LINK</b> _linkID_ _status_ <b> AT TIME </b> _time_
|
||||
|
||||
<b> LINK</b> _linkID_ _status_ <b> AT CLOCKTIME</b> _clocktime_ <b> AM / PM</b>
|
||||
<b> LINK</b> _linkID_ _status_ <b> AT CLOCKTIME</b> _clocktime_
|
||||
|
||||
where:
|
||||
<table style = "border: 0px solid black">
|
||||
@@ -54,7 +55,8 @@ where:
|
||||
|
||||
__Remarks:__
|
||||
1. Simple controls are used to change link status or settings based on tank water level, junction pressure, time into the simulation or time of day.
|
||||
2. See the notes for the @ref StatusPage section for conventions used in specifying link status and setting, particularly for control valves.
|
||||
2. See the notes for the @ref StatusPage section for conventions used in specifying link status and setting, particularly for control valves.
|
||||
3. Adding the keyword <b>DISABLED</b> at the end of a control statement will indicate that the control is disabled and will not be applied.
|
||||
|
||||
__Examples:__
|
||||
|
||||
@@ -65,8 +67,8 @@ LINK 12 CLOSED IF NODE 23 ABOVE 20
|
||||
;Open Link 12 if the pressure at Node 130 is under 30 psi<br>
|
||||
LINK 12 OPEN IF NODE 130 BELOW 30
|
||||
|
||||
;Pump PUMP02's speed is set to 1.5 at 16 hours into the simulation<br>
|
||||
LINK PUMP02 1.5 AT TIME 16
|
||||
;Disable setting Pump PUMP02's speed to 1.5 at 16 hours into the simulation<br>
|
||||
LINK PUMP02 1.5 AT TIME 16 DISABLED
|
||||
|
||||
;Link 12 is closed at 10 am and opened at 8 pm throughout the simulation<br>
|
||||
LINK 12 CLOSED AT CLOCKTIME 10 AM<br>
|
||||
@@ -92,9 +94,10 @@ __Remarks:__
|
||||
- Head v. Flow for pumps
|
||||
- Efficiency v. Flow for pumps
|
||||
- Volume v. Depth for tanks
|
||||
- Fraction of fully open flow v. fraction open for Positional Control Valves
|
||||
- Head Loss v. Flow for General Purpose Valves
|
||||
2. The points of a curve must be entered in order of increasing X-values (lower to higher).
|
||||
3. If the input file will be used with the Windows version of EPANET, then adding a comment which contains the curve type and description, separated by a colon, directly above the first entry for a curve will ensure that these items appear correctly in EPANET's Curve Editor. Curve types include <B>PUMP, EFFICIENCY, VOLUME</B>, and <B>HEADLOSS</B>. See the examples below.
|
||||
3. If the input file will be used with the Windows version of EPANET, then adding a comment which contains the curve type and description, separated by a colon, directly above the first entry for a curve will ensure that these items appear correctly in EPANET's Curve Editor. Curve types include <B>PUMP, EFFICIENCY, VOLUME, VALVE</B>, and <B>HEADLOSS</B>. See the examples below.
|
||||
|
||||
__Example:__
|
||||
```
|
||||
@@ -234,6 +237,26 @@ J3 115 ;No demand at this junction
|
||||
```
|
||||
*/
|
||||
|
||||
/**
|
||||
@page LeaksPage [LEAKAGE]
|
||||
|
||||
__Purpose:__
|
||||
|
||||
Assigns leakage parameters to individual pipes.
|
||||
|
||||
__Format:__
|
||||
|
||||
A line for each pipe subject to leaking that contains:
|
||||
- Pipe ID label
|
||||
- the area of cracks that leak in sq. mm per 100 units of pipe length (ft or m)
|
||||
- the rate at which cracks expand in sq. mm per unit of pressure head (ft or m)
|
||||
|
||||
__Remarks__
|
||||
1. This section is optional.
|
||||
2. Leak area is the total area of all cracks assumed to exist per 100 feet (or meters) of pipe.
|
||||
3. Experimental values of expansion range between 0 and 0.001 (sq mm)/m depending on pipe material and crack size.
|
||||
*/
|
||||
|
||||
/**
|
||||
@page MixingPage [MIXING]
|
||||
|
||||
@@ -277,7 +300,8 @@ Defines various simulation options.
|
||||
__Formats:__
|
||||
<table style = "border: 0px solid black">
|
||||
<tr><td><B>UNITS</B></td><td><B>CFS / GPM / MGD / IMGD / AFD /</B></td></tr>
|
||||
<tr><td> </td><td><B>LPS / LPM / MLD / CMH / CMD</B></td></tr>
|
||||
<tr><td> </td><td><B>LPS / LPM / MLD / CMS / CMH / CMD</B></td></tr>
|
||||
<tr><td><B>PRESSURE</B></td><td><B>PSI / KPA / METERS / FEET / BAR</B></td></tr>
|
||||
<tr><td><B>HEADLOSS</B></td><td><B>H-W / D-W / C-M</B></td></tr>
|
||||
<tr><td><B>HYDRAULICS</B></td><td><B>USE / SAVE </B><I> filename</I></td></tr>
|
||||
<tr><td><B>VISCOSITY</B></td><td><I>value</I></td></tr>
|
||||
@@ -297,6 +321,7 @@ __Formats:__
|
||||
<tr><td><B>PATTERN</B></td><td><I>id</I></td></tr>
|
||||
<tr><td><B>DEMAND MULTIPLIER</B></td><td><I>value</I></td></tr>
|
||||
<tr><td><B>EMITTER EXPONENT</B></td><td><I>value</I></td></tr>
|
||||
<tr><td><B>EMITTER BACKFLOW</B></td><td><B>YES / NO</B></td></tr>
|
||||
<tr><td><B>QUALITY</B></td><td><B>NONE / CHEMICAL / AGE / TRACE </B><I>nodeID</I></td></tr>
|
||||
<tr><td><B>DIFFUSIVITY</B></td><td><I>value</I></td></tr>
|
||||
<tr><td><B>TOLERANCE</B></td><td><I>value</I></td></tr>
|
||||
@@ -313,10 +338,13 @@ __Definitions:__
|
||||
- \b LPS = liters per second
|
||||
- \b LPM = liters per minute
|
||||
- \b MLD = million liters per day
|
||||
- \b CMS = cubic meters per second
|
||||
- \b CMH = cubic meters per hour
|
||||
- \b CMD = cubic meters per day
|
||||
|
||||
For <b>CFS, GPM, MGD, IMGD</b>, and <b>AFD</b> other input quantities are expressed in US Customary Units. If flow units are in liters or cubic meters then Metric Units must be used for all other input quantities as well. (See the @ref Units topic). The default flow units are \b GPM.
|
||||
For <b>CFS, GPM, MGD, IMGD</b>, and <b>AFD</b> other input quantities are expressed in US Customary Units. If flow units are in liters or cubic meters then Metric Units must be used for all other input quantities as well. (See the @ref Units topic). An exception is pressure which can use either US or SI units. The default flow units are \b GPM.
|
||||
|
||||
\b PRESSURE sets the units in which pressure is expressed, regardless of which unit system is in use. The default pressure unit is \b PSI for US Customary Units and \b METERS for SI Metric Units.
|
||||
|
||||
\b HEADLOSS selects a formula to use for computing head loss for flow through a pipe. The choices are the Hazen-Williams (\b H-W ), Darcy-Weisbach (\b D-W ), or Chezy-Manning (\b C-M ) formulas. The default is \b H-W.
|
||||
|
||||
@@ -346,7 +374,7 @@ The \b HYDRAULICS option allows you to either <B>SAVE</B> the current hydraulics
|
||||
|
||||
\b MINIMUM PRESSURE is the pressure below which no demand can be delivered under a pressure driven analysis. It has no effect on a demand driven analysis. Its default value is 0.
|
||||
|
||||
\b REQUIRED PRESSURE is the pressure required to supply a node's full demand under a pressure driven analysis. It has no effect on a demand driven analysis. It must be at least 0.1 psi or m higher than the MINIMUM PRESSURE, which is also its default value.
|
||||
\b REQUIRED PRESSURE is the pressure required to supply a node's full demand under a pressure driven analysis. It has no effect on a demand driven analysis. It must be at least 0.1 pressure units higher than the MINIMUM PRESSURE, which is also its default value.
|
||||
|
||||
\b PRESSURE EXPONENT is the power to which pressure is raised when computing the demand delivered to a node under a pressure driven analysis. It has no effect on a demand driven analysis. Its default value is 0.5.
|
||||
|
||||
@@ -356,6 +384,8 @@ The <b>DEMAND MULTIPLIER</b> is used to adjust the values of baseline demands fo
|
||||
|
||||
<b>EMITTER EXPONENT</b> specifies the power to which the pressure at a junction is raised when computing the flow issuing from an emitter. The default is 0.5.
|
||||
|
||||
<b>EMITTER BACKFLOW</b> specifies if back flow through an emitter (i.e., flow into the network) is allowed. The default is <b>YES</b>.
|
||||
|
||||
\b QUALITY selects the type of water quality analysis to perform. The choices are <b>NONE, CHEMICAL, AGE</b>, and \b TRACE. In place of \b CHEMICAL the actual name of the chemical can be used followed by its concentration units (e.g., <b>CHLORINE mg/L</b>). If \b TRACE is selected it must be followed by the ID label of the node being traced. The default selection is \b NONE (no water quality analysis).
|
||||
|
||||
\b DIFFUSIVITY is the molecular diffusivity of the chemical being analyzed relative to that of chlorine in water. The default value is 1.0. Diffusivity is only used when mass transfer limitations are considered in pipe wall reactions. A value of 0 will cause EPANET to ignore mass transfer limitations.
|
||||
@@ -496,7 +526,7 @@ One line per node containing:
|
||||
|
||||
__Remarks:__
|
||||
1. Quality is assumed to be zero for nodes not listed.
|
||||
2. Quality represents concentration for chemicals, hours for water age, or percent for source tracing.
|
||||
2. Quality represents concentration for chemicals or hours for water age. Values for source tracing are not required and will be ignored.
|
||||
3. The <b>[QUALITY]</b> section is optional.
|
||||
*/
|
||||
|
||||
@@ -587,6 +617,8 @@ __Definitions:__
|
||||
|
||||
\b SUMMARY determines whether a summary table of number of network components and key analysis options is generated. The default is \b YES.
|
||||
|
||||
\b MESSAGES determines whether error and warning messages are reported. The default is \b YES.
|
||||
|
||||
\b ENERGY determines if a table reporting average energy usage and cost for each pump is provided. The default is \b NO.
|
||||
|
||||
\b NODES identifies which nodes will be reported on. You can either list individual node ID labels or use the keywords \b NONE or \b ALL. Additional \b NODES lines can be used to continue the list. The default is \b NONE.
|
||||
@@ -896,6 +928,38 @@ __Example:__
|
||||
@endcode
|
||||
*/
|
||||
|
||||
/**
|
||||
@page TagsPage [TAGS]
|
||||
|
||||
__Purpose:__
|
||||
|
||||
Associates category labels (tags) with specific nodes and links.
|
||||
|
||||
__Format:__
|
||||
|
||||
One line for each node and link with a tag containing:
|
||||
- the keyword <b>NODE</b> or <b>LINK</b>
|
||||
- the node or link ID label
|
||||
- the text of the tag label (with no spaces)
|
||||
|
||||
__Remarks:__
|
||||
1. Tags can be useful for assigning nodes to different pressure zones or for classifying pipes by material or age.
|
||||
2. If a node or link’s tag is not identified in this section then it is assumed to be blank.
|
||||
3. The [TAGS] section is optional and has no effect on the hydraulic or water quality calculations.
|
||||
|
||||
__Example:__
|
||||
@code
|
||||
[TAGS]
|
||||
;Object ID Tag
|
||||
;------------------------------
|
||||
NODE 1001 Zone_A
|
||||
NODE 1002 Zone_A
|
||||
NODE 45 Zone_B
|
||||
LINK 201 UNCI-1960
|
||||
LINK 202 PVC-1985
|
||||
@endcode
|
||||
*/
|
||||
|
||||
/**
|
||||
@page TanksPage [TANKS]
|
||||
|
||||
@@ -1005,7 +1069,7 @@ Attaches a descriptive title to the network being analyzed.
|
||||
|
||||
__Format:__
|
||||
|
||||
Any number of lines of text.
|
||||
Up to three lines of text containing no more than 79 characters each can be used as a title.
|
||||
|
||||
__Remarks:__
|
||||
|
||||
@@ -1028,19 +1092,26 @@ One line for each valve containing:
|
||||
- Diameter, inches (mm)
|
||||
- Valve type
|
||||
- Valve setting
|
||||
- Minor loss coefficient
|
||||
- Minor loss coefficient when fully open
|
||||
- ID of valve characteristic curve (PCVs only)
|
||||
|
||||
__Remarks:__
|
||||
1. Valve types and settings include:
|
||||
1. Valve types and settings include: \n
|
||||
|Valve Type | Setting |
|
||||
|-----------|---------|
|
||||
|<B>PRV</B> (pressure reducing valve) | Pressure, psi (m) |
|
||||
|<B>PSV</B> (pressure sustaining valve) | Pressure, psi (m) |
|
||||
|<B>PBV</B> (pressure breaker valve) | Pressure, psi (m) |
|
||||
|<B>PRV</B> (pressure reducing valve) | Pressure (pressure units) |
|
||||
|<B>PSV</B> (pressure sustaining valve) | Pressure (pressure units) |
|
||||
|<B>PBV</B> (pressure breaker valve) | Pressure (pressure units) |
|
||||
|<B>FCV</B> (flow control valve) | Flow (flow units) |
|
||||
|<B>TCV</B> (throttle control valve) | Loss Coefficient |
|
||||
|<B>TCV</B> (throttle control valve) | Partially open loss coefficient |
|
||||
|<B>PCV</B> (positional control valve) | Percent open |
|
||||
|<B>GPV</B> (general purpose valve) | ID of head loss curve |
|
||||
\n
|
||||
2. Shutoff valves and check valves are considered to be part of a pipe, not a separate control valve component (see @ref PipesPage).
|
||||
3. The loss coefficient setting for a TCV should not be less than its fully open loss coefficient.
|
||||
4. The characteristic curve for a PCV relates the valve's percent of fully open flow to the percent open. If not supplied then a linear curve is assumed.
|
||||
5. The partially opened loss coefficient for a PCV is the inverse of the squared value from its characteristic curve times the fully open loss coefficient.
|
||||
6. The head loss curve for a GPV relates head loss across the valve to the flow rate through it.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -1073,8 +1144,6 @@ upper-left corner of the network's bounding rectangle. Default is zero offset.
|
||||
__Remarks:__
|
||||
|
||||
1. The [BACKDROP] section is optional and only provides support for an external GUI program that uses the EPANET engine.
|
||||
|
||||
2. Only Windows Enhanced Metafiles and bitmap files can be used as backdrops.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -1095,9 +1164,9 @@ __Remarks:__
|
||||
|
||||
1. Include one line for each node that has coordinates.
|
||||
|
||||
2. The coordinates represent the distance from the node to an arbitrary origin at the lower left of the network. Any convenient units of measure for this distance can be used.
|
||||
2. Any convenient geographic, projected or arbitrary Cartesian coordinate system can be used.
|
||||
|
||||
3. The locations of the nodes need not be to actual scale.
|
||||
3. The locations of nodes need not be to actual scale.
|
||||
|
||||
4. A [COORDINATES] section is optional and only provides support for an external GUI program that uses the EPANET engine.
|
||||
*/
|
||||
@@ -1144,7 +1213,7 @@ __Remarks:__
|
||||
|
||||
1. Include one line for each label.
|
||||
|
||||
2. The coordinates refer to the upper left corner of the label and are with respect to an arbitrary origin at the lower left of the network.
|
||||
2. The coordinates refer to the upper left corner of the label.
|
||||
|
||||
3. The optional anchor node anchors the label to the node when the network layout is re-scaled during zoom-in operations.
|
||||
|
||||
@@ -71,9 +71,14 @@ These are the toolkit's enumerated types whose members are used as function argu
|
||||
@fn int EN_runproject(EN_Project ph, const char *f1, const char *f2, const char *f3, void (*pviewprog)(char *))
|
||||
@fn int EN_init(EN_Project ph, const char *rptFile, const char *outFile, int unitsType, int headLossType)
|
||||
@fn int EN_open(EN_Project ph, const char *inpFile, const char *rptFile, const char *binOutFile)
|
||||
@fn int EN_openX(EN_Project ph, const char *inpFile, const char *rptFile, const char *binOutFile)
|
||||
@fn int EN_getcount(EN_Project ph, int code, int *count)
|
||||
@fn int EN_gettitle(EN_Project ph, char *line1, char *line2, char *line3)
|
||||
@fn int EN_settitle(EN_Project ph, char *line1, char *line2, char *line3)
|
||||
@fn int EN_settitle(EN_Project ph, const char *line1, const char *line2, const char *line3)
|
||||
@fn int EN_getcomment(EN_Project ph, int object, int index, char *comment)
|
||||
@fn int EN_setcomment(EN_Project ph, int object, int index, const char *comment)
|
||||
@fn int EN_gettag(EN_Project ph, int object, int index, char *tag)
|
||||
@fn int EN_settag(EN_Project ph, int object, int index, const char *tag)
|
||||
@fn int EN_saveinpfile(EN_Project ph, const char *filename)
|
||||
@fn int EN_close(EN_Project ph)
|
||||
@}
|
||||
@@ -110,25 +115,27 @@ These are the toolkit's enumerated types whose members are used as function argu
|
||||
/**
|
||||
@addtogroup Reporting
|
||||
@{
|
||||
@fn int EN_writeline(EN_Project ph, char *line)
|
||||
@fn int EN_writeline(EN_Project ph, const char *line)
|
||||
@fn int EN_report(EN_Project ph)
|
||||
@fn int EN_copyreport(EN_Project ph, char *filename)
|
||||
@fn int EN_copyreport(EN_Project ph, const char *filename)
|
||||
@fn int EN_clearreport(EN_Project ph)
|
||||
@fn int EN_resetreport(EN_Project ph)
|
||||
@fn int EN_setreport(EN_Project ph, char *reportFormat)
|
||||
@fn int EN_setreport(EN_Project ph, const char *reportFormat)
|
||||
@fn int EN_setstatusreport(EN_Project ph, int code)
|
||||
@fn int EN_getversion(int *version)
|
||||
@fn int EN_geterror(int errcode, char *errmsg, int maxLen)
|
||||
@fn int EN_getstatistic(EN_Project ph, int type, double* value)
|
||||
@fn int EN_getresultindex(EN_Project ph, int type, int index, int *value)
|
||||
|
||||
@fn int EN_timetonextevent(EN_Project ph, int *eventType, long *duration, int *elementIndex);
|
||||
@fn int EN_setreportcallback(EN_Project ph, void (*callback)(void *userData, void *EN_projectHandle, const char*))
|
||||
@fn int EN_setreportcallbackuserdata(EN_Project ph, void *userData)
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@addtogroup Options
|
||||
@{
|
||||
@fn int EN_getoption(EN_Project ph, int option, double *value)
|
||||
@fn int EN_getoption(EN_Project ph, int option, double *out_value)
|
||||
@fn int EN_setoption(EN_Project ph, int option, double value)
|
||||
@fn int EN_getflowunits(EN_Project ph, int *units)
|
||||
@fn int EN_setflowunits(EN_Project ph, int units)
|
||||
@@ -136,67 +143,67 @@ These are the toolkit's enumerated types whose members are used as function argu
|
||||
@fn int EN_settimeparam(EN_Project ph, int param, long value)
|
||||
@fn int EN_getqualinfo(EN_Project ph, int *qualType, char *chemName, char *chemUnits, int *traceNode)
|
||||
@fn int EN_getqualtype(EN_Project ph, int *qualType, int *traceNode)
|
||||
@fn int EN_setqualtype(EN_Project ph, int qualType, char *chemName, char *chemUnits, char *traceNode)
|
||||
@fn int EN_setqualtype(EN_Project ph, int qualType, const char *chemName, const char *chemUnits, const char *traceNode)
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@addtogroup Nodes
|
||||
/** \addtogroup Nodes
|
||||
@{
|
||||
@fn int EN_addnode(EN_Project ph, char *id, int nodeType, int *index)
|
||||
@fn int EN_addnode(EN_Project ph, const char *id, int nodeType, int *out_index)
|
||||
@fn int EN_deletenode(EN_Project ph, int index, int actionCode)
|
||||
@fn int EN_getnodeindex(EN_Project ph, char *id, int *index)
|
||||
@fn int EN_getnodeid(EN_Project ph, int index, char *id)
|
||||
@fn int EN_setnodeid(EN_Project ph, int index, char *newid)
|
||||
@fn int EN_getnodetype(EN_Project ph, int index, int *code)
|
||||
@fn int EN_getnodevalue(EN_Project ph, int index, int code, double *value)
|
||||
@fn int EN_setnodevalue(EN_Project ph, int index, int code, double v)
|
||||
@fn int EN_setjuncdata(EN_Project ph, int index, double elev, double dmnd, char *dmndpat)
|
||||
@fn int EN_settankdata(EN_Project ph, int index, double elev, double initlvl,
|
||||
double minlvl, double maxlvl, double diam, double minvol, char *volcurve)
|
||||
@fn int EN_getcoord(EN_Project ph, int index, double *x, double *y)
|
||||
@fn int EN_getnodeindex(EN_Project ph, const char *id, int *out_index)
|
||||
@fn int EN_getnodeid(EN_Project ph, int index, char *out_id)
|
||||
@fn int EN_setnodeid(EN_Project ph, int index, const char *newid)
|
||||
@fn int EN_getnodetype(EN_Project ph, int index, int *out_nodeType)
|
||||
@fn int EN_getnodevalue(EN_Project ph, int index, int property, double *out_value)
|
||||
@fn int EN_getnodevalues(EN_Project ph, int property, double *out_values)
|
||||
@fn int EN_setnodevalue(EN_Project ph, int index, int property, double value)
|
||||
@fn int EN_setjuncdata(EN_Project ph, int index, double elev, double dmnd, const char *dmndpat)
|
||||
@fn int EN_settankdata(EN_Project ph, int index, double elev, double initlvl, double minlvl, double maxlvl, double diam, double minvol, const char *volcurve)
|
||||
@fn int EN_getcoord(EN_Project ph, int index, double *out_x, double *out_y)
|
||||
@fn int EN_setcoord(EN_Project ph, int index, double x, double y)
|
||||
@}
|
||||
*/
|
||||
@}*/
|
||||
|
||||
/**
|
||||
@addtogroup Demands
|
||||
@{
|
||||
@fn int EN_getdemandmodel(EN_Project ph, int *type, double *pmin, double *preq, double *pexp)
|
||||
@fn int EN_setdemandmodel(EN_Project ph, int type, double pmin, double preq, double pexp)
|
||||
@fn int EN_adddemand(EN_Project ph, int nodeIndex, double baseDemand, char *demandPattern, char *demandName)
|
||||
@fn int EN_adddemand(EN_Project ph, int nodeIndex, double baseDemand, const char *demandPattern, const char *demandName)
|
||||
@fn int EN_deletedemand(EN_Project ph, int nodeIndex, int demandIndex)
|
||||
@fn int EN_getdemandindex(EN_Project p, int nodeIndex, char *demandName, int *demandIndex)
|
||||
@fn int EN_getdemandindex(EN_Project p, int nodeIndex, const char *demandName, int *demandIndex)
|
||||
@fn int EN_getnumdemands(EN_Project ph, int nodeIndex, int *numDemands)
|
||||
@fn int EN_getbasedemand(EN_Project ph, int nodeIndex, int demandIndex, double *baseDemand)
|
||||
@fn int EN_setbasedemand(EN_Project ph, int nodeIndex, int demandIndex, double baseDemand)
|
||||
@fn int EN_getdemandpattern(EN_Project ph, int nodeIndex, int demandIndex, int *pattIndex)
|
||||
@fn int EN_setdemandpattern(EN_Project ph, int nodeIndex, int demandIndex, int patIndex)
|
||||
@fn int EN_getdemandname(EN_Project ph, int nodeIndex, int demandIdx, char *demandName)
|
||||
@fn int EN_setdemandname(EN_Project ph, int nodeIndex, int demandIdx, char *demandName)
|
||||
@fn int EN_setdemandname(EN_Project ph, int nodeIndex, int demandIdx, const char *demandName)
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@addtogroup Links
|
||||
@{
|
||||
@fn int EN_addlink(EN_Project ph, char *id, int linkType, char *fromNode, char *toNode, int *index)
|
||||
@fn int EN_addlink(EN_Project ph, char *id, int linkType, const char *fromNode, const char *toNode, int *out_index)
|
||||
@fn int EN_deletelink(EN_Project ph, int index, int actionCode)
|
||||
@fn int EN_getlinkindex(EN_Project ph, char *id, int *index)
|
||||
@fn int EN_getlinkindex(EN_Project ph, const char *id, int *out_index)
|
||||
@fn int EN_getlinkid(EN_Project ph, int index, char *id)
|
||||
@fn int EN_setlinkid(EN_Project ph, int index, char *newid)
|
||||
@fn int EN_getlinktype(EN_Project ph, int index, int *linkType)
|
||||
@fn int EN_setlinkid(EN_Project ph, int index, const char *newid)
|
||||
@fn int EN_getlinktype(EN_Project ph, int index, int *out_linkType)
|
||||
@fn int EN_setlinktype(EN_Project ph, int *index, int linkType, int actionCode)
|
||||
@fn int EN_getlinknodes(EN_Project ph, int index, int *node1, int *node2)
|
||||
@fn int EN_getlinknodes(EN_Project ph, int index, int *out_node1, int *out_node2)
|
||||
@fn int EN_setlinknodes(EN_Project ph, int index, int node1, int node2)
|
||||
@fn int EN_getlinkvalue(EN_Project ph, int index, int property, double *value)
|
||||
@fn int EN_getlinkvalue(EN_Project ph, int index, int property, double *out_value)
|
||||
@fn int EN_getlinkvalues(EN_Project ph, int property, double *out_values)
|
||||
@fn int EN_setlinkvalue(EN_Project ph, int index, int property, double value)
|
||||
@fn int EN_setpipedata(EN_Project ph, int index, double length, double diam, double rough, double mloss)
|
||||
@fn int EN_getpumptype(EN_Project ph, int linkIndex, int *pumpType)
|
||||
@fn int EN_getheadcurveindex(EN_Project ph, int pumpIndex, int *curveIndex)
|
||||
@fn int EN_getpumptype(EN_Project ph, int linkIndex, int *out_pumpType)
|
||||
@fn int EN_getheadcurveindex(EN_Project ph, int pumpIndex, int *out_curveIndex)
|
||||
@fn int EN_setheadcurveindex(EN_Project ph, int pumpIndex, int curveIndex)
|
||||
@fn int EN_getvertexcount(EN_Project ph, int index, int *count)
|
||||
@fn int EN_getvertex(EN_Project ph, int index, int vertex, double *x, double *y)
|
||||
@fn int EN_getvertexcount(EN_Project ph, int index, int *out_count)
|
||||
@fn int EN_getvertex(EN_Project ph, int index, int vertex, double *out_x, double *out_y)
|
||||
@fn int EN_setvertex(EN_Project ph, int index, int vertex, double x, double y)
|
||||
@fn int EN_setvertices(EN_Project ph, int index, double *x, double *y, int count)
|
||||
@}
|
||||
*/
|
||||
@@ -204,32 +211,34 @@ These are the toolkit's enumerated types whose members are used as function argu
|
||||
/**
|
||||
@addtogroup Patterns
|
||||
@{
|
||||
@fn int EN_addpattern(EN_Project ph, char *id)
|
||||
@fn int EN_addpattern(EN_Project ph, const char *id)
|
||||
@fn int EN_deletepattern(EN_Project ph, int index)
|
||||
@fn int EN_getpatternindex(EN_Project ph, char *id, int *index)
|
||||
@fn int EN_getpatternindex(EN_Project ph, char *id, int *out_index)
|
||||
@fn int EN_getpatternid(EN_Project ph, int index, char *id)
|
||||
@fn int EN_setpatternid(EN_Project ph, int index, char *id)
|
||||
@fn int EN_getpatternlen(EN_Project ph, int index, int *len)
|
||||
@fn int EN_getpatternvalue(EN_Project ph, int index, int period, double *value)
|
||||
@fn int EN_setpatternid(EN_Project ph, int index, const char *id)
|
||||
@fn int EN_getpatternlen(EN_Project ph, int index, int *out_len)
|
||||
@fn int EN_getpatternvalue(EN_Project ph, int index, int period, double *out_value)
|
||||
@fn int EN_setpatternvalue(EN_Project ph, int index, int period, double value)
|
||||
@fn int EN_getaveragepatternvalue(EN_Project ph, int index, double *value)
|
||||
@fn int EN_getaveragepatternvalue(EN_Project ph, int index, double *out_value)
|
||||
@fn int EN_setpattern(EN_Project ph, int index, double *f, int len)
|
||||
@fn int EN_loadpatternfile(EN_Project ph, const char *filename, const char *id)
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@addtogroup Curves
|
||||
@{
|
||||
@fn int EN_addcurve(EN_Project ph, char *id)
|
||||
@fn int EN_addcurve(EN_Project ph, const char *id)
|
||||
@fn int EN_deletecurve(EN_Project ph, int index)
|
||||
@fn int EN_getcurveindex(EN_Project ph, char *id, int *index)
|
||||
@fn int EN_getcurveid(EN_Project ph, int index, char *id)
|
||||
@fn int EN_setcurveid(EN_Project ph, int index, char *id)
|
||||
@fn int EN_getcurvelen(EN_Project ph, int index, int *len)
|
||||
@fn int EN_getcurvetype(EN_Project ph, int index, int *type)
|
||||
@fn int EN_getcurvevalue(EN_Project ph, int curveIndex, int pointIndex, double *x, double *y)
|
||||
@fn int EN_getcurveindex(EN_Project ph, const char *id, int *out_index)
|
||||
@fn int EN_getcurveid(EN_Project ph, int index, char *out_id)
|
||||
@fn int EN_setcurveid(EN_Project ph, int index, const char *id)
|
||||
@fn int EN_getcurvelen(EN_Project ph, int index, int *out_len)
|
||||
@fn int EN_getcurvetype(EN_Project ph, int index, int *out_type)
|
||||
@fn int EN_setcurvetype(EN_Project ph, int index, int type)
|
||||
@fn int EN_getcurvevalue(EN_Project ph, int curveIndex, int pointIndex, double *out_x, double *out_y)
|
||||
@fn int EN_setcurvevalue(EN_Project ph, int curveIndex, int pointIndex, double x, double y)
|
||||
@fn int EN_getcurve(EN_Project ph, int curveIndex, char* id, int *nPoints, double **xValues, double **yValues)
|
||||
@fn int EN_getcurve(EN_Project ph, int index, char *out_id, int *out_nPoints, double *out_xValues, double *out_yValues)
|
||||
@fn int EN_setcurve(EN_Project ph, int index, double *xValues, double *yValues, int nPoints)
|
||||
@}
|
||||
*/
|
||||
@@ -237,10 +246,12 @@ These are the toolkit's enumerated types whose members are used as function argu
|
||||
/**
|
||||
@addtogroup Controls
|
||||
@{
|
||||
@fn int EN_addcontrol(EN_Project ph, int type, int linkIndex, double setting, int nodeIndex, double level, int *index)
|
||||
@fn int EN_addcontrol(EN_Project ph, int type, int linkIndex, double setting, int nodeIndex, double level, int *out_index)
|
||||
@fn int EN_deletecontrol(EN_Project ph, int index)
|
||||
@fn int EN_getcontrol(EN_Project ph, int index, int *type, int *linkIndex, double *setting, int *nodeIndex, double *level)
|
||||
@fn int EN_getcontrol(EN_Project ph, int index, int *out_type, int *out_linkIndex, double *out_setting, int *out_nodeIndex, double *out_level)
|
||||
@fn int EN_setcontrol(EN_Project ph, int index, int type, int linkIndex, double setting, int nodeIndex, double level)
|
||||
@fn int EN_getcontrolenabled(EN_Project ph, int index, int *out_enabled)
|
||||
@fn int EN_setcontrolenabled(EN_Project ph, int index, int enabled)
|
||||
@}
|
||||
*/
|
||||
|
||||
@@ -263,42 +274,50 @@ These are the toolkit's enumerated types whose members are used as function argu
|
||||
@fn int EN_getelseaction(EN_Project ph, int ruleIndex, int actionIndex, int *linkIndex, int *status, double *setting)
|
||||
@fn int EN_setelseaction(EN_Project ph, int ruleIndex, int actionIndex, int linkIndex, int status, double setting)
|
||||
@fn int EN_setrulepriority(EN_Project ph, int index, double priority)
|
||||
@fn int EN_getruleenabled(EN_Project ph, int index, int *out_enabled)
|
||||
@fn int EN_setruleenabled(EN_Project ph, int index, int enabled)
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@addtogroup Enumerations
|
||||
@{
|
||||
\enum EN_SizeLimits
|
||||
\enum EN_ObjectType
|
||||
\enum EN_CountType
|
||||
\enum EN_NodeType
|
||||
\enum EN_LinkType
|
||||
\enum EN_PumpType
|
||||
\enum EN_PumpStateType
|
||||
\enum EN_CurveType
|
||||
\enum EN_QualityType
|
||||
\enum EN_SourceType
|
||||
\enum EN_ControlType
|
||||
\enum EN_HeadLossType
|
||||
\enum EN_NodeProperty
|
||||
\enum EN_LinkProperty
|
||||
\enum EN_LinkStatusType
|
||||
\enum EN_TimeParameter
|
||||
\enum EN_Option
|
||||
\enum EN_FlowUnits
|
||||
\enum EN_DemandModel
|
||||
\enum EN_MixingModel
|
||||
\enum EN_StatisticType
|
||||
\enum EN_InitHydOption
|
||||
\enum EN_ActionCodeType
|
||||
\enum EN_AnalysisStatistic
|
||||
\enum EN_StatusReport
|
||||
\enum EN_RuleObject
|
||||
\enum EN_RuleVariable
|
||||
\enum EN_RuleOperator
|
||||
\enum EN_RuleStatus
|
||||
\typedef EN_SizeLimits
|
||||
\typedef EN_ObjectType
|
||||
\typedef EN_CountType
|
||||
\typedef EN_NodeType
|
||||
\typedef EN_LinkType
|
||||
\typedef EN_PumpType
|
||||
\typedef EN_PumpStateType
|
||||
\typedef EN_CurveType
|
||||
\typedef EN_QualityType
|
||||
\typedef EN_SourceType
|
||||
\typedef EN_ControlType
|
||||
\typedef EN_HeadLossType
|
||||
\typedef EN_NodeProperty
|
||||
\typedef EN_LinkProperty
|
||||
\typedef EN_LinkStatusType
|
||||
\typedef EN_TimeParameter
|
||||
\typedef EN_TimestepEvent
|
||||
\typedef EN_Option
|
||||
\typedef EN_FlowUnits
|
||||
\typedef EN_PressUnits
|
||||
\typedef EN_DemandModel
|
||||
\typedef EN_MixingModel
|
||||
\typedef EN_StatisticType
|
||||
\typedef EN_InitHydOption
|
||||
\typedef EN_ActionCodeType
|
||||
\typedef EN_AnalysisStatistic
|
||||
\typedef EN_StatusReport
|
||||
\typedef EN_RuleObject
|
||||
\typedef EN_RuleVariable
|
||||
\typedef EN_RuleOperator
|
||||
\typedef EN_RuleStatus
|
||||
\def EN_MISSING
|
||||
\def EN_SET_CLOSED
|
||||
\def EN_SET_OPEN
|
||||
\def EN_FALSE
|
||||
\def EN_TRUE
|
||||
@}
|
||||
*/
|
||||
|
||||
@@ -346,19 +365,26 @@ These are the toolkit's enumerated types whose members are used as function argu
|
||||
| 226 | No head curve or power rating for pump |
|
||||
| 227 | Invalid head curve for pump |
|
||||
| 230 | Nonincreasing x-values for curve |
|
||||
| 233 | Network has unconnected node |
|
||||
| 231 | No data provided for a curve |
|
||||
| 232 | No data provided for a pattern |
|
||||
| 233 | Network has unconnected nodes |
|
||||
| 240 | Function call refers to nonexistent water quality source |
|
||||
| 241 | Function call refers to nonexistent control |
|
||||
| 250 | Function call contains invalid format (e.g. too long an ID name) |
|
||||
| 251 | Function call contains invalid parameter code |
|
||||
| 252 | Function call rferes to an invalid ID name |
|
||||
| 253 | Function call refers to nonexistent demand category |
|
||||
| 254 | Function call refers to node with no coordinates |
|
||||
| 255 | Function call refers to link with no vertices |
|
||||
| 257 | Function call refers to nonexistent rule |
|
||||
| 258 | Function call refers to nonexistent rule clause |
|
||||
| 259 | Function call attempts to delete a node that still has links connected to it |
|
||||
| 260 | Function call attempts to delete node assigned as a Trace Node |
|
||||
| 261 | Function call attempts to delete a node or link contained in a control |
|
||||
| 262 | Function call attempts to modify network structure while a solver is open |
|
||||
| 263 | Function call refers to node that is not a tank |
|
||||
| 264 | Function call refers to a link that is not a valve |
|
||||
| 299 | An invalid section keyword was detected in an input file |
|
||||
| ||
|
||||
| 301 | Identical file names used for different types of files |
|
||||
| 302 | Cannot open input file |
|
||||
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
@page Units Measurement Units
|
||||
|
||||
The toolkit can use data expressed in either US Customary of SI Metric units. A project's unit system depends on the unit system used for its choice of flow units. If the @ref EN_open function is used to supply data to a project from an Input File then its flow units are set in the @ref OptionsPage section of the file. If the @ref EN_init function is used to initialize a project then the choice of flow units is the fourth argument to the function. The following table lists the units used to express the various parameters in an EPANET model.
|
||||
The toolkit can use data expressed in either US Customary of SI Metric units. A project's unit system depends on the unit system used for its choice of flow units. If the @ref EN_open function is used to supply data to a project from an Input File then its flow units are set in the @ref OptionsPage section of the file. If the @ref EN_init function is used to initialize a project then the choice of flow units is the fourth argument to the function. An exception to this convention is pressure whose units can be expressed in either US or SI units. The following table lists the units used to express the various parameters in an EPANET model.
|
||||
|
||||
| Parameter | US Customary | SI Metric |
|
||||
|----------------|-------------------------|---------------------------|
|
||||
@@ -17,14 +17,17 @@ The toolkit can use data expressed in either US Customary of SI Metric units. A
|
||||
|Flow | CFS (cubic feet / sec) | LPS (liters / sec) |
|
||||
| | GPM (gallons / min) | LPM (liters / min) |
|
||||
| | MGD (million gal / day) | MLD (megaliters / day) |
|
||||
| | IMGD (Imperial MGD) | CMH (cubic meters / hr) |
|
||||
| | AFD (acre-feet / day) | CMD (cubic meters / day) |
|
||||
| | IMGD (Imperial MGD) | CMS (cubic meters / sec) |
|
||||
| | AFD (acre-feet / day) | CMH (cubic meters / hr) |
|
||||
| | | CMD (cubic meters / day) |
|
||||
|Friction Factor | unitless | unitless |
|
||||
|Head | feet | meters |
|
||||
|Length | feet | meters |
|
||||
|Minor Loss Coeff. | unitless | unitless |
|
||||
|Power | horsepower | kwatts |
|
||||
|Pressure | psi | meters |
|
||||
|Pressure | psi (pounds / sq. in.)| meters |
|
||||
| | feet | kPa (kiloPascal) |
|
||||
| | | bar |
|
||||
|Reaction Coeff. (Bulk) | 1/day (1st-order)| 1/day (1st-order) |
|
||||
|Reaction Coeff. (Wall) | mass/sq-ft/day (0-order) | mass/sq-m/day (0-order) |
|
||||
| | ft/day (1st-order) | meters/day (1st-order) |
|
||||
|
||||
@@ -34,7 +34,7 @@ void runHydraulics(EN_Project ph, char *inputFile, char *reportFile)
|
||||
ERRCODE(EN_solveH(ph));
|
||||
ERRCODE(EN_saveH(ph));
|
||||
ERRCODE(EN_report(ph));
|
||||
EN_geterror(ph, errcode, errmsg);
|
||||
EN_geterror(errcode, errmsg, EN_MAXMSG);
|
||||
if (errcode) printf("\n%s\n", errmsg);
|
||||
}
|
||||
\endcode
|
||||
@@ -57,7 +57,7 @@ EN_deleteproject(ph);
|
||||
|
||||
After an input file has been loaded in this fashion the resulting network can have objects added or deleted, and their properties set using the various Toolkit functions .
|
||||
|
||||
The second method for supplying network data to a project is to use the Toolkit's functions to add objects and to set their properties via code. In this case the @ref EN_init function should be called immediately after creating a project, passing in the names of a report and binary output files (both optional) as well as the choices of flow units and head loss formulas to use. After that the various \b EN_add functions, such as @ref EN_addnode, @ref EN_addlink, @ref EN_addpattern, @ref EN_addcontrol, etc., can be called to add new objects to the network. Here is a partial example of constructing a network from code:
|
||||
The second method for supplying network data to a project is to use the Toolkit's functions to add objects and to set their properties via code. In this case the @ref EN_init function should be called immediately after creating a project, passing in the names of a report and binary output files (both optional) as well as the choices of flow units and head loss formulas to use. After that the various \b EN_add functions, such as @ref EN_addnode , @ref EN_addlink , @ref EN_addpattern , @ref EN_addcontrol , etc., can be called to add new objects to the network. Here is a partial example of constructing a network from code:
|
||||
|
||||
\code {.c}
|
||||
int index;
|
||||
@@ -76,7 +76,7 @@ See the @ref Example2 for a more complete example. The labels used to name objec
|
||||
|
||||
The Toolkit contains several functions for retrieving and setting the properties of a network's objects and its analysis options. The names of retrieval functions all begin with \b EN_get (e.g., @ref EN_getnodevalue, @ref EN_getoption, etc.) while the functions used for setting parameter values begin with \b EN_set (e.g., @ref EN_setnodevalue, @ref EN_setoption, etc.).
|
||||
|
||||
Most of these functions use an index number to refer to a specific network component (such as a node, link, time pattern or data curve). This number is simply the position of the component in the list of all components of similar type (e.g., node 10 is the tenth node, starting from 1, in the network) and is not the same as the ID label assigned to the component. A series of functions exist to determine a component's index number given its ID label (see @ref EN_getnodeindex, @ref EN_getlinkindex, @ref EN_getpatternindex, and @ref EN_getcurveindex). Likewise, functions exist to retrieve a component's ID label given its index number (see @ref EN_getlinkid, @ref EN_getnodeid, @ref EN_getpatternid, and @ref EN_getcurveid). The @ref EN_getcount function can be used to determine the number of different components in the network. Be aware that a component's index can change as elements are added or deleted from the network. The @ref EN_addnode and @ref EN_addlink functions return the index of the newly added node or link as a convenience for immediately setting their properties.
|
||||
Most of these functions use an index number to refer to a specific network component (such as a node, link, time pattern or data curve). This number is simply the position of the component in the list of all components of similar type (e.g., node 10 is the tenth node, starting from 1, in the network) and is not the same as the ID label assigned to the component. A series of functions exist to determine a component's index number given its ID label (see @ref EN_getnodeindex , @ref EN_getlinkindex , @ref EN_getpatternindex , and @ref EN_getcurveindex ). Likewise, functions exist to retrieve a component's ID label given its index number (see @ref EN_getlinkid , @ref EN_getnodeid , @ref EN_getpatternid , and @ref EN_getcurveid ). The @ref EN_getcount function can be used to determine the number of different components in the network. Be aware that a component's index can change as elements are added or deleted from the network. The @ref EN_addnode and @ref EN_addlink functions return the index of the newly added node or link as a convenience for immediately setting their properties.
|
||||
|
||||
The code below is an example of using the property retrieval and setting functions. It changes all links with diameter of 10 inches to 12 inches.
|
||||
|
||||
@@ -177,16 +177,24 @@ int runConcurrentQuality(EN_Project ph)
|
||||
@section results Retrieving Computed Results
|
||||
|
||||
The @ref EN_getnodevalue and @ref EN_getlinkvalue functions can also be used to retrieve the results of hydraulic and water quality simulations. The computed parameters (and their Toolkit codes) that can be retrieved are as follows:
|
||||
|For Nodes: | For Links: |
|
||||
|----------------------------------- | ----------------------------------------- |
|
||||
|\b EN_DEMAND (demand) |\b EN_FLOW (flow rate) |
|
||||
|\b EN_DEMANDDEFICIT (demand deficit) |\b EN_VELOCITY (flow velocity) |
|
||||
|\b EN_HEAD (hydraulic head) |\b EN_HEADLOSS (head loss) |
|
||||
|\b EN_PRESSURE (pressure) |\b EN_STATUS (link status) |
|
||||
|\b EN_TANKLEVEL (tank water level) |\b EN_SETTING (pump speed or valve setting) |
|
||||
|\b EN_TANKVOLUME (tank water volume) |\b EN_ENERGY (pump energy usage) |
|
||||
|\b EN_QUALITY (water quality) |\b EN_PUMP_EFFIC (pump efficiency) |
|
||||
|\b EN_SOURCEMASS (source mass inflow)| |
|
||||
|For Nodes: | For Links: |
|
||||
|------------------------------------ | ----------------------------------------- |
|
||||
|\b EN_DEMAND (total node outflow |\b EN_FLOW (flow rate) |
|
||||
|\b EN_HEAD (hydraulic head) |\b EN_VELOCITY (flow velocity) |
|
||||
|\b EN_PRESSURE (pressure) |\b EN_HEADLOSS (head loss) |
|
||||
|\b EN_TANKLEVEL (tank water level) |\b EN_STATUS (link status) |
|
||||
|\b EN_TANKVOLUME (tank water volume) |\b EN_SETTING (pump speed or valve setting)|
|
||||
|\b EN_QUALITY (water quality) |\b EN_ENERGY (pump energy usage) |
|
||||
|\b EN_SOURCEMASS (source mass inflow)|\b EN_PUMP_EFFIC (pump efficiency) |
|
||||
| |\b EN_LINK_LEAKAGE (pipe leakage flow rate |
|
||||
|
||||
In addition, the following quantities related to a node's outflow can be retrieved:
|
||||
-# EN_FULLDEMAND (consumer demand requested)
|
||||
-# EN_DEMANDFLOW (consumer demand delivered)
|
||||
-# EN_DEMANDDEFICIT (difference between consumer demand requested and delivered)
|
||||
-# EN_EMITTERFLOW (outflow through a node's emitter)
|
||||
-# EN_LEAKAGEFLOW (outflow due to leakage in a node's connecting pipes)
|
||||
where `EN_DEMAND` is the sum of `EN_DEMANDFLOW`, `EN_EMITTERFLOW`, and `EN_LEAKAGEFLOW`.
|
||||
|
||||
The following code shows how to retrieve the pressure at each node of a network after each time step of a hydraulic analysis (`writetofile` is a user-defined function that will write a record to a file):
|
||||
\code {.c}
|
||||
|
||||
@@ -5,7 +5,7 @@ Attribute VB_Name = "Module1"
|
||||
'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT
|
||||
'(EPANET2.DLL)
|
||||
|
||||
'Last updated on 11/04/2019
|
||||
'Last updated on 04/23/2025
|
||||
|
||||
' These are codes used by the DLL functions
|
||||
Public Const EN_ELEVATION = 0 ' Node parameters
|
||||
@@ -25,7 +25,6 @@ Public Const EN_SOURCEMASS = 13
|
||||
Public Const EN_INITVOLUME = 14
|
||||
Public Const EN_MIXMODEL = 15
|
||||
Public Const EN_MIXZONEVOL = 16
|
||||
|
||||
Public Const EN_TANKDIAM = 17
|
||||
Public Const EN_MINVOLUME = 18
|
||||
Public Const EN_VOLCURVE = 19
|
||||
@@ -36,7 +35,12 @@ Public Const EN_TANK_KBULK = 23
|
||||
Public Const EN_TANKVOLUME = 24
|
||||
Public Const EN_MAXVOLUME = 25
|
||||
Public Const EN_CANOVERFLOW = 26
|
||||
Public Const EN_DEMANDDEFICIT = 27
|
||||
Public Const EN_DEMANDDEFICIT = 27
|
||||
Public Const EN_NODE_INCONTROL = 28
|
||||
Public Const EN_EMITTERFLOW = 29
|
||||
Public Const EN_LEAKAGEFLOW = 30
|
||||
Public Const EN_DEMANDFLOW = 31
|
||||
Public Const EN_FULLDEMAND = 32
|
||||
|
||||
Public Const EN_DIAMETER = 0 ' Link parameters
|
||||
Public Const EN_LENGTH = 1
|
||||
@@ -54,7 +58,6 @@ Public Const EN_SETTING = 12
|
||||
Public Const EN_ENERGY = 13
|
||||
Public Const EN_LINKQUAL = 14
|
||||
Public Const EN_LINKPATTERN = 15
|
||||
|
||||
Public Const EN_PUMP_STATE = 16
|
||||
Public Const EN_PUMP_EFFIC = 17
|
||||
Public Const EN_PUMP_POWER = 18
|
||||
@@ -62,6 +65,13 @@ Public Const EN_PUMP_HCURVE = 19
|
||||
Public Const EN_PUMP_ECURVE = 20
|
||||
Public Const EN_PUMP_ECOST = 21
|
||||
Public Const EN_PUMP_EPAT = 22
|
||||
Public Const EN_LINK_INCONTROL = 23
|
||||
Public Const EN_GPV_CURVE = 24
|
||||
Public Const EN_PCV_CURVE = 25
|
||||
Public Const EN_LEAK_AREA = 26
|
||||
Public Const EN_LEAK_EXPAN = 27
|
||||
Public Const EN_LINK_LEAKAGE = 28
|
||||
Public Const EN_VALVE_TYPE = 29
|
||||
|
||||
Public Const EN_DURATION = 0 ' Time parameters
|
||||
Public Const EN_HYDSTEP = 1
|
||||
@@ -78,6 +88,7 @@ Public Const EN_HTIME = 11
|
||||
Public Const EN_QTIME = 12
|
||||
Public Const EN_HALTFLAG = 13
|
||||
Public Const EN_NEXTEVENT = 14
|
||||
Public Const EN_NEXTEVENTTANK = 15
|
||||
|
||||
Public Const EN_ITERATIONS = 0 ' Run statistics
|
||||
Public Const EN_RELATIVEERROR = 1
|
||||
@@ -86,13 +97,14 @@ Public Const EN_MAXFLOWCHANGE = 3
|
||||
Public Const EN_MASSBALANCE = 4
|
||||
Public Const EN_DEFICIENTNODES = 5
|
||||
Public Const EN_DEMANDREDUCTION = 6
|
||||
Public Const EN_LEAKAGELOSS = 7
|
||||
|
||||
Public Const EN_NODE = 0 ' Component types
|
||||
Public Const EN_LINK = 1
|
||||
Public Const EN_TIMEPAT = 2
|
||||
Public Const EN_CURVE = 3
|
||||
Public Const EN_CONTROL = 4
|
||||
Public Const EN_RULE = 5
|
||||
Public Const EN_RULE = 5
|
||||
|
||||
Public Const EN_NODECOUNT = 0 ' Component counts
|
||||
Public Const EN_TANKCOUNT = 1
|
||||
@@ -115,6 +127,15 @@ Public Const EN_PBV = 5
|
||||
Public Const EN_FCV = 6
|
||||
Public Const EN_TCV = 7
|
||||
Public Const EN_GPV = 8
|
||||
Public Const EN_PCV = 9
|
||||
|
||||
Public Const EN_CLOSED = 0 ' Link status types
|
||||
Public Const EN_OPEN = 1
|
||||
|
||||
Public Const EN_PUMP_XHEAD = 0 ' Pump state types
|
||||
Public Const EN_PUMP_CLOSED = 2
|
||||
Public Const EN_PUMP_OPEN = 3
|
||||
Public Const EN_PUMP_XFLOW = 5
|
||||
|
||||
Public Const EN_NONE = 0 ' Quality analysis types
|
||||
Public Const EN_CHEM = 1
|
||||
@@ -140,6 +161,13 @@ Public Const EN_LPM = 6
|
||||
Public Const EN_MLD = 7
|
||||
Public Const EN_CMH = 8
|
||||
Public Const EN_CMD = 9
|
||||
Public Const EN_CMS = 10
|
||||
|
||||
Public Const EN_PSI = 0 ' Pressure units types
|
||||
Public Const EN_KPA = 1
|
||||
Public Const EN_METERS = 2
|
||||
Public Const EN_BAR = 3
|
||||
Public Const EN_FEET = 4
|
||||
|
||||
Public Const EN_DDA = 0 ' Demand driven analysis
|
||||
Public Const EN_PDA = 1 ' Pressure driven analysis
|
||||
@@ -157,7 +185,7 @@ Public Const EN_GLOBALPRICE = 9
|
||||
Public Const EN_GLOBALPATTERN = 10
|
||||
Public Const EN_DEMANDCHARGE = 11
|
||||
Public Const EN_SP_GRAVITY = 12
|
||||
Public Const EN_SP_VISCOS = 13
|
||||
Public Const EN_SP_VISCOS = 13
|
||||
Public Const EN_UNBALANCED = 14
|
||||
Public Const EN_CHECKFREQ = 15
|
||||
Public Const EN_MAXCHECK = 16
|
||||
@@ -167,13 +195,18 @@ Public Const EN_BULKORDER = 19
|
||||
Public Const EN_WALLORDER = 20
|
||||
Public Const EN_TANKORDER = 21
|
||||
Public Const EN_CONCENLIMIT = 22
|
||||
Public Const EN_DEMANDPATTERN = 23
|
||||
Public Const EN_EMITBACKFLOW = 24
|
||||
Public Const EN_PRESS_UNITS = 25
|
||||
Public Const EN_STATUS_REPORT = 26
|
||||
|
||||
Public Const EN_LOWLEVEL = 0 ' Control types
|
||||
Public Const EN_HILEVEL = 1
|
||||
Public Const EN_TIMER = 2
|
||||
Public Const EN_TIMEOFDAY = 3
|
||||
|
||||
Public Const EN_AVERAGE = 1 ' Time statistic types
|
||||
Public Const EN_SERIES = 0 ' Time statistic types
|
||||
Public Const EN_AVERAGE = 1
|
||||
Public Const EN_MINIMUM = 2
|
||||
Public Const EN_MAXIMUM = 3
|
||||
Public Const EN_RANGE = 4
|
||||
@@ -189,7 +222,7 @@ Public Const EN_INITFLOW = 10 ' Re-initialize flow flag
|
||||
Public Const EN_SAVE_AND_INIT = 11
|
||||
|
||||
Public Const EN_CONST_HP = 0 ' Constant horsepower pump curve
|
||||
Public Const EN_POWER_FUNC = 1 ' Power function pump cuve
|
||||
Public Const EN_POWER_FUNC = 1 ' Power function pump curve
|
||||
Public Const EN_CUSTOM = 2 ' User-defined custom pump curve
|
||||
Public Const EN_NOCURVE = 3 ' No pump curve
|
||||
|
||||
@@ -198,6 +231,7 @@ Public Const EN_PUMP_CURVE = 1 ' Pump curve
|
||||
Public Const EN_EFFIC_CURVE = 2 ' Efficiency curve
|
||||
Public Const EN_HLOSS_CURVE = 3 ' Head loss curve
|
||||
Public Const EN_GENERIC_CURVE = 4 ' Generic curve
|
||||
Public Const EN_VALVE_CURVE = 5 ' Valve position curve
|
||||
|
||||
Public Const EN_UNCONDITIONAL = 0 ' Unconditional object deletion
|
||||
Public Const EN_CONDITIONAL = 1 ' Conditional object deletion
|
||||
@@ -239,7 +273,18 @@ Public Const EN_R_IS_OPEN = 1 ' Rule status types
|
||||
Public Const EN_R_IS_CLOSED = 2
|
||||
Public Const EN_R_IS_ACTIVE = 3
|
||||
|
||||
Public Const EN_MISSING As Double = -1.0E10
|
||||
Public Const EN_STEP_REPORT = 0 ' Types of events that can cause a timestep to end
|
||||
Public Const EN_STEP_HYD = 1
|
||||
Public Const EN_STEP_WQ = 2
|
||||
Public Const EN_STEP_TANKEVENT = 3
|
||||
Public Const EN_STEP_CONTROLEVENT = 4
|
||||
|
||||
Public Const EN_MISSING As Double = -10000000000#
|
||||
Public Const EN_SET_CLOSED As Double = -10000000000#
|
||||
Public Const EN_SET_OPEN As Double = 10000000000#
|
||||
|
||||
Public Const EN_FALSE = 0 ' boolean false
|
||||
Public Const EN_TRUE = 1 ' boolean true
|
||||
|
||||
'These are the external functions that comprise the DLL
|
||||
|
||||
@@ -248,11 +293,15 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENepanet Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String, ByVal pviewprog As Any) As Long
|
||||
Declare Function ENinit Lib "epanet2.dll" (ByVal rptFile As String, ByVal outFile As String, ByVal unitsType As Long, ByVal headlossType As Long) As Long
|
||||
Declare Function ENopen Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String) As Long
|
||||
Declare Function ENopenX Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String) As Long
|
||||
Declare Function ENgettitle Lib "epanet2.dll" (ByVal line1 As String, ByVal line2 As String, ByVal line3 As String) As Long
|
||||
Declare Function ENsettitle Lib "epanet2.dll" (ByVal titleline1 As String, ByVal titleline2 As String, ByVal titleline3 As String) As Long
|
||||
Declare Function ENsaveinpfile Lib "epanet2.dll" (ByVal filename As String) As Long
|
||||
Declare Function ENclose Lib "epanet2.dll" () As Long
|
||||
|
||||
Declare Function ENgetcomment Lib "epanet2.dll" (ByVal ObjectType As Long, ByVal index As Long, ByVal comment As String) As Long
|
||||
Declare Function ENsetcomment Lib "epanet2.dll" (ByVal ObjectType As Long, ByVal index As Long, ByVal comment As String) As Long
|
||||
Declare Function ENgettag Lib "epanet2.dll" (ByVal ObjectType As Long, ByVal index As Long, ByVal tag As String) As Long
|
||||
Declare Function ENsettag Lib "epanet2.dll" (ByVal ObjectType As Long, ByVal index As Long, ByVal tag As String) As Long
|
||||
'Hydraulic Analysis Functions
|
||||
Declare Function ENsolveH Lib "epanet2.dll" () As Long
|
||||
Declare Function ENsaveH Lib "epanet2.dll" () As Long
|
||||
@@ -285,6 +334,7 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENgeterror Lib "epanet2.dll" (ByVal errcode As Long, ByVal errmsg As String, ByVal maxLen As Long) As Long
|
||||
Declare Function ENgetstatistic Lib "epanet2.dll" (ByVal type_ As Long, ByRef value As Single) As Long
|
||||
Declare Function ENgetresultindex Lib "epanet2.dll" (ByVal type_ As Long, ByVal index As Long, ByRef value As Long) As Long
|
||||
Declare Function ENtimetonextevent Lib "epanet2.dll" (eventType As Long, duration As Long, elementIndex As Long) As Long
|
||||
|
||||
'Analysis Options Functions
|
||||
Declare Function ENgetoption Lib "epanet2.dll" (ByVal option_ As Long, value As Single) As Long
|
||||
@@ -310,6 +360,7 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENsettankdata Lib "epanet2.dll" (ByVal index As Long, ByVal elev As Single, ByVal initlvl As Single, ByVal minlvl As Single, ByVal maxlvl As Single, ByVal diam As Single, ByVal minvol As Single, ByVal volcurve As String) As Long
|
||||
Declare Function ENgetcoord Lib "epanet2.dll" (ByVal index As Long, x As Double, y As Double) As Long
|
||||
Declare Function ENsetcoord Lib "epanet2.dll" (ByVal index As Long, ByVal x As Double, ByVal y As Double) As Long
|
||||
Declare Function ENgetnodevalues Lib "epanet2.dll" (ByVal property as Long, values as Any) As Long
|
||||
|
||||
'Nodal Demand Functions
|
||||
Declare Function ENgetdemandmodel Lib "epanet2.dll" (type_ As Long, pmin As Single, preq As Single, pexp As Single) As Long
|
||||
@@ -319,7 +370,7 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENgetdemandindex Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandName As String, demandIndex As Long) As Long
|
||||
Declare Function ENgetnumdemands Lib "epanet2.dll" (ByVal nodeIndex As Long, numDemands As Long) As Long
|
||||
Declare Function ENgetbasedemand Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandIndex As Long, value As Single) As Long
|
||||
Declare Function ENsetbasedemand Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandIndex As Long, ByVal BaseDemand As Single) As Long
|
||||
Declare Function ENsetbasedemand Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandIndex As Long, ByVal baseDemand As Single) As Long
|
||||
Declare Function ENgetdemandpattern Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandIndex As Long, patIndex As Long) As Long
|
||||
Declare Function ENsetdemandpattern Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandIndex As Long, ByVal patIndex As Long) As Long
|
||||
Declare Function ENgetdemandname Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandIndex As Long, ByVal demandName As String) As Long
|
||||
@@ -340,7 +391,9 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENsetpipedata Lib "epanet2.dll" (ByVal index As Long, ByVal length As Single, ByVal diam As Single, ByVal rough As Single, ByVal mloss As Single) As Long
|
||||
Declare Function ENgetvertexcount Lib "epanet2.dll" (ByVal index As Long, count As Long) As Long
|
||||
Declare Function ENgetvertex Lib "epanet2.dll" (ByVal index As Long, ByVal vertex As Long, x As Double, y As Double) As Long
|
||||
Declare Function ENsetvertex Lib "epanet2.dll" (ByVal index As Long, ByVal vertex As Long, ByVal x As Double, ByVal y As Double) As Long
|
||||
Declare Function ENsetvertices Lib "epanet2.dll" (ByVal index As Long, xCoords As Any, yCoords As Any, ByVal count As Long) As Long
|
||||
Declare Function ENgetlinkvalues Lib "epanet2.dll" (ByVal property as Long, values as Any) As Long
|
||||
|
||||
'Pump Functions
|
||||
Declare Function ENgetheadcurveindex Lib "epanet2.dll" (ByVal linkIndex As Long, curveIndex As Long) As Long
|
||||
@@ -358,6 +411,7 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENsetpatternvalue Lib "epanet2.dll" (ByVal index As Long, ByVal period As Long, ByVal value As Single) As Long
|
||||
Declare Function ENgetaveragepatternvalue Lib "epanet2.dll" (ByVal index As Long, value As Single) As Long
|
||||
Declare Function ENsetpattern Lib "epanet2.dll" (ByVal index As Long, values As Any, ByVal len_ As Long) As Long
|
||||
Declare Function ENloadpatternfile Lib "epanet2.dll" (ByVal filename As String, ByVal id As String) As Long
|
||||
|
||||
'Data Curve Functions
|
||||
Declare Function ENaddcurve Lib "epanet2.dll" (ByVal id As String) As Long
|
||||
@@ -367,6 +421,7 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENsetcurveid Lib "epanet2.dll" (ByVal index As Long, ByVal newid As String) As Long
|
||||
Declare Function ENgetcurvelen Lib "epanet2.dll" (ByVal index As Long, len_ As Long) As Long
|
||||
Declare Function ENgetcurvetype Lib "epanet2.dll" (ByVal index As Long, type_ As Long) As Long
|
||||
Declare Function ENsetcurvetype Lib "epanet2.dll" (ByVal index As Long, ByVal type_ As Long) As Long
|
||||
Declare Function ENgetcurvevalue Lib "epanet2.dll" (ByVal curveIndex As Long, ByVal pointIndex As Long, x As Single, y As Single) As Long
|
||||
Declare Function ENsetcurvevalue Lib "epanet2.dll" (ByVal curveIndex As Long, ByVal pointIndex As Long, ByVal x As Single, ByVal y As Single) As Long
|
||||
Declare Function ENgetcurve Lib "epanet2.dll" (ByVal index As Long, ByVal id As String, nPoints As Long, xValues As Any, yValues As Any) As Long
|
||||
@@ -377,7 +432,9 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENdeletecontrol Lib "epanet2.dll" (ByVal index As Long) As Long
|
||||
Declare Function ENgetcontrol Lib "epanet2.dll" (ByVal index As Long, type_ As Long, linkIndex As Long, setting As Single, nodeIndex As Long, level As Single) As Long
|
||||
Declare Function ENsetcontrol Lib "epanet2.dll" (ByVal index As Long, ByVal type_ As Long, ByVal linkIndex As Long, ByVal setting As Single, ByVal nodeIndex As Long, ByVal level As Single) As Long
|
||||
|
||||
Declare Function ENgetcontrolenabled Lib "epanet2.dll" (ByVal index As Long, out_enabled As Long) As Long
|
||||
Declare Function ENsetcontrolenabled Lib "epanet2.dll" (ByVal index As Long, ByVal enabled As Long) As Long
|
||||
|
||||
'Rule-Based Control Functions
|
||||
Declare Function ENaddrule Lib "epanet2.dll" (ByVal rule As String) As Long
|
||||
Declare Function ENdeleterule Lib "epanet2.dll" (ByVal index As Long) As Long
|
||||
@@ -393,3 +450,6 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENsetthenaction Lib "epanet2.dll" (ByVal ruleIndex As Long, ByVal actionIndex As Long, ByVal linkIndex As Long, ByVal status As Long, ByVal setting As Single) As Long
|
||||
Declare Function ENgetelseaction Lib "epanet2.dll" (ByVal ruleIndex As Long, ByVal actionIndex As Long, linkIndex As Long, status As Long, setting As Single) As Long
|
||||
Declare Function ENsetelseaction Lib "epanet2.dll" (ByVal ruleIndex As Long, ByVal actionIndex As Long, ByVal linkIndex As Long, ByVal status As Long, ByVal setting As Single) As Long
|
||||
Declare Function ENgetruleenabled Lib "epanet2.dll" (ByVal index As Long, out_enabled As Long) As Long
|
||||
Declare Function ENsetruleenabled Lib "epanet2.dll" (ByVal index As Long, ByVal enabled As Long) As Long
|
||||
|
||||
|
||||
728
include/epanet2.cs
Normal file
728
include/epanet2.cs
Normal file
@@ -0,0 +1,728 @@
|
||||
//using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
//epanet2.cs[By Oscar Vegas]
|
||||
//Last updated on 04/23/2025
|
||||
|
||||
//Declarations of functions in the EPANET PROGRAMMERs TOOLKIT
|
||||
//(EPANET2.DLL) for use with C#
|
||||
|
||||
|
||||
namespace EpanetCSharpLibrary
|
||||
{
|
||||
|
||||
public static class Epanet
|
||||
{
|
||||
|
||||
public const string EPANETDLL = "epanet2.dll";
|
||||
|
||||
//These are codes used by the DLL functions
|
||||
public const int EN_ELEVATION = 0; // Node parameters
|
||||
public const int EN_BASEDEMAND = 1;
|
||||
public const int EN_PATTERN = 2;
|
||||
public const int EN_EMITTER = 3;
|
||||
public const int EN_INITQUAL = 4;
|
||||
public const int EN_SOURCEQUAL = 5;
|
||||
public const int EN_SOURCEPAT = 6;
|
||||
public const int EN_SOURCETYPE = 7;
|
||||
public const int EN_TANKLEVEL = 8;
|
||||
public const int EN_DEMAND = 9;
|
||||
public const int EN_HEAD = 10;
|
||||
public const int EN_PRESSURE = 11;
|
||||
public const int EN_QUALITY = 12;
|
||||
public const int EN_SOURCEMASS = 13;
|
||||
public const int EN_INITVOLUME = 14;
|
||||
public const int EN_MIXMODEL = 15;
|
||||
public const int EN_MIXZONEVOL = 16;
|
||||
|
||||
public const int EN_TANKDIAM = 17;
|
||||
public const int EN_MINVOLUME = 18;
|
||||
public const int EN_VOLCURVE = 19;
|
||||
public const int EN_MINLEVEL = 20;
|
||||
public const int EN_MAXLEVEL = 21;
|
||||
public const int EN_MIXFRACTION = 22;
|
||||
public const int EN_TANK_KBULK = 23;
|
||||
|
||||
public const int EN_TANKVOLUME = 24;
|
||||
public const int EN_MAXVOLUME = 25;
|
||||
public const int EN_CANOVERFLOW = 26;
|
||||
public const int EN_DEMANDDEFICIT = 27;
|
||||
public const int EN_NODE_INCONTROL = 28;
|
||||
public const int EN_EMITTERFLOW = 29;
|
||||
public const int EN_LEAKAGEFLOW = 30;
|
||||
public const int EN_DEMANDFLOW = 31;
|
||||
public const int EN_FULLDEMAND = 32;
|
||||
|
||||
public const int EN_DIAMETER = 0; //Link parameters
|
||||
public const int EN_LENGTH = 1;
|
||||
public const int EN_ROUGHNESS = 2;
|
||||
public const int EN_MINORLOSS = 3;
|
||||
public const int EN_INITSTATUS = 4;
|
||||
public const int EN_INITSETTING = 5;
|
||||
public const int EN_KBULK = 6;
|
||||
public const int EN_KWALL = 7;
|
||||
public const int EN_FLOW = 8;
|
||||
public const int EN_VELOCITY = 9;
|
||||
public const int EN_HEADLOSS = 10;
|
||||
public const int EN_STATUS = 11;
|
||||
public const int EN_SETTING = 12;
|
||||
public const int EN_ENERGY = 13;
|
||||
public const int EN_LINKQUAL = 14;
|
||||
public const int EN_LINKPATTERN = 15;
|
||||
|
||||
public const int EN_PUMP_STATE = 16;
|
||||
public const int EN_PUMP_EFFIC = 17;
|
||||
public const int EN_PUMP_POWER = 18;
|
||||
public const int EN_PUMP_HCURVE = 19;
|
||||
public const int EN_PUMP_ECURVE = 20;
|
||||
public const int EN_PUMP_ECOST = 21;
|
||||
public const int EN_PUMP_EPAT = 22;
|
||||
public const int EN_LINK_INCONTROL = 23;
|
||||
public const int EN_GPV_CURVE = 24;
|
||||
public const int EN_PCV_CURVE = 25;
|
||||
public const int EN_LEAK_AREA = 26;
|
||||
public const int EN_LEAK_EXPAN = 27;
|
||||
public const int EN_LINK_LEAKAGE = 28;
|
||||
public const int EN_VALVE_TYPE = 29;
|
||||
|
||||
public const int EN_DURATION = 0; //Time parameters
|
||||
public const int EN_HYDSTEP = 1;
|
||||
public const int EN_QUALSTEP = 2;
|
||||
public const int EN_PATTERNSTEP = 3;
|
||||
public const int EN_PATTERNSTART = 4;
|
||||
public const int EN_REPORTSTEP = 5;
|
||||
public const int EN_REPORTSTART = 6;
|
||||
public const int EN_RULESTEP = 7;
|
||||
public const int EN_STATISTIC = 8;
|
||||
public const int EN_PERIODS = 9;
|
||||
public const int EN_STARTTIME = 10;
|
||||
public const int EN_HTIME = 11;
|
||||
public const int EN_QTIME = 12;
|
||||
public const int EN_HALTFLAG = 13;
|
||||
public const int EN_NEXTEVENT = 14;
|
||||
|
||||
public const int EN_ITERATIONS = 0;
|
||||
public const int EN_RELATIVEERROR = 1;
|
||||
public const int EN_MAXHEADERROR = 2;
|
||||
public const int EN_MAXFLOWCHANGE = 3;
|
||||
public const int EN_MASSBALANCE = 4;
|
||||
public const int EN_DEFICIENTNODES = 5;
|
||||
public const int EN_DEMANDREDUCTION = 6;
|
||||
public const int EN_LEAKAGELOSS = 7;
|
||||
|
||||
public const int EN_NODE = 0; //Component types
|
||||
public const int EN_LINK = 1;
|
||||
public const int EN_TIMEPAT = 2;
|
||||
public const int EN_CURVE = 3;
|
||||
public const int EN_CONTROL = 4;
|
||||
public const int EN_RULE = 5;
|
||||
|
||||
public const int EN_NODECOUNT = 0; //Component counts
|
||||
public const int EN_TANKCOUNT = 1;
|
||||
public const int EN_LINKCOUNT = 2;
|
||||
public const int EN_PATCOUNT = 3;
|
||||
public const int EN_CURVECOUNT = 4;
|
||||
public const int EN_CONTROLCOUNT = 5;
|
||||
public const int EN_RULECOUNT = 6;
|
||||
|
||||
public const int EN_JUNCTION = 0; //Node types
|
||||
public const int EN_RESERVOIR = 1;
|
||||
public const int EN_TANK = 2;
|
||||
|
||||
public const int EN_CVPIPE = 0; //Link types
|
||||
public const int EN_PIPE = 1;
|
||||
public const int EN_PUMP = 2;
|
||||
public const int EN_PRV = 3;
|
||||
public const int EN_PSV = 4;
|
||||
public const int EN_PBV = 5;
|
||||
public const int EN_FCV = 6;
|
||||
public const int EN_TCV = 7;
|
||||
public const int EN_GPV = 8;
|
||||
public const int EN_PCV = 9;
|
||||
|
||||
public const int EN_NONE = 0; //Quality analysis types
|
||||
public const int EN_CHEM = 1;
|
||||
public const int EN_AGE = 2;
|
||||
public const int EN_TRACE = 3;
|
||||
|
||||
public const int EN_CONCEN = 0; //Source quality types
|
||||
public const int EN_MASS = 1;
|
||||
public const int EN_SETPOINT = 2;
|
||||
public const int EN_FLOWPACED = 3;
|
||||
|
||||
public const int EN_HW = 0; //Head loss formulas
|
||||
public const int EN_DW = 1;
|
||||
public const int EN_CM = 2;
|
||||
|
||||
public const int EN_CFS = 0; //Flow units types
|
||||
public const int EN_GPM = 1;
|
||||
public const int EN_MGD = 2;
|
||||
public const int EN_IMGD = 3;
|
||||
public const int EN_AFD = 4;
|
||||
public const int EN_LPS = 5;
|
||||
public const int EN_LPM = 6;
|
||||
public const int EN_MLD = 7;
|
||||
public const int EN_CMH = 8;
|
||||
public const int EN_CMD = 9;
|
||||
public const int EN_CMS = 10;
|
||||
|
||||
public const int EN_PSI = 0; //Pressure units types
|
||||
public const int EN_KPA = 1;
|
||||
public const int EN_METERS = 2;
|
||||
public const int EN_BAR = 3;
|
||||
public const int EN_FEET = 4;
|
||||
|
||||
public const int EN_DDA = 0; //Demand driven analysis
|
||||
public const int EN_PDA = 1; //Pressure driven analysis
|
||||
|
||||
public const int EN_TRIALS = 0; //Simulation options
|
||||
public const int EN_ACCURACY = 1;
|
||||
public const int EN_TOLERANCE = 2;
|
||||
public const int EN_EMITEXPON = 3;
|
||||
public const int EN_DEMANDMULT = 4;
|
||||
public const int EN_HEADERROR = 5;
|
||||
public const int EN_FLOWCHANGE = 6;
|
||||
public const int EN_HEADLOSSFORM = 7;
|
||||
public const int EN_GLOBALEFFIC = 8;
|
||||
public const int EN_GLOBALPRICE = 9;
|
||||
public const int EN_GLOBALPATTERN = 10;
|
||||
public const int EN_DEMANDCHARGE = 11;
|
||||
public const int EN_SP_GRAVITY = 12;
|
||||
public const int EN_SP_VISCOS = 13;
|
||||
public const int EN_UNBALANCED = 14;
|
||||
public const int EN_CHECKFREQ = 15;
|
||||
public const int EN_MAXCHECK = 16;
|
||||
public const int EN_DAMPLIMIT = 17;
|
||||
public const int EN_SP_DIFFUS = 18;
|
||||
public const int EN_BULKORDER = 19;
|
||||
public const int EN_WALLORDER = 20;
|
||||
public const int EN_TANKORDER = 21;
|
||||
public const int EN_CONCENLIMIT = 22;
|
||||
public const int EN_DEMANDPATTERN = 23;
|
||||
public const int EN_EMITBACKFLOW = 24;
|
||||
public const int EN_PRESS_UNITS = 25;
|
||||
public const int EN_STATUS_REPORT = 26;
|
||||
|
||||
public const int EN_LOWLEVEL = 0; //Control types
|
||||
public const int EN_HILEVEL = 1;
|
||||
public const int EN_TIMER = 2;
|
||||
public const int EN_TIMEOFDAY = 3;
|
||||
|
||||
public const int EN_AVERAGE = 1; //Time statistic types
|
||||
public const int EN_MINIMUM = 2;
|
||||
public const int EN_MAXIMUM = 3;
|
||||
public const int EN_RANGE = 4;
|
||||
|
||||
public const int EN_MIX1 = 0; //Tank mixing models
|
||||
public const int EN_MIX2 = 1;
|
||||
public const int EN_FIFO = 2;
|
||||
public const int EN_LIFO = 3;
|
||||
|
||||
public const int EN_NOSAVE = 0; //Save-results-to-file flag
|
||||
public const int EN_SAVE = 1;
|
||||
public const int EN_INITFLOW = 10; //Re-initialize flow flag
|
||||
public const int EN_SAVE_AND_INIT = 11;
|
||||
|
||||
public const int EN_CONST_HP = 0; //Constant horsepower pump curve
|
||||
public const int EN_POWER_FUNC = 1; //Power function pump curve
|
||||
public const int EN_CUSTOM = 2; //User-defined custom pump curve
|
||||
public const int EN_NOCURVE = 3; //No pump curve
|
||||
|
||||
public const int EN_VOLUME_CURVE = 0; //Volume curve
|
||||
public const int EN_PUMP_CURVE = 1; //Pump curve
|
||||
public const int EN_EFFIC_CURVE = 2; //Efficiency curve
|
||||
public const int EN_HLOSS_CURVE = 3; //Head loss curve
|
||||
public const int EN_GENERIC_CURVE = 4; //Generic curve
|
||||
public const int EN_VALVE_CURVE = 5; //Valve position curve
|
||||
|
||||
public const int EN_UNCONDITIONAL = 0; //Unconditional object deletion
|
||||
public const int EN_CONDITIONAL = 1; //Conditional object deletion
|
||||
|
||||
public const int EN_NO_REPORT = 0; //No status report
|
||||
public const int EN_NORMAL_REPORT = 1; //Normal status report
|
||||
public const int EN_FULL_REPORT = 2; //Full status report
|
||||
|
||||
public const int EN_R_NODE = 6; //Rule objects
|
||||
public const int EN_R_LINK = 7;
|
||||
public const int EN_R_SYSTEM = 8;
|
||||
|
||||
public const int EN_R_DEMAND = 0; //Rule variables
|
||||
public const int EN_R_HEAD = 1;
|
||||
public const int EN_R_GRADE = 2;
|
||||
public const int EN_R_LEVEL = 3;
|
||||
public const int EN_R_PRESSURE = 4;
|
||||
public const int EN_R_FLOW = 5;
|
||||
public const int EN_R_STATUS = 6;
|
||||
public const int EN_R_SETTING = 7;
|
||||
public const int EN_R_POWER = 8;
|
||||
public const int EN_R_TIME = 9;
|
||||
public const int EN_R_CLOCKTIME = 10;
|
||||
public const int EN_R_FILLTIME = 11;
|
||||
public const int EN_R_DRAINTIME = 12;
|
||||
|
||||
public const int EN_R_EQ = 0; //Rule operators
|
||||
public const int EN_R_NE = 1;
|
||||
public const int EN_R_LE = 2;
|
||||
public const int EN_R_GE = 3;
|
||||
public const int EN_R_LT = 4;
|
||||
public const int EN_R_GT = 5;
|
||||
public const int EN_R_IS = 6;
|
||||
public const int EN_R_NOT = 7;
|
||||
public const int EN_R_BELOW = 8;
|
||||
public const int EN_R_ABOVE = 9;
|
||||
|
||||
public const int EN_R_IS_OPEN = 1; //Rule status types
|
||||
public const int EN_R_IS_CLOSED = 2;
|
||||
public const int EN_R_IS_ACTIVE = 3;
|
||||
|
||||
public const double EN_MISSING = -1.0E10;
|
||||
public const double EN_SET_CLOSED = -1.0E10
|
||||
public const double EN_SET_OPEN = 1.0E10
|
||||
|
||||
public const int EN_FALSE = 0 // boolean false
|
||||
public const int EN_TRUE = 1 // boolean true
|
||||
|
||||
#region Epanet Imports
|
||||
|
||||
public delegate void UserSuppliedFunction(string param0);
|
||||
|
||||
|
||||
//Project Functions
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetversion")]
|
||||
public static extern int ENgetversion(ref int version);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENepanet")]
|
||||
public static extern int ENepanet(string inpFile, string rptFile, string outFile, UserSuppliedFunction vfunc);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENopen")]
|
||||
public static extern int ENopen(string inpFile, string rptFile, string outFile);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENopenX")]
|
||||
public static extern int ENopenX(string inpFile, string rptFile, string outFile);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgettitle")]
|
||||
public static extern int ENgettitle(string titleline1, string titleline2, string titleline3);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsettitle")]
|
||||
public static extern int ENsettitle(string titleline1, string titleline2, string titleline3);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetcomment")]
|
||||
public static extern int ENgetcomment(int type, int index, string comment);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetcomment")]
|
||||
public static extern int ENsetcomment(int type, int index, string comment);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgettag")]
|
||||
public static extern int ENgettag(int type, int index, string tag);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsettag")]
|
||||
public static extern int ENsettag(int type, int index, string tag);
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsaveinpfile")]
|
||||
public static extern int ENsaveinpfile(string filename);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENclose")]
|
||||
public static extern int ENclose();
|
||||
|
||||
|
||||
//Hydraulic Analysis Functions
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsolveH")]
|
||||
public static extern int ENsolveH();
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsaveH")]
|
||||
public static extern int ENsaveH();
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENopenH")]
|
||||
public static extern int ENopenH();
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENinitH")]
|
||||
public static extern int ENinitH(int initFlag);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENrunH")]
|
||||
public static extern int ENrunH(ref long currentTime);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENnextH")]
|
||||
public static extern int ENnextH(ref long tStep);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENcloseH")]
|
||||
public static extern int ENcloseH();
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsavehydfile")]
|
||||
public static extern int ENsavehydfile(string filename);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENusehydfile")]
|
||||
public static extern int ENusehydfile(string filename);
|
||||
|
||||
|
||||
//Water Quality Analysis Functions
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsolveQ")]
|
||||
public static extern int ENsolveQ();
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENopenQ")]
|
||||
public static extern int ENopenQ();
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENinitQ")]
|
||||
public static extern int ENinitQ(int saveFlag);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENrunQ")]
|
||||
public static extern int ENrunQ(ref long currentTime);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENnextQ")]
|
||||
public static extern int ENnextQ(ref long tStep);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENstepQ")]
|
||||
public static extern int ENstepQ(ref long timeLeft);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENcloseQ")]
|
||||
public static extern int ENcloseQ();
|
||||
|
||||
|
||||
//Reporting Functions
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENwriteline")]
|
||||
public static extern int ENwriteline(string line);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENreport")]
|
||||
public static extern int ENreport();
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENcopyreport")]
|
||||
public static extern int ENcopyreport(string filename);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENclearreport")]
|
||||
public static extern int ENclearreport();
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENresetreport")]
|
||||
public static extern int ENresetreport();
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetreport")]
|
||||
public static extern int ENsetreport(string format);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetstatusreport")]
|
||||
public static extern int ENsetstatusreport(int level);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetcount")]
|
||||
public static extern int ENgetcount(int code, ref int count);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgeterror")]
|
||||
public static extern int ENgeterror(int errcode, string errmsg, int maxLen);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetstatistic")]
|
||||
public static extern int ENgetstatistic(int type, ref int value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetresultindex")]
|
||||
public static extern int ENgetresultindex(int type, int index, ref int value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENtimetonextevent")]
|
||||
public static extern int ENtimetonextevent(ref int eventType, ref long duration, ref int elementIndex);
|
||||
|
||||
|
||||
//Analysis Options Functions
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetoption")]
|
||||
public static extern int ENgetoption(int option, ref float value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetoption")]
|
||||
public static extern int ENsetoption(int option, ref float value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetflowunits")]
|
||||
public static extern int ENgetflowunits(ref int units);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetflowunits")]
|
||||
public static extern int ENsetflowunits(int units);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgettimeparam")]
|
||||
public static extern int ENgettimeparam(int param, ref int value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsettimeparam")]
|
||||
public static extern int ENsettimeparam(int optioncode, long value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetqualinfo")]
|
||||
public static extern int ENgetqualinfo(ref int qualType, string chemName, string chemUnits, ref int traceNode);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetqualtype")]
|
||||
public static extern int ENgetqualtype(ref int qualType, ref int traceNode);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetqualtype")]
|
||||
public static extern int ENsetqualtype(int qualType, string chemName, string chemUnits, string traceNode);
|
||||
|
||||
|
||||
//Node Functions
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENaddnode")]
|
||||
public static extern int ENaddnode(string id, int nodeType, ref int index);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENdeletenode")]
|
||||
public static extern int ENdeletenode(int index, int actionCode);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetnodeindex")]
|
||||
public static extern int ENgetnodeindex(string id, ref int index);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetnodeid")]
|
||||
public static extern int ENgetnodeid(int index, string id);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetnodeid")]
|
||||
public static extern int ENsetnodeid(int index, string newid);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetnodetype")]
|
||||
public static extern int ENgetnodetype(int index, ref int nodeType);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetnodevalue")]
|
||||
public static extern int ENgetnodevalue(int index, int param, ref float value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetnodevalue")]
|
||||
public static extern int ENsetnodevalue(int index, int param, float value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetjuncdata")]
|
||||
public static extern int ENsetjuncdata(int index, float elev, float dmnd, string dmndpat);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsettankdata")]
|
||||
public static extern int ENsettankdata(int index, float elev, float initlvl, float minlvl, float maxlvl, float diam, float minvol, string volcurve);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetcoord")]
|
||||
public static extern int ENgetcoord(int index, ref double x, ref double y);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetcoord")]
|
||||
public static extern int ENsetcoord(int index, double x, double y);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetnodevalues")]
|
||||
public static extern int ENgetnodevalues(int param, ref float values);
|
||||
|
||||
//Nodal Demand Functions
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetdemandmodel")]
|
||||
public static extern int ENgetdemandmodel(ref int model, ref float pmin, ref float preq, ref float pexp);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetdemandmodel")]
|
||||
public static extern int ENsetdemandmodel(int model, float pmin, float preq, float pexp);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENadddemand")]
|
||||
public static extern int ENadddemand(int nodeIndex, float baseDemand, string demandPattern, string demandName);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENdeletedemand")]
|
||||
public static extern int ENdeletedemand(int nodeIndex, int demandIndex);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetdemandindex")]
|
||||
public static extern int ENgetdemandindex(int nodeIndex, string demandName, ref int demandIndex);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetnumdemands")]
|
||||
public static extern int ENgetnumdemands(int nodeIndex, ref int numDemands);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetbasedemand")]
|
||||
public static extern int ENgetbasedemand(int nodeIndex, int demandIndex, ref float baseDemand);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetbasedemand")]
|
||||
public static extern int ENsetbasedemand(int nodeIndex, int demandIndex, float baseDemand);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetdemandpattern")]
|
||||
public static extern int ENgetdemandpattern(int nodeIndex, int demandIndex, ref int patIndex);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetdemandpattern")]
|
||||
public static extern int ENsetdemandpattern(int nodeIndex, int demandIndex, int patIndex);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetdemandname")]
|
||||
public static extern int ENgetdemandname(int nodeIndex, int demandIndex, string demandName);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetdemandname")]
|
||||
public static extern int ENsetdemandname(int nodeIndex, int demandIndex, string demandName);
|
||||
|
||||
|
||||
//Link Functions
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENaddlink")]
|
||||
public static extern int ENaddlink(string id, int linkType, string fromNode, string toNode, ref int index);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENdeletelink")]
|
||||
public static extern int ENdeletelink(int index, int actionCode);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetlinkindex")]
|
||||
public static extern int ENgetlinkindex(string id, ref int index);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetlinkid")]
|
||||
public static extern int ENgetlinkid(int index, string id);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetlinkid")]
|
||||
public static extern int ENsetlinkid(int index, string newid);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetlinktype")]
|
||||
public static extern int ENgetlinktype(int index, ref int linkType);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetlinktype")]
|
||||
public static extern int ENsetlinktype(ref int index, int linkType, int actionCode);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetlinknodes")]
|
||||
public static extern int ENgetlinknodes(int index, ref int node1, ref int node2);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetlinknodes")]
|
||||
public static extern int ENsetlinknodes(int index, int node1, int node2);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetlinkvalue")]
|
||||
public static extern int ENgetlinkvalue(int index, int param, ref float value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetlinkvalue")]
|
||||
public static extern int ENsetlinkvalue(int index, int param, float value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetpipedata")]
|
||||
public static extern int ENsetpipedata(int index, float length, float diam, float rough, float mloss);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetvertexcount")]
|
||||
public static extern int ENgetvertexcount(int index, ref int count);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetvertex")]
|
||||
public static extern int ENgetvertex(int index, int vertex, ref double x, ref double y);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetvertices")]
|
||||
public static extern int ENsetvertices(int index, ref double[] x, ref double[] y, int count);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetlinkvalues")]
|
||||
public static extern int ENgetlinkvalues(int param, ref float values);
|
||||
|
||||
|
||||
//Pump Functions
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetheadcurveindex")]
|
||||
public static extern int ENgetheadcurveindex(int linkIndex, ref int curveIndex);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetheadcurveindex")]
|
||||
public static extern int ENsetheadcurveindex(int linkIndex, int curveIndex);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetpumptype")]
|
||||
public static extern int ENgetpumptype(int linkIndex, ref int pumpType);
|
||||
|
||||
|
||||
//Time Pattern Functions
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENaddpattern")]
|
||||
public static extern int ENaddpattern(string id);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENdeletepattern")]
|
||||
public static extern int ENdeletepattern(int index);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetpatternindex")]
|
||||
public static extern int ENgetpatternindex(string id, ref int index);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetpatternid")]
|
||||
public static extern int ENgetpatternid(int index, string id);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetpatternid")]
|
||||
public static extern int ENsetpatternid(int index, string id);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetpatternlen")]
|
||||
public static extern int ENgetpatternlen(int index, ref int len);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetpatternvalue")]
|
||||
public static extern int ENgetpatternvalue(int index, int period, ref float value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetpatternvalue")]
|
||||
public static extern int ENsetpatternvalue(int index, int period, float value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetaveragepatternvalue")]
|
||||
public static extern int ENgetaveragepatternvalue(int index, ref float value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetpattern")]
|
||||
public static extern int ENsetpattern(int index, ref float[] values, int len);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENloadpatternfile")]
|
||||
public static extern int ENdeletepattern(string filename, string id);
|
||||
|
||||
|
||||
//Data Curve Functions
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENaddcurve")]
|
||||
public static extern int ENaddcurve(string id);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENdeletecurve")]
|
||||
public static extern int ENdeletecurve(int index);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetcurveindex")]
|
||||
public static extern int ENgetcurveindex(string id, ref int index);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetcurveid")]
|
||||
public static extern int ENgetcurveid(int index, string id);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetcurveid")]
|
||||
public static extern int ENsetcurveid(int index, string id);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetcurvelen")]
|
||||
public static extern int ENgetcurvelen(int index, ref int len);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetcurvetype")]
|
||||
public static extern int ENgetcurvetype(int index, ref int type);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetcurvevalue")]
|
||||
public static extern int ENgetcurvevalue(int curveIndex, int pointIndex, ref float x, ref float y);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetcurvevalue")]
|
||||
public static extern int ENsetcurvevalue(int curveIndex, int pointIndex, float x, float y);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetcurve")]
|
||||
public static extern int ENgetcurve(int index, string id, ref int nPoints, ref float xValues, ref float yValues);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetcurve")]
|
||||
public static extern int ENsetcurve(int index, ref float[] xValues, ref float[] yValues, int nPoints);
|
||||
|
||||
|
||||
//Simple Control Functions
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENaddcontrol")]
|
||||
public static extern int ENaddcontrol(int type, int linkIndex, float setting, int nodeIndex, float level, ref int index);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENdeletecontrol")]
|
||||
public static extern int ENdeletecontrol(int index);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetcontrol")]
|
||||
public static extern int ENgetcontrol(int index, ref int type, ref int linkIndex, ref float setting, ref int nodeIndex, ref float level);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetcontrol")]
|
||||
public static extern int ENsetcontrol(int index, int type, int linkIndex, float setting, int nodeIndex, float level);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetcontrolenabled")]
|
||||
public static extern int ENgetcontrolenabled(int index, ref int out_enabled);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetcontrolenabled")]
|
||||
public static extern int ENsetcontrolenabled(int index, int enabled);
|
||||
|
||||
|
||||
//Rule-Based Control Functions
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENaddrule")]
|
||||
public static extern int ENaddrule(string rule);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENdeleterule")]
|
||||
public static extern int ENdeleterule(int index);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetrule")]
|
||||
public static extern int ENgetrule(int index, ref int nPremises, ref int nThenActions, ref int nElseActions, ref float priority);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetruleID")]
|
||||
public static extern int ENgetruleID(int index, string id);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetrulepriority")]
|
||||
public static extern int ENsetcurvENsetrulepriorityeid(int index, float priority);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetpremise")]
|
||||
public static extern int ENgetpremise(int ruleIndex, int premiseIndex, ref int logop, ref int objectt, ref int objIndex, ref int variable, ref int relop, ref int status, ref float value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetpremise")]
|
||||
public static extern int ENsetpremise(int ruleIndex, int premiseIndex, int logop, int objectt, int objIndex, int variable, int relop, int status, float value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetpremiseindex")]
|
||||
public static extern int ENsetpremiseindex(int ruleIndex, int premiseIndex, int objIndex);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetpremisestatus")]
|
||||
public static extern int ENsetpremisestatus(int ruleIndex, int premiseIndex, int status);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetpremisevalue")]
|
||||
public static extern int ENsetpremisevalue(int ruleIndex, int premiseIndex, float value);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetthenaction")]
|
||||
public static extern int ENgetthenaction(int ruleIndex, int actionIndex, ref int linkIndex, ref int status, ref float setting);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetthenaction")]
|
||||
public static extern int ENsetthenaction(int ruleIndex, int actionIndex, int linkIndex, int status, float setting);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetelseaction")]
|
||||
public static extern int ENgetelseaction(int ruleIndex, int actionIndex, ref int linkIndex, ref int status, ref float setting);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetelseaction")]
|
||||
public static extern int ENsetelseaction(int ruleIndex, int actionIndex, int linkIndex, int status, float setting);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENgetruleenabled")]
|
||||
public static extern int ENgetruleenabled(int index, ref int out_enabled);
|
||||
|
||||
[DllImport(EPANETDLL, EntryPoint = "ENsetruleenabled")]
|
||||
public static extern int ENsetruleenabled(int index, int enabled);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,6 +25,7 @@ EXPORTS
|
||||
ENgetbasedemand = _ENgetbasedemand@12
|
||||
ENgetcomment = _ENgetcomment@12
|
||||
ENgetcontrol = _ENgetcontrol@24
|
||||
ENgetcontrolenabled = _ENgetcontrolenabled@8
|
||||
ENgetcoord = _ENgetcoord@12
|
||||
ENgetcount = _ENgetcount@8
|
||||
ENgetcurve = _ENgetcurve@20
|
||||
@@ -44,13 +45,14 @@ EXPORTS
|
||||
ENgetlinkid = _ENgetlinkid@8
|
||||
ENgetlinkindex = _ENgetlinkindex@8
|
||||
ENgetlinknodes = _ENgetlinknodes@12
|
||||
ENsetlinknodes = _ENsetlinknodes@12
|
||||
ENgetlinktype = _ENgetlinktype@8
|
||||
ENgetlinkvalue = _ENgetlinkvalue@12
|
||||
ENgetlinkvalues = _ENgetlinkvalues@8
|
||||
ENgetnodeid = _ENgetnodeid@8
|
||||
ENgetnodeindex = _ENgetnodeindex@8
|
||||
ENgetnodetype = _ENgetnodetype@8
|
||||
ENgetnodevalue = _ENgetnodevalue@12
|
||||
ENgetnodevalue = _ENgetnodevalue@12
|
||||
ENgetnodevalues = _ENgetnodevalues@8
|
||||
ENgetnumdemands = _ENgetnumdemands@8
|
||||
ENgetoption = _ENgetoption@8
|
||||
ENgetpatternid = _ENgetpatternid@8
|
||||
@@ -63,8 +65,10 @@ EXPORTS
|
||||
ENgetqualtype = _ENgetqualtype@8
|
||||
ENgetresultindex = _ENgetresultindex@12
|
||||
ENgetrule = _ENgetrule@20
|
||||
ENgetruleenabled = _ENgetruleenabled@8
|
||||
ENgetruleID = _ENgetruleID@8
|
||||
ENgetstatistic = _ENgetstatistic@8
|
||||
ENgettag = _ENgettag@12
|
||||
ENgetthenaction = _ENgetthenaction@20
|
||||
ENgettimeparam = _ENgettimeparam@8
|
||||
ENgettitle = _ENgettitle@12
|
||||
@@ -73,12 +77,14 @@ EXPORTS
|
||||
ENgetvertexcount = _ENgetvertexcount@8
|
||||
ENinit = _ENinit@16
|
||||
ENinitH = _ENinitH@4
|
||||
ENinitQ = _ENinitQ@4
|
||||
ENinitQ = _ENinitQ@4
|
||||
ENloadpatternfile = _ENloadpatternfile@8
|
||||
ENnextH = _ENnextH@4
|
||||
ENnextQ = _ENnextQ@4
|
||||
ENopen = _ENopen@12
|
||||
ENopenH = _ENopenH@0
|
||||
ENopenQ = _ENopenQ@0
|
||||
ENopenX = _ENopenX@12
|
||||
ENreport = _ENreport@0
|
||||
ENresetreport = _ENresetreport@0
|
||||
ENrunH = _ENrunH@4
|
||||
@@ -89,9 +95,11 @@ EXPORTS
|
||||
ENsetbasedemand = _ENsetbasedemand@12
|
||||
ENsetcomment = _ENsetcomment@12
|
||||
ENsetcontrol = _ENsetcontrol@24
|
||||
ENsetcontrolenabled = _ENsetcontrolenabled@8
|
||||
ENsetcoord = _ENsetcoord@20
|
||||
ENsetcurve = _ENsetcurve@16
|
||||
ENsetcurveid = _ENsetcurveid@8
|
||||
ENsetcurveid = _ENsetcurveid@8
|
||||
ENsetcurvetype = _ENsetcurvetype@8
|
||||
ENsetcurvevalue = _ENsetcurvevalue@16
|
||||
ENsetdemandmodel = _ENsetdemandmodel@16
|
||||
ENsetdemandname = _ENsetdemandname@12
|
||||
@@ -117,15 +125,19 @@ EXPORTS
|
||||
ENsetpremisevalue = _ENsetpremisevalue@12
|
||||
ENsetqualtype = _ENsetqualtype@16
|
||||
ENsetreport = _ENsetreport@4
|
||||
ENsetruleenabled = _ENsetruleenabled@8
|
||||
ENsetrulepriority = _ENsetrulepriority@8
|
||||
ENsetstatusreport = _ENsetstatusreport@4
|
||||
ENsettag = _ENsettag@12
|
||||
ENsettankdata = _ENsettankdata@32
|
||||
ENsetthenaction = _ENsetthenaction@20
|
||||
ENsettimeparam = _ENsettimeparam@8
|
||||
ENsettitle = _ENsettitle@12
|
||||
ENsettitle = _ENsettitle@12
|
||||
ENsetvertex = _ENsetvertex@24
|
||||
ENsetvertices = _ENsetvertices@16
|
||||
ENsolveH = _ENsolveH@0
|
||||
ENsolveQ = _ENsolveQ@0
|
||||
ENstepQ = _ENstepQ@4
|
||||
ENtimetonextevent = _ENtimetonextevent@12
|
||||
ENusehydfile = _ENusehydfile@4
|
||||
ENwriteline = _ENwriteline@4
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: epanet2.h
|
||||
Description: declarations of the legacy style EPANET 2 API functions
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 10/29/2019
|
||||
Last Updated: 02/14/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -18,7 +18,7 @@ set of thread safe API functions that allows one to run concurrent analyses on
|
||||
multiple EPANET projects can be found in the epanet2_2.h header file. The two
|
||||
APIs share the same function names and arguments with the difference being that
|
||||
the thread safe functions use the prefix "EN_" and include an extra argument that
|
||||
represents the EPANET project being analyzed. To avoid unneccesary repetition,
|
||||
represents the EPANET project being analyzed. To avoid unnecessary repetition,
|
||||
only the thread safe API functions have been documented. To see a description of
|
||||
a legacy style API function declared here please refer to its complementary named
|
||||
function in epanet2_2.h.
|
||||
@@ -72,14 +72,21 @@ extern "C" {
|
||||
|
||||
int DLLEXPORT ENopen(const char *inpFile, const char *rptFile,
|
||||
const char *outFile);
|
||||
|
||||
|
||||
int DLLEXPORT ENopenX(const char *inpFile, const char *rptFile,
|
||||
const char *outFile);
|
||||
|
||||
int DLLEXPORT ENgettitle(char *line1, char *line2, char *line3);
|
||||
|
||||
int DLLEXPORT ENsettitle(char *line1, char *line2, char *line3);
|
||||
|
||||
int DLLEXPORT ENsettitle(const char *line1, const char *line2, const char *line3);
|
||||
|
||||
int DLLEXPORT ENgetcomment(int object, int index, char *comment);
|
||||
|
||||
int DLLEXPORT ENsetcomment(int object, int index, char *comment);
|
||||
int DLLEXPORT ENsetcomment(int object, int index, const char *comment);
|
||||
|
||||
int DLLEXPORT ENgettag(int object, int index, char *tag);
|
||||
|
||||
int DLLEXPORT ENsettag(int object, int index, const char *tag);
|
||||
|
||||
int DLLEXPORT ENgetcount(int object, int *count);
|
||||
|
||||
@@ -107,9 +114,9 @@ extern "C" {
|
||||
|
||||
int DLLEXPORT ENcloseH();
|
||||
|
||||
int DLLEXPORT ENsavehydfile(char *filename);
|
||||
int DLLEXPORT ENsavehydfile(const char *filename);
|
||||
|
||||
int DLLEXPORT ENusehydfile(char *filename);
|
||||
int DLLEXPORT ENusehydfile(const char *filename);
|
||||
|
||||
/********************************************************************
|
||||
|
||||
@@ -137,17 +144,17 @@ extern "C" {
|
||||
|
||||
********************************************************************/
|
||||
|
||||
int DLLEXPORT ENwriteline(char *line);
|
||||
int DLLEXPORT ENwriteline(const char *line);
|
||||
|
||||
int DLLEXPORT ENreport();
|
||||
|
||||
int DLLEXPORT ENcopyreport(char *filename);
|
||||
int DLLEXPORT ENcopyreport(const char *filename);
|
||||
|
||||
int DLLEXPORT ENclearreport();
|
||||
|
||||
int DLLEXPORT ENresetreport();
|
||||
|
||||
int DLLEXPORT ENsetreport(char *format);
|
||||
int DLLEXPORT ENsetreport(const char *format);
|
||||
|
||||
int DLLEXPORT ENsetstatusreport(int level);
|
||||
|
||||
@@ -156,9 +163,16 @@ extern "C" {
|
||||
int DLLEXPORT ENgeterror(int errcode, char *errmsg, int maxLen);
|
||||
|
||||
int DLLEXPORT ENgetstatistic(int type, EN_API_FLOAT_TYPE* value);
|
||||
|
||||
|
||||
int DLLEXPORT ENgetresultindex(int type, int index, int *value);
|
||||
|
||||
int DLLEXPORT ENtimetonextevent(int *eventType, long *duration, int *elementIndex);
|
||||
|
||||
int DLLEXPORT ENsetreportcallback(void (*callback)(void *userData, void *EN_projectHandle, const char*));
|
||||
|
||||
int DLLEXPORT ENsetreportcallbackuserdata(void *userData);
|
||||
|
||||
|
||||
/********************************************************************
|
||||
|
||||
Analysis Options Functions
|
||||
@@ -182,8 +196,8 @@ extern "C" {
|
||||
|
||||
int DLLEXPORT ENgetqualtype(int *qualType, int *traceNode);
|
||||
|
||||
int DLLEXPORT ENsetqualtype(int qualType, char *chemName, char *chemUnits,
|
||||
char *traceNode);
|
||||
int DLLEXPORT ENsetqualtype(int qualType, const char *chemName,
|
||||
const char *chemUnits, const char *traceNode);
|
||||
|
||||
/********************************************************************
|
||||
|
||||
@@ -191,29 +205,31 @@ extern "C" {
|
||||
|
||||
********************************************************************/
|
||||
|
||||
int DLLEXPORT ENaddnode(char *id, int nodeType, int *index);
|
||||
int DLLEXPORT ENaddnode(const char *id, int nodeType, int *index);
|
||||
|
||||
int DLLEXPORT ENdeletenode(int index, int actionCode);
|
||||
|
||||
int DLLEXPORT ENgetnodeindex(char *id, int *index);
|
||||
int DLLEXPORT ENgetnodeindex(const char *id, int *index);
|
||||
|
||||
int DLLEXPORT ENgetnodeid(int index, char *id);
|
||||
|
||||
int DLLEXPORT ENsetnodeid(int index, char *newid);
|
||||
int DLLEXPORT ENsetnodeid(int index, const char *newid);
|
||||
|
||||
int DLLEXPORT ENgetnodetype(int index, int *nodeType);
|
||||
|
||||
int DLLEXPORT ENgetnodevalue(int index, int property, EN_API_FLOAT_TYPE *value);
|
||||
|
||||
int DLLEXPORT ENgetnodevalues(int property, EN_API_FLOAT_TYPE *value);
|
||||
|
||||
int DLLEXPORT ENsetnodevalue(int index, int property, EN_API_FLOAT_TYPE value);
|
||||
|
||||
int DLLEXPORT ENsetjuncdata(int index, EN_API_FLOAT_TYPE elev,
|
||||
EN_API_FLOAT_TYPE dmnd, char *dmndpat);
|
||||
EN_API_FLOAT_TYPE dmnd, const char *dmndpat);
|
||||
|
||||
int DLLEXPORT ENsettankdata(int index, EN_API_FLOAT_TYPE elev,
|
||||
EN_API_FLOAT_TYPE initlvl, EN_API_FLOAT_TYPE minlvl,
|
||||
EN_API_FLOAT_TYPE maxlvl, EN_API_FLOAT_TYPE diam,
|
||||
EN_API_FLOAT_TYPE minvol, char *volcurve);
|
||||
EN_API_FLOAT_TYPE minvol, const char *volcurve);
|
||||
|
||||
int DLLEXPORT ENgetcoord(int index, double *x, double *y);
|
||||
|
||||
@@ -232,13 +248,14 @@ extern "C" {
|
||||
EN_API_FLOAT_TYPE preq, EN_API_FLOAT_TYPE pexp);
|
||||
|
||||
int DLLEXPORT ENadddemand(int nodeIndex, EN_API_FLOAT_TYPE baseDemand,
|
||||
char *demandPattern, char *demandName);
|
||||
const char *demandPattern, const char *demandName);
|
||||
|
||||
int DLLEXPORT ENdeletedemand(int nodeIndex, int demandIndex);
|
||||
|
||||
|
||||
int DLLEXPORT ENgetnumdemands(int nodeIndex, int *numDemands);
|
||||
|
||||
int DLLEXPORT ENgetdemandindex(int nodeIndex, char *demandName, int *demandIndex);
|
||||
int DLLEXPORT ENgetdemandindex(int nodeIndex, const char *demandName,
|
||||
int *demandIndex);
|
||||
|
||||
int DLLEXPORT ENgetbasedemand(int nodeIndex, int demandIndex,
|
||||
EN_API_FLOAT_TYPE *baseDemand);
|
||||
@@ -252,7 +269,7 @@ extern "C" {
|
||||
|
||||
int DLLEXPORT ENgetdemandname(int nodeIndex, int demandIndex, char *demandName);
|
||||
|
||||
int DLLEXPORT ENsetdemandname(int nodeIndex, int demandIndex, char *demandName);
|
||||
int DLLEXPORT ENsetdemandname(int nodeIndex, int demandIndex, const char *demandName);
|
||||
|
||||
/********************************************************************
|
||||
|
||||
@@ -260,15 +277,16 @@ extern "C" {
|
||||
|
||||
********************************************************************/
|
||||
|
||||
int DLLEXPORT ENaddlink(char *id, int linkType, char *fromNode, char *toNode, int *index);
|
||||
int DLLEXPORT ENaddlink(const char *id, int linkType, const char *fromNode,
|
||||
const char *toNode, int *index);
|
||||
|
||||
int DLLEXPORT ENdeletelink(int index, int actionCode);
|
||||
|
||||
int DLLEXPORT ENgetlinkindex(char *id, int *index);
|
||||
int DLLEXPORT ENgetlinkindex(const char *id, int *index);
|
||||
|
||||
int DLLEXPORT ENgetlinkid(int index, char *id);
|
||||
|
||||
int DLLEXPORT ENsetlinkid(int index, char *newid);
|
||||
int DLLEXPORT ENsetlinkid(int index, const char *newid);
|
||||
|
||||
int DLLEXPORT ENgetlinktype(int index, int *linkType);
|
||||
|
||||
@@ -280,16 +298,20 @@ extern "C" {
|
||||
|
||||
int DLLEXPORT ENgetlinkvalue(int index, int property, EN_API_FLOAT_TYPE *value);
|
||||
|
||||
int DLLEXPORT ENgetlinkvalues(int property, EN_API_FLOAT_TYPE *value);
|
||||
|
||||
int DLLEXPORT ENsetlinkvalue(int index, int property, EN_API_FLOAT_TYPE value);
|
||||
|
||||
int DLLEXPORT ENsetpipedata(int index, EN_API_FLOAT_TYPE length,
|
||||
EN_API_FLOAT_TYPE diam, EN_API_FLOAT_TYPE rough,
|
||||
EN_API_FLOAT_TYPE mloss);
|
||||
|
||||
|
||||
int DLLEXPORT ENgetvertexcount(int index, int *count);
|
||||
|
||||
|
||||
int DLLEXPORT ENgetvertex(int index, int vertex, double *x, double *y);
|
||||
|
||||
|
||||
int DLLEXPORT ENsetvertex(int index, int vertex, double x, double y);
|
||||
|
||||
int DLLEXPORT ENsetvertices(int index, double *x, double *y, int count);
|
||||
|
||||
/********************************************************************
|
||||
@@ -310,15 +332,15 @@ extern "C" {
|
||||
|
||||
********************************************************************/
|
||||
|
||||
int DLLEXPORT ENaddpattern(char *id);
|
||||
int DLLEXPORT ENaddpattern(const char *id);
|
||||
|
||||
int DLLEXPORT ENdeletepattern(int index);
|
||||
|
||||
int DLLEXPORT ENgetpatternindex(char *id, int *index);
|
||||
int DLLEXPORT ENgetpatternindex(const char *id, int *index);
|
||||
|
||||
int DLLEXPORT ENgetpatternid(int index, char *id);
|
||||
|
||||
int DLLEXPORT ENsetpatternid(int index, char *id);
|
||||
int DLLEXPORT ENsetpatternid(int index, const char *id);
|
||||
|
||||
int DLLEXPORT ENgetpatternlen(int index, int *len);
|
||||
|
||||
@@ -330,26 +352,30 @@ extern "C" {
|
||||
|
||||
int DLLEXPORT ENsetpattern(int index, EN_API_FLOAT_TYPE *values, int len);
|
||||
|
||||
int DLLEXPORT ENloadpatternfile(const char *filename, const char *id);
|
||||
|
||||
/********************************************************************
|
||||
|
||||
Data Curve Functions
|
||||
|
||||
********************************************************************/
|
||||
|
||||
int DLLEXPORT ENaddcurve(char *id);
|
||||
int DLLEXPORT ENaddcurve(const char *id);
|
||||
|
||||
int DLLEXPORT ENdeletecurve(int index);
|
||||
|
||||
int DLLEXPORT ENgetcurveindex(char *id, int *index);
|
||||
int DLLEXPORT ENgetcurveindex(const char *id, int *index);
|
||||
|
||||
int DLLEXPORT ENgetcurveid(int index, char *id);
|
||||
|
||||
int DLLEXPORT ENsetcurveid(int index, char *id);
|
||||
int DLLEXPORT ENsetcurveid(int index, const char *id);
|
||||
|
||||
int DLLEXPORT ENgetcurvelen(int index, int *len);
|
||||
|
||||
int DLLEXPORT ENgetcurvetype(int index, int *type);
|
||||
|
||||
int DLLEXPORT ENsetcurvetype(int index, int type);
|
||||
|
||||
int DLLEXPORT ENgetcurvevalue(int curveIndex, int pointIndex,
|
||||
EN_API_FLOAT_TYPE *x, EN_API_FLOAT_TYPE *y);
|
||||
|
||||
@@ -379,6 +405,9 @@ extern "C" {
|
||||
int DLLEXPORT ENsetcontrol(int index, int type, int linkIndex,
|
||||
EN_API_FLOAT_TYPE setting, int nodeIndex, EN_API_FLOAT_TYPE level);
|
||||
|
||||
int DLLEXPORT ENgetcontrolenabled(int index, int *out_enabled);
|
||||
|
||||
int DLLEXPORT ENsetcontrolenabled(int index, int enabled);
|
||||
|
||||
/********************************************************************
|
||||
|
||||
@@ -421,9 +450,13 @@ extern "C" {
|
||||
|
||||
int DLLEXPORT ENsetelseaction(int ruleIndex, int actionIndex, int linkIndex,
|
||||
int status, EN_API_FLOAT_TYPE setting);
|
||||
|
||||
|
||||
int DLLEXPORT ENsetrulepriority(int index, EN_API_FLOAT_TYPE priority);
|
||||
|
||||
int DLLEXPORT ENgetruleenabled(int index, int *out_enabled);
|
||||
|
||||
int DLLEXPORT ENsetruleenabled(int index, int enabled);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@ unit epanet2;
|
||||
{ Declarations of imported procedures from the EPANET PROGRAMMERs TOOLKIT }
|
||||
{ (EPANET2.DLL) }
|
||||
|
||||
{Last updated on 11/12/19}
|
||||
{Last updated on 04/23/2025}
|
||||
|
||||
interface
|
||||
|
||||
@@ -12,7 +12,9 @@ const
|
||||
{ These are codes used by the DLL functions }
|
||||
EN_MAXID = 31; { Max. # characters in ID name }
|
||||
EN_MAXMSG = 255; { Max. # characters in strings }
|
||||
EN_MISSING = -1.E10;
|
||||
EN_MISSING = -1.0E10;
|
||||
EN_SET_CLOSED = -1.0E10;
|
||||
EN_SET_OPEN = 1.0E10;
|
||||
|
||||
EN_ELEVATION = 0; { Node parameters }
|
||||
EN_BASEDEMAND = 1;
|
||||
@@ -31,7 +33,6 @@ const
|
||||
EN_INITVOLUME = 14;
|
||||
EN_MIXMODEL = 15;
|
||||
EN_MIXZONEVOL = 16;
|
||||
|
||||
EN_TANKDIAM = 17;
|
||||
EN_MINVOLUME = 18;
|
||||
EN_VOLCURVE = 19;
|
||||
@@ -42,7 +43,12 @@ const
|
||||
EN_TANKVOLUME = 24;
|
||||
EN_MAXVOLUME = 25;
|
||||
EN_CANOVERFLOW = 26;
|
||||
EN_DEMANDDEFICIT = 27;
|
||||
EN_DEMANDDEFICIT = 27;
|
||||
EN_NODE_INCONTROL = 28;
|
||||
EN_EMITTERFLOW = 29;
|
||||
EN_LEAKAGEFLOW = 30;
|
||||
EN_DEMANDFLOW = 31;
|
||||
EN_FULLDEMAND = 32;
|
||||
|
||||
EN_DIAMETER = 0; { Link parameters }
|
||||
EN_LENGTH = 1;
|
||||
@@ -67,6 +73,13 @@ const
|
||||
EN_PUMP_ECURVE = 20;
|
||||
EN_PUMP_ECOST = 21;
|
||||
EN_PUMP_EPAT = 22;
|
||||
EN_LINK_INCONTROL = 23;
|
||||
EN_GPV_CURVE = 24;
|
||||
EN_PCV_CURVE = 25;
|
||||
EN_LEAK_AREA = 26;
|
||||
EN_LEAK_EXPAN = 27;
|
||||
EN_LINK_LEAKAGE = 28;
|
||||
EN_VALVE_TYPE = 29;
|
||||
|
||||
EN_DURATION = 0; { Time parameters }
|
||||
EN_HYDSTEP = 1;
|
||||
@@ -92,6 +105,7 @@ const
|
||||
EN_MASSBALANCE = 4;
|
||||
EN_DEFICIENTNODES = 5;
|
||||
EN_DEMANDREDUCTION = 6;
|
||||
EN_LEAKAGELOSS = 7;
|
||||
|
||||
EN_NODE = 0; { Component Types }
|
||||
EN_LINK = 1;
|
||||
@@ -121,6 +135,7 @@ const
|
||||
EN_FCV = 6;
|
||||
EN_TCV = 7;
|
||||
EN_GPV = 8;
|
||||
EN_PCV = 9;
|
||||
|
||||
EN_CLOSED = 0; { Link status types }
|
||||
EN_OPEN = 1;
|
||||
@@ -154,6 +169,13 @@ const
|
||||
EN_MLD = 7;
|
||||
EN_CMH = 8;
|
||||
EN_CMD = 9;
|
||||
EN_CMS = 10;
|
||||
|
||||
EN_PSI = 0; { Pressure units types }
|
||||
EN_KPA = 1;
|
||||
EN_METERS = 2;
|
||||
EN_BAR = 3;
|
||||
EN_FEET = 4;
|
||||
|
||||
EN_DDA = 0; { Demand model types }
|
||||
EN_PDA = 1;
|
||||
@@ -181,6 +203,10 @@ const
|
||||
EN_WALLORDER = 20;
|
||||
EN_TANKORDER = 21;
|
||||
EN_CONCENLIMIT = 22;
|
||||
EN_DEMANDPATTERN = 23;
|
||||
EN_EMITBACKFLOW = 24;
|
||||
EN_PRESS_UNITS = 25;
|
||||
EN_STATUS_REPORT = 26;
|
||||
|
||||
EN_LOWLEVEL = 0; { Control types }
|
||||
EN_HILEVEL = 1;
|
||||
@@ -212,7 +238,8 @@ const
|
||||
EN_PUMP_CURVE = 1;
|
||||
EN_EFFIC_CURVE = 2;
|
||||
EN_HLOSS_CURVE = 3;
|
||||
EN_GENERIC_CURVE = 4;
|
||||
EN_GENERIC_CURVE = 4;
|
||||
EN_VALVE_CURVE = 5;
|
||||
|
||||
EN_UNCONDITIONAL = 0; { Deletion action codes }
|
||||
EN_CONDITIONAL = 1;
|
||||
@@ -254,169 +281,205 @@ const
|
||||
EN_R_IS_CLOSED = 2;
|
||||
EN_R_IS_ACTIVE = 3;
|
||||
|
||||
EpanetLib = 'epanet2.dll';
|
||||
EN_FALSE = 0; { boolean false }
|
||||
EN_TRUE = 1; { boolean true }
|
||||
|
||||
|
||||
{$MACRO ON}
|
||||
|
||||
{$ifdef MSWINDOWS}
|
||||
EpanetLib = 'epanet2.dll';
|
||||
{$DEFINE cdecl := stdcall}
|
||||
{$endif}
|
||||
|
||||
{$ifdef UNIX}
|
||||
{$ifdef DARWIN}
|
||||
EpanetLib = 'libepanet2.dylib';
|
||||
{$linklib libepanet2}
|
||||
{$else}
|
||||
EpanetLib = 'libepanet2.so';
|
||||
{$endif}
|
||||
{$endif}
|
||||
|
||||
{$ifdef UNIX}
|
||||
{$DEFINE TimeType:=Int64}
|
||||
{$else}
|
||||
{$DEFINE TimeType:=Integer}
|
||||
{$endif}
|
||||
|
||||
{Project Functions}
|
||||
function ENepanet(F1: PAnsiChar; F2: PAnsiChar; F3: PAnsiChar; F4: Pointer): Integer; stdcall; external EpanetLib;
|
||||
function ENinit(F2: PAnsiChar; F3: PAnsiChar; UnitsType: Integer; HeadlossType: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENopen(F1: PAnsiChar; F2: PAnsiChar; F3: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENgetcount(Code: Integer; var Count: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgettitle(Line1: PAnsiChar; Line2: PAnsiChar; Line3: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENsettitle(Line1: PAnsiChar; Line2: PAnsiChar; Line3: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENgetcomment(ObjType: Integer; Index: Integer; Comment: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENsetcomment(ObjType: Integer; Index: Integer; Comment: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENsaveinpfile(F: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENclose: Integer; stdcall; external EpanetLib;
|
||||
function ENepanet(F1: PAnsiChar; F2: PAnsiChar; F3: PAnsiChar; F4: Pointer): Integer; cdecl; external EpanetLib;
|
||||
function ENinit(F2: PAnsiChar; F3: PAnsiChar; UnitsType: Integer; HeadlossType: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENopen(F1: PAnsiChar; F2: PAnsiChar; F3: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENopenX(F1: PAnsiChar; F2: PAnsiChar; F3: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENgetcount(Code: Integer; var Count: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgettitle(Line1: PAnsiChar; Line2: PAnsiChar; Line3: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENsettitle(Line1: PAnsiChar; Line2: PAnsiChar; Line3: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENgetcomment(ObjType: Integer; Index: Integer; Comment: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENsetcomment(ObjType: Integer; Index: Integer; Comment: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENgettag(ObjType: Integer; Index: Integer; Tag: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENsettag(ObjType: Integer; Index: Integer; Tag: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENsaveinpfile(F: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENclose: Integer; cdecl; external EpanetLib;
|
||||
|
||||
{Hydraulic Functions}
|
||||
function ENsolveH: Integer; stdcall; external EpanetLib;
|
||||
function ENsaveH: Integer; stdcall; external EpanetLib;
|
||||
function ENopenH: Integer; stdcall; external EpanetLib;
|
||||
function ENinitH(SaveFlag: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENrunH(var T: LongInt): Integer; stdcall; external EpanetLib;
|
||||
function ENnextH(var Tstep: LongInt): Integer; stdcall; external EpanetLib;
|
||||
function ENcloseH: Integer; stdcall; external EpanetLib;
|
||||
function ENsavehydfile(F: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENusehydfile(F: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENsolveH: Integer; cdecl; external EpanetLib;
|
||||
function ENsaveH: Integer; cdecl; external EpanetLib;
|
||||
function ENopenH: Integer; cdecl; external EpanetLib;
|
||||
function ENinitH(SaveFlag: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENrunH(var T: TimeType): Integer; cdecl; external EpanetLib;
|
||||
function ENnextH(var Tstep: TimeType): Integer; cdecl; external EpanetLib;
|
||||
function ENcloseH: Integer; cdecl; external EpanetLib;
|
||||
function ENsavehydfile(F: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENusehydfile(F: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
|
||||
{Quality Functions}
|
||||
function ENsolveQ: Integer; stdcall; external EpanetLib;
|
||||
function ENopenQ: Integer; stdcall; external EpanetLib;
|
||||
function ENinitQ(SaveFlag: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENrunQ(var T: LongInt): Integer; stdcall; external EpanetLib;
|
||||
function ENnextQ(var Tstep: LongInt): Integer; stdcall; external EpanetLib;
|
||||
function ENstepQ(var Tleft: LongInt): Integer; stdcall; external EpanetLib;
|
||||
function ENcloseQ: Integer; stdcall; external EpanetLib;
|
||||
function ENsolveQ: Integer; cdecl; external EpanetLib;
|
||||
function ENopenQ: Integer; cdecl; external EpanetLib;
|
||||
function ENinitQ(SaveFlag: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENrunQ(var T: TimeType): Integer; cdecl; external EpanetLib;
|
||||
function ENnextQ(var Tstep: TimeType): Integer; cdecl; external EpanetLib;
|
||||
function ENstepQ(var Tleft: TimeType): Integer; cdecl; external EpanetLib;
|
||||
function ENcloseQ: Integer; cdecl; external EpanetLib;
|
||||
|
||||
{Reporting Functions}
|
||||
function ENwriteline(S: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENreport: Integer; stdcall; external EpanetLib;
|
||||
function ENcopyreport(F: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENclearreport: Integer; stdcall; external EpanetLib;
|
||||
function ENresetreport: Integer; stdcall; external EpanetLib;
|
||||
function ENsetreport(S: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENsetstatusreport(Code: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetversion(var Version: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgeterror(Errcode: Integer; Errmsg: PAnsiChar; MaxLen: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetstatistic(StatType: Integer; var Value: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENgetresultindex(Code: Integer; Index: Integer; var Value: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENwriteline(S: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENreport: Integer; cdecl; external EpanetLib;
|
||||
function ENcopyreport(F: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENclearreport: Integer; cdecl; external EpanetLib;
|
||||
function ENresetreport: Integer; cdecl; external EpanetLib;
|
||||
function ENsetreport(S: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENsetstatusreport(Code: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetversion(var Version: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgeterror(Errcode: Integer; Errmsg: PAnsiChar; MaxLen: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetstatistic(StatType: Integer; var Value: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENgetresultindex(Code: Integer; Index: Integer; var Value: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENtimetonextevent(var EventType: Integer; var Duration: TimeType; var ElementIndex: Integer): Integer; cdecl; external EpanetLib;
|
||||
|
||||
{Analysis Options Functions}
|
||||
function ENgetoption(Code: Integer; var Value: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENsetoption(Code: Integer; Value: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENgetflowunits(var Code: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENsetflowunits(Code: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgettimeparam(Code: Integer; var Value: LongInt): Integer; stdcall; external EpanetLib;
|
||||
function ENsettimeparam(Code: Integer; Value: LongInt): Integer; stdcall; external EpanetLib;
|
||||
function ENgetqualinfo(var QualType: Integer; ChemName: PAnsiChar; ChemUnits: PAnsiChar; var TraceNode: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetqualtype(var QualCode: Integer; var TraceNode: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENsetqualtype(QualCode: Integer; ChemName: PAnsiChar; ChemUnits: PAnsiChar; TraceNodeID: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENgetoption(Code: Integer; var Value: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetoption(Code: Integer; Value: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENgetflowunits(var Code: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENsetflowunits(Code: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgettimeparam(Code: Integer; var Value: TimeType): Integer; cdecl; external EpanetLib;
|
||||
function ENsettimeparam(Code: Integer; Value: TimeType): Integer; cdecl; external EpanetLib;
|
||||
function ENgetqualinfo(var QualType: Integer; ChemName: PAnsiChar; ChemUnits: PAnsiChar; var TraceNode: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetqualtype(var QualCode: Integer; var TraceNode: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENsetqualtype(QualCode: Integer; ChemName: PAnsiChar; ChemUnits: PAnsiChar; TraceNodeID: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
|
||||
{Node Functions}
|
||||
function ENaddnode(ID: PAnsiChar; NodeType: Integer; var Index: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENdeletenode(Index: Integer; ActionCode: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetnodeindex(ID: PAnsiChar; var Index: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetnodeid(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENsetnodeid(Index: Integer; NewID: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENgetnodetype(Index: Integer; var Code: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetnodevalue(Index: Integer; Code: Integer; var Value: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENsetnodevalue(Index: Integer; Code: Integer; Value: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENsetjuncdata(Index: Integer; Elev: Single; Dmnd: Single; DmndPat: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENsettankdata(Index: Integer; Elev, InitLvl, MinLvl, MaxLvl, Diam, MinVol: Single; VolCurve: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENgetcoord(Index: Integer; var X: Double; var Y: Double): Integer; stdcall; external EpanetLib;
|
||||
function ENsetcoord(Index: Integer; X: Double; Y: Double): Integer; stdcall; external EpanetLib;
|
||||
function ENaddnode(ID: PAnsiChar; NodeType: Integer; var Index: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENdeletenode(Index: Integer; ActionCode: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetnodeindex(ID: PAnsiChar; var Index: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetnodeid(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENsetnodeid(Index: Integer; NewID: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENgetnodetype(Index: Integer; var Code: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetnodevalue(Index: Integer; Code: Integer; var Value: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetnodevalue(Index: Integer; Code: Integer; Value: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetjuncdata(Index: Integer; Elev: Single; Dmnd: Single; DmndPat: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENsettankdata(Index: Integer; Elev, InitLvl, MinLvl, MaxLvl, Diam, MinVol: Single; VolCurve: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENgetcoord(Index: Integer; var X: Double; var Y: Double): Integer; cdecl; external EpanetLib;
|
||||
function ENsetcoord(Index: Integer; X: Double; Y: Double): Integer; cdecl; external EpanetLib;
|
||||
function ENgetnodevalues(Code: Integer; var X: array of Single): Integer; cdecl; external EpanetLib;
|
||||
|
||||
{Demand Functions}
|
||||
function ENgetdemandmodel(var Model: Integer; var Pmin: Single; var Preq: Single; var Pexp: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENsetdemandmodel(Model: Integer; Pmin: Single; Preq: Single; Pexp: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENgetnumdemands(NodeIndex: Integer; var NumDemands: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENadddemand(NodeIndex: Integer; BaseDemand: Single; PatName: PAnsiChar; DemandName: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENdeletedemand(NodeIndex: Integer; DemandIndex: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetdemandindex(NodeIndex: Integer; DemandName: PAnsiChar; var DemandIndex: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetbasedemand(NodeIndex: Integer; DemandIndex: Integer; var BaseDemand: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENsetbasedemand(NodeIndex: Integer; DemandIndex: Integer; BaseDemand: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENgetdemandpattern(NodeIndex: Integer; DemandIndex: Integer; var PatIndex: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENsetdemandpattern(NodeIndex: Integer; DemandIndex: Integer; PatIndex: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetdemandname(NodeIndex: Integer; DemandIndex: Integer; DemandName: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENsetdemandname(NodeIndex: Integer; DemandIndex: Integer; DemandName: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENgetdemandmodel(var Model: Integer; var Pmin: Single; var Preq: Single; var Pexp: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetdemandmodel(Model: Integer; Pmin: Single; Preq: Single; Pexp: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENgetnumdemands(NodeIndex: Integer; var NumDemands: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENadddemand(NodeIndex: Integer; BaseDemand: Single; PatName: PAnsiChar; DemandName: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENdeletedemand(NodeIndex: Integer; DemandIndex: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetdemandindex(NodeIndex: Integer; DemandName: PAnsiChar; var DemandIndex: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetbasedemand(NodeIndex: Integer; DemandIndex: Integer; var BaseDemand: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetbasedemand(NodeIndex: Integer; DemandIndex: Integer; BaseDemand: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENgetdemandpattern(NodeIndex: Integer; DemandIndex: Integer; var PatIndex: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENsetdemandpattern(NodeIndex: Integer; DemandIndex: Integer; PatIndex: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetdemandname(NodeIndex: Integer; DemandIndex: Integer; DemandName: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENsetdemandname(NodeIndex: Integer; DemandIndex: Integer; DemandName: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
|
||||
{Link Functions}
|
||||
function ENaddlink(ID: PAnsiChar; LinkType: Integer; FromNode: PAnsiChar; ToNode: PAnsiChar; var Index: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENdeletelink(Index: Integer; ActionCode: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetlinkindex(ID: PAnsiChar; var Index: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetlinkid(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENsetlinkid(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENgetlinktype(Index: Integer; var Code: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENsetlinktype(var Index: Integer; LinkType: Integer; ActionCode: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetlinknodes(Index: Integer; var Node1: Integer; var Node2: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENsetlinknodes(Index: Integer; Node1: Integer; Node2: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetlinkvalue(Index: Integer; Code: Integer; var Value: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENsetlinkvalue(Index: Integer; Code: Integer; Value: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENsetpipedata(Index: Integer; Length: Single; Diam: Single; Rough: Single; Mloss:Single): Integer; stdcall; external EpanetLib;
|
||||
function ENaddlink(ID: PAnsiChar; LinkType: Integer; FromNode: PAnsiChar; ToNode: PAnsiChar; var Index: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENdeletelink(Index: Integer; ActionCode: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetlinkindex(ID: PAnsiChar; var Index: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetlinkid(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENsetlinkid(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENgetlinktype(Index: Integer; var Code: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENsetlinktype(var Index: Integer; LinkType: Integer; ActionCode: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetlinknodes(Index: Integer; var Node1: Integer; var Node2: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENsetlinknodes(Index: Integer; Node1: Integer; Node2: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetlinkvalue(Index: Integer; Code: Integer; var Value: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetlinkvalue(Index: Integer; Code: Integer; Value: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetpipedata(Index: Integer; Length: Single; Diam: Single; Rough: Single; Mloss:Single): Integer; cdecl; external EpanetLib;
|
||||
function ENgetlinkvalues(Code: Integer; var X: array of Single): Integer; cdecl; external EpanetLib;
|
||||
|
||||
function ENgetvertexcount(Index: Integer; var Count: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetvertex(Index: Integer; Vertex: Integer; var X: Double; var Y: Double): Integer; stdcall; external EpanetLib;
|
||||
function ENsetvertices(Index: Integer; var X: Double; var Y: Double; Count: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetvertexcount(Index: Integer; var Count: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetvertex(Index: Integer; Vertex: Integer; var X: Double; var Y: Double): Integer; cdecl; external EpanetLib;
|
||||
function ENsetvertex(Index: Integer; Vertex: Integer; X: Double; Y: Double): Integer; cdecl; external EpanetLib;
|
||||
function ENsetvertices(Index: Integer; var X: Double; var Y: Double; Count: Integer): Integer; cdecl; external EpanetLib;
|
||||
|
||||
{Pump Functions}
|
||||
function ENgetpumptype(LinkIndex: Integer; var PumpType: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetheadcurveindex(LinkIndex: Integer; var CurveIndex: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENsetheadcurveindex(LinkIndex: Integer; CurveIndex: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetpumptype(LinkIndex: Integer; var PumpType: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetheadcurveindex(LinkIndex: Integer; var CurveIndex: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENsetheadcurveindex(LinkIndex: Integer; CurveIndex: Integer): Integer; cdecl; external EpanetLib;
|
||||
|
||||
{Pattern Functions}
|
||||
function ENaddpattern(ID: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENdeletepattern(Index: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetpatternindex(ID: PAnsiChar; var Index: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetpatternid(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENsetpatternid(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENgetpatternlen(Index: Integer; var Len: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetpatternvalue(Index: Integer; Period: Integer; var Value: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENsetpatternvalue(Index: Integer; Period: Integer; Value: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENgetaveragepatternvalue(Index: Integer; var Value: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENsetpattern(Index: Integer; var F: Single; N: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENaddpattern(ID: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENdeletepattern(Index: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetpatternindex(ID: PAnsiChar; var Index: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetpatternid(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENsetpatternid(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENgetpatternlen(Index: Integer; var Len: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetpatternvalue(Index: Integer; Period: Integer; var Value: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetpatternvalue(Index: Integer; Period: Integer; Value: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENgetaveragepatternvalue(Index: Integer; var Value: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetpattern(Index: Integer; var F: Single; N: Integer): Integer; cdecl; external EpanetLib;
|
||||
|
||||
{Curve Functions}
|
||||
function ENaddcurve(ID: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENdeletecurve(Index: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetcurveindex(ID: PAnsiChar; var Index: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetcurveid(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENsetcurveid(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENgetcurvelen(Index: Integer; var Len: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetcurvetype(Index: Integer; var CurveType: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetcurvevalue(CurveIndex: Integer; PointIndex: Integer; var X: Single; var Y: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENsetcurvevalue(CurveIndex: Integer; PointIndex: Integer; X: Single; Y: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENgetcurve(Index: Integer; ID: PAnsiChar; var N: Integer; var X: Single; var Y: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENsetcurve(Index: Integer; var X: Single; var Y: Single; N: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENaddcurve(ID: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENdeletecurve(Index: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetcurveindex(ID: PAnsiChar; var Index: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetcurveid(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENsetcurveid(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENgetcurvelen(Index: Integer; var Len: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetcurvetype(Index: Integer; var CurveType: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENsetcurvetype(Index: Integer; CurveType: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetcurvevalue(CurveIndex: Integer; PointIndex: Integer; var X: Single; var Y: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetcurvevalue(CurveIndex: Integer; PointIndex: Integer; X: Single; Y: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENgetcurve(Index: Integer; ID: PAnsiChar; var N: Integer; var X: Single; var Y: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetcurve(Index: Integer; var X: Single; var Y: Single; N: Integer): Integer; cdecl; external EpanetLib;
|
||||
|
||||
{Control Functions}
|
||||
function ENaddcontrol(Ctype: Integer; Link: Integer; Setting: Single; Node: Integer; Level: Single; var Index: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENdeletecontrol(Index: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENgetcontrol(Index: Integer; var Ctype: Integer; var Link: Integer; var Setting: Single; var Node: Integer; var Level: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENsetcontrol(Index: Integer; Ctype: Integer; Link: Integer; Setting: Single; Node: Integer; Level: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENaddcontrol(Ctype: Integer; Link: Integer; Setting: Single; Node: Integer; Level: Single; var Index: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENdeletecontrol(Index: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetcontrol(Index: Integer; var Ctype: Integer; var Link: Integer; var Setting: Single; var Node: Integer; var Level: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetcontrol(Index: Integer; Ctype: Integer; Link: Integer; Setting: Single; Node: Integer; Level: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENgetcontrolenabled(Index: Integer; var out_enabled: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENsetcontrolenabled(Index: Integer; enabled: Integer): Integer; cdecl; external EpanetLib;
|
||||
|
||||
{Rule-Based Control Functions}
|
||||
function ENaddrule(Rule: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENdeleterule(Index: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENaddrule(Rule: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENdeleterule(Index: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENgetrule(Index: Integer; var Npremises: Integer; var NthenActions: Integer;
|
||||
var NelseActions: Integer; var Priority: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENgetruleID(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||
function ENsetrulepriority(Index: Integer; Priority: Single): Integer; stdcall; external EpanetLib;
|
||||
var NelseActions: Integer; var Priority: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENgetruleID(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
|
||||
function ENsetrulepriority(Index: Integer; Priority: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENgetpremise(RuleIndex: Integer; PremiseIndex: Integer; var LogOp: Integer;
|
||||
var ObjType: Integer; var ObjIndex: Integer; var Param: Integer; var RelOp: Integer;
|
||||
var Status: Integer; var Value: Single): Integer; stdcall; external EpanetLib;
|
||||
var Status: Integer; var Value: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetpremise(RuleIndex: Integer; PremiseIndex: Integer; LogOp: Integer; ObjType: Integer;
|
||||
ObjIndex: Integer; Param: Integer; RelOp: Integer; Status: Integer; Value: Single): Integer; stdcall; external EpanetLib;
|
||||
function ENsetpremiseindex(RuleIndex: Integer; PremiseIndex: Integer; ObjIndex: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENsetpremisestatus(RuleIndex: Integer; PremiseIndex: Integer; Status: Integer): Integer; stdcall; external EpanetLib;
|
||||
function ENsetpremisevalue(RuleIndex: Integer; PremiseIndex: Integer; Value: Single): Integer; stdcall; external EpanetLib;
|
||||
ObjIndex: Integer; Param: Integer; RelOp: Integer; Status: Integer; Value: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetpremiseindex(RuleIndex: Integer; PremiseIndex: Integer; ObjIndex: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENsetpremisestatus(RuleIndex: Integer; PremiseIndex: Integer; Status: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENsetpremisevalue(RuleIndex: Integer; PremiseIndex: Integer; Value: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENgetthenaction(RuleIndex: Integer; ActionIndex: Integer; var LinkIndex: Integer;
|
||||
var Status: Integer; var Setting: Single): Integer; stdcall; external EpanetLib;
|
||||
var Status: Integer; var Setting: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetthenaction(RuleIndex: Integer; ActionIndex: Integer; LinkIndex: Integer;
|
||||
Status: Integer; Setting: Single): Integer; stdcall; external EpanetLib;
|
||||
Status: Integer; Setting: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENgetelseaction(RuleIndex: Integer; ActionIndex: Integer; var LinkIndex: Integer;
|
||||
var Status: Integer; var Setting: Single): Integer; stdcall; external EpanetLib;
|
||||
var Status: Integer; var Setting: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENsetelseaction(RuleIndex: Integer; ActionIndex: Integer; LinkIndex: Integer;
|
||||
Status: Integer; Setting: Single): Integer; stdcall; external EpanetLib;
|
||||
Status: Integer; Setting: Single): Integer; cdecl; external EpanetLib;
|
||||
function ENgetruleenabled(Index: Integer; var out_enabled: Integer): Integer; cdecl; external EpanetLib;
|
||||
function ENsetruleenabled(Index: Integer; enabled: Integer): Integer; cdecl; external EpanetLib;
|
||||
|
||||
implementation
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT
|
||||
'(EPANET2.DLL) for use with VB.Net.
|
||||
|
||||
'Last updated on 11/04/2019
|
||||
'Last updated on 04/23/2025
|
||||
|
||||
Imports System.Runtime.InteropServices
|
||||
Imports System.Text
|
||||
@@ -29,7 +29,6 @@ Public Const EN_SOURCEMASS = 13
|
||||
Public Const EN_INITVOLUME = 14
|
||||
Public Const EN_MIXMODEL = 15
|
||||
Public Const EN_MIXZONEVOL = 16
|
||||
|
||||
Public Const EN_TANKDIAM = 17
|
||||
Public Const EN_MINVOLUME = 18
|
||||
Public Const EN_VOLCURVE = 19
|
||||
@@ -37,11 +36,15 @@ Public Const EN_MINLEVEL = 20
|
||||
Public Const EN_MAXLEVEL = 21
|
||||
Public Const EN_MIXFRACTION = 22
|
||||
Public Const EN_TANK_KBULK = 23
|
||||
|
||||
Public Const EN_TANKVOLUME = 24
|
||||
Public Const EN_MAXVOLUME = 25
|
||||
Public Const EN_CANOVERFLOW = 26
|
||||
Public Const EN_DEMANDDEFICIT = 27
|
||||
Public Const EN_DEMANDDEFICIT = 27
|
||||
Public Const EN_NODE_INCONTROL = 28
|
||||
Public Const EN_EMITTERFLOW = 29
|
||||
Public Const EN_LEAKAGEFLOW = 30
|
||||
Public Const EN_DEMANDFLOW = 31
|
||||
Public Const EN_FULLDEMAND = 32
|
||||
|
||||
Public Const EN_DIAMETER = 0 ' Link parameters
|
||||
Public Const EN_LENGTH = 1
|
||||
@@ -59,7 +62,6 @@ Public Const EN_SETTING = 12
|
||||
Public Const EN_ENERGY = 13
|
||||
Public Const EN_LINKQUAL = 14
|
||||
Public Const EN_LINKPATTERN = 15
|
||||
|
||||
Public Const EN_PUMP_STATE = 16
|
||||
Public Const EN_PUMP_EFFIC = 17
|
||||
Public Const EN_PUMP_POWER = 18
|
||||
@@ -67,6 +69,13 @@ Public Const EN_PUMP_HCURVE = 19
|
||||
Public Const EN_PUMP_ECURVE = 20
|
||||
Public Const EN_PUMP_ECOST = 21
|
||||
Public Const EN_PUMP_EPAT = 22
|
||||
Public Const EN_LINK_INCONTROL = 23
|
||||
Public Const EN_GPV_CURVE = 24
|
||||
Public Const EN_PCV_CURVE = 25
|
||||
Public Const EN_LEAK_AREA = 26
|
||||
Public Const EN_LEAK_EXPAN = 27
|
||||
Public Const EN_LINK_LEAKAGE = 28
|
||||
Public Const EN_VALVE_TYPE = 29
|
||||
|
||||
Public Const EN_DURATION = 0 ' Time parameters
|
||||
Public Const EN_HYDSTEP = 1
|
||||
@@ -91,6 +100,7 @@ Public Const EN_MAXFLOWCHANGE = 3
|
||||
Public Const EN_MASSBALANCE = 4
|
||||
Public Const EN_DEFICIENTNODES = 5
|
||||
Public Const EN_DEMANDREDUCTION = 6
|
||||
Public Const EN_LEAKAGELOSS = 7
|
||||
|
||||
Public Const EN_NODE = 0 ' Component types
|
||||
Public Const EN_LINK = 1
|
||||
@@ -120,6 +130,7 @@ Public Const EN_PBV = 5
|
||||
Public Const EN_FCV = 6
|
||||
Public Const EN_TCV = 7
|
||||
Public Const EN_GPV = 8
|
||||
Public Const EN_PCV = 9
|
||||
|
||||
Public Const EN_NONE = 0 ' Quality analysis types
|
||||
Public Const EN_CHEM = 1
|
||||
@@ -145,6 +156,13 @@ Public Const EN_LPM = 6
|
||||
Public Const EN_MLD = 7
|
||||
Public Const EN_CMH = 8
|
||||
Public Const EN_CMD = 9
|
||||
Public Const EN_CMS = 10
|
||||
|
||||
Public Const EN_PSI = 0 ' Pressure units types
|
||||
Public Const EN_KPA = 1
|
||||
Public Const EN_METERS = 2
|
||||
Public Const EN_BAR = 3
|
||||
Public Const EN_FEET = 4
|
||||
|
||||
Public Const EN_DDA = 0 ' Demand driven analysis
|
||||
Public Const EN_PDA = 1 ' Pressure driven analysis
|
||||
@@ -172,6 +190,10 @@ Public Const EN_BULKORDER = 19
|
||||
Public Const EN_WALLORDER = 20
|
||||
Public Const EN_TANKORDER = 21
|
||||
Public Const EN_CONCENLIMIT = 22
|
||||
Public Const EN_DEMANDPATTERN = 23
|
||||
Public Const EN_EMITBACKFLOW = 24
|
||||
Public Const EN_PRESS_UNITS = 25
|
||||
Public Const EN_STATUS_REPORT = 26
|
||||
|
||||
Public Const EN_LOWLEVEL = 0 ' Control types
|
||||
Public Const EN_HILEVEL = 1
|
||||
@@ -203,6 +225,7 @@ Public Const EN_PUMP_CURVE = 1 ' Pump curve
|
||||
Public Const EN_EFFIC_CURVE = 2 ' Efficiency curve
|
||||
Public Const EN_HLOSS_CURVE = 3 ' Head loss curve
|
||||
Public Const EN_GENERIC_CURVE = 4 ' Generic curve
|
||||
Public Const EN_VALVE_CURVE = 5 ' Valve position curve
|
||||
|
||||
Public Const EN_UNCONDITIONAL = 0 ' Unconditional object deletion
|
||||
Public Const EN_CONDITIONAL = 1 ' Conditional object deletion
|
||||
@@ -245,6 +268,11 @@ Public Const EN_R_IS_CLOSED = 2
|
||||
Public Const EN_R_IS_ACTIVE = 3
|
||||
|
||||
Public Const EN_MISSING As Double = -1.0E10
|
||||
Public Const EN_SET_CLOSED As Double = -1.0E10
|
||||
Public Const EN_SET_OPEN As Double = 1.0E10
|
||||
|
||||
Public Const EN_FALSE = 0 ' boolean false
|
||||
Public Const EN_TRUE = 1 ' boolean true
|
||||
|
||||
'These are the external functions that comprise the DLL
|
||||
|
||||
@@ -253,8 +281,13 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENepanet Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String, ByVal pviewprog As Any) As Int32
|
||||
Declare Function ENinit Lib "epanet2.dll" (ByVal rptFile As String, ByVal outFile As String, ByVal unitsType As Int32, ByVal headlossType As Int32) As Int32
|
||||
Declare Function ENopen Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String) As Int32
|
||||
Declare Function ENopenX Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String) As Int32
|
||||
Declare Function ENgettitle Lib "epanet2.dll" (ByVal titleline1 As String, ByVal titleline2 As String, ByVal titleline3 As String) As Int32
|
||||
Declare Function ENsettitle Lib "epanet2.dll" (ByVal titleline1 As String, ByVal titleline2 As String, ByVal titleline3 As String) As Int32
|
||||
Declare Function ENgetcomment Lib "epanet2.dll" (ByVal type_ As Int32, ByVal index As Int32, ByVal comment As String) As Int32
|
||||
Declare Function ENsetcomment Lib "epanet2.dll" (ByVal type_ As Int32, ByVal index As Int32, ByVal comment As String) As Int32
|
||||
Declare Function ENgettag Lib "epanet2.dll" (ByVal type_ As Int32, ByVal index As Int32, ByVal tag As String) As Int32
|
||||
Declare Function ENsettag Lib "epanet2.dll" (ByVal type_ As Int32, ByVal index As Int32, ByVal tag As String) As Int32
|
||||
Declare Function ENsaveinpfile Lib "epanet2.dll" (ByVal filename As String) As Int32
|
||||
Declare Function ENclose Lib "epanet2.dll" () As Int32
|
||||
|
||||
@@ -290,6 +323,7 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENgeterror Lib "epanet2.dll" (ByVal errcode As Int32, ByVal errmsg As String, ByVal maxLen As Int32) As Int32
|
||||
Declare Function ENgetstatistic Lib "epanet2.dll" (ByVal type_ As Int32, ByRef value As Single) As Int32
|
||||
Declare Function ENgetresultindex Lib "epanet2.dll" (ByVal type_ As Int32, ByVal index As Int32, ByRef value As Int32) As Int32
|
||||
Declare Function ENtimetonextevent Lib "epanet2.dll" (eventType As Int32, duration As Int32, elementIndex As Int32) As Int32
|
||||
|
||||
'Analysis Options Functions
|
||||
Declare Function ENgetoption Lib "epanet2.dll" (ByVal option As Int32, value As Single) As Int32
|
||||
@@ -315,7 +349,8 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENsettankdata Lib "epanet2.dll" (ByVal index As Int32, ByVal elev As Single, ByVal initlvl As Single, ByVal minlvl As Single, ByVal maxlvl As Single, ByVal diam As Single, ByVal minvol As Single, ByVal volcurve As String) As Int32
|
||||
Declare Function ENgetcoord Lib "epanet2.dll" (ByVal index As Int32, x As Double, y As Double) As Int32
|
||||
Declare Function ENsetcoord Lib "epanet2.dll" (ByVal index As Int32, ByVal x As Double, ByVal y As Double) As Int32
|
||||
|
||||
Declare Function ENgetnodevalues Lib "epanet2.dll" (ByVal property as Int32, values as Any) As Int32
|
||||
|
||||
'Nodal Demand Functions
|
||||
Declare Function ENgetdemandmodel Lib "epanet2.dll" (type_ As Int32, pmin As Single, preq As Single, pexp As Single) As Int32
|
||||
Declare Function ENsetdemandmodel Lib "epanet2.dll" (ByVal type_ As Int32, ByVal pmin As Single, ByVal preq As Single, ByVal pexp As Single) As Int32
|
||||
@@ -345,7 +380,9 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENsetpipedata Lib "epanet2.dll" (ByVal index As Int32, ByVal length As Single, ByVal diam As Single, ByVal rough As Single, ByVal mloss As Single) As Int32
|
||||
Declare Function ENgetvertexcount Lib "epanet2.dll" (ByVal index As Int32, count As Int32) As Int32
|
||||
Declare Function ENgetvertex Lib "epanet2.dll" (ByVal index As Int32, ByVal vertex As Int32, x As Double, y As Double) As Int32
|
||||
Declare Function ENsetvertex Lib "epanet2.dll" (ByVal index As Int32, ByVal vertex As Int32, ByVal x As Double, ByVal y As Double) As Int32
|
||||
Declare Function ENsetvertices Lib "epanet2.dll" (ByVal index As Int32, xCoords As Any, yCoords As Any, ByVal count As Int32) As Int32
|
||||
Declare Function ENgetlinkvalues Lib "epanet2.dll" (ByVal property as Int32, values as Any) As Int32
|
||||
|
||||
'Pump Functions
|
||||
Declare Function ENgetheadcurveindex Lib "epanet2.dll" (ByVal linkIndex As Int32, curveIndex As Int32) As Int32
|
||||
@@ -363,6 +400,7 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENsetpatternvalue Lib "epanet2.dll" (ByVal index As Int32, ByVal period As Int32, ByVal value As Single) As Int32
|
||||
Declare Function ENgetaveragepatternvalue Lib "epanet2.dll" (ByVal index As Int32, value As Single) As Int32
|
||||
Declare Function ENsetpattern Lib "epanet2.dll" (ByVal index As Int32, values As Any, ByVal len_ As Int32) As Int32
|
||||
Declare Function ENloadpatternfile Lib "epanet2.dll" (ByVal filename As String, ByVal id As String) As Int32
|
||||
|
||||
'Data Curve Functions
|
||||
Declare Function ENaddcurve Lib "epanet2.dll" (ByVal id As String) As Int32
|
||||
@@ -372,6 +410,7 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENsetcurveid Lib "epanet2.dll" (ByVal index As Int32, ByVal newid As String) As Int32
|
||||
Declare Function ENgetcurvelen Lib "epanet2.dll" (ByVal index As Int32, len_ As Int32) As Int32
|
||||
Declare Function ENgetcurvetype Lib "epanet2.dll" (ByVal index As Int32, type_ As Int32) As Int32
|
||||
Declare Function ENsetcurvetype Lib "epanet2.dll" (ByVal index As Int32, ByVal type_ As Int32) As Int32
|
||||
Declare Function ENgetcurvevalue Lib "epanet2.dll" (ByVal curveIndex As Int32, ByVal pointIndex As Int32, x As Single, y As Single) As Int32
|
||||
Declare Function ENsetcurvevalue Lib "epanet2.dll" (ByVal curveIndex As Int32, ByVal pointIndex As Int32, ByVal x As Single, ByVal y As Single) As Int32
|
||||
Declare Function ENgetcurve Lib "epanet2.dll" (ByVal index As Int32, ByVal id As String, nPoints As Int32, xValues As Any, yValues As Any) As Int32
|
||||
@@ -382,6 +421,8 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENdeletecontrol Lib "epanet2.dll" (ByVal index As Int32) As Int32
|
||||
Declare Function ENgetcontrol Lib "epanet2.dll" (ByVal index As Int32, type_ As Int32, linkIndex As Int32, setting As Single, nodeIndex As Int32, level As Single) As Int32
|
||||
Declare Function ENsetcontrol Lib "epanet2.dll" (ByVal index As Int32, ByVal type_ As Int32, ByVal linkIndex As Int32, ByVal setting As Single, ByVal nodeIndex As Int32, ByVal level As Single) As Int32
|
||||
Declare Function ENgetcontrolenabled Lib "epanet2.dll" (ByVal index As Int32, out_enabled As Int32) As Int32
|
||||
Declare Function ENsetcontrolenabled Lib "epanet2.dll" (ByVal index As Int32, ByVal enabled As Int32) As Int32
|
||||
|
||||
'Rule-Based Control Functions
|
||||
Declare Function ENaddrule Lib "epanet2.dll" (ByVal rule As String) As Int32
|
||||
@@ -398,5 +439,7 @@ Public Const EN_MISSING As Double = -1.0E10
|
||||
Declare Function ENsetthenaction Lib "epanet2.dll" (ByVal ruleIndex As Int32, ByVal actionIndex As Int32, ByVal linkIndex As Int32, ByVal status As Int32, ByVal setting As Single) As Int32
|
||||
Declare Function ENgetelseaction Lib "epanet2.dll" (ByVal ruleIndex As Int32, ByVal actionIndex As Int32, linkIndex As Int32, status As Int32, setting As Single) As Int32
|
||||
Declare Function ENsetelseaction Lib "epanet2.dll" (ByVal ruleIndex As Int32, ByVal actionIndex As Int32, ByVal linkIndex As Int32, ByVal status As Int32, ByVal setting As Single) As Int32
|
||||
Declare Function ENgetruleenabled Lib "epanet2.dll" (ByVal index As Int32, out_enabled As Int32) As Int32
|
||||
Declare Function ENsetruleenabled Lib "epanet2.dll" (ByVal index As Int32, ByVal enabled As Int32) As Int32
|
||||
|
||||
End Module
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,13 +3,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: epanet2_enums.h
|
||||
Description: enumerations of symbolic constants used by the API functions
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/06/2019
|
||||
Last Updated: 04/23/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -17,13 +17,11 @@
|
||||
#ifndef EPANET2_ENUMS_H
|
||||
#define EPANET2_ENUMS_H
|
||||
|
||||
|
||||
// --- Define the EPANET toolkit constants
|
||||
|
||||
/// Size Limts
|
||||
/**
|
||||
Limits on the size of character arrays used to store ID names
|
||||
and text messages.
|
||||
/// Character array size limits
|
||||
/*! \enum EN_SizeLimits
|
||||
* Limits on the size of character arrays used to store ID names
|
||||
* and text messages.
|
||||
*/
|
||||
typedef enum {
|
||||
EN_MAXID = 31, //!< Max. # characters in ID name
|
||||
@@ -31,11 +29,11 @@ typedef enum {
|
||||
} EN_SizeLimits;
|
||||
|
||||
/// Node properties
|
||||
/**
|
||||
These node properties are used with @ref EN_getnodevalue and @ref EN_setnodevalue.
|
||||
Those marked as read only are computed values that can only be retrieved.
|
||||
/*! \enum EN_NodeProperty
|
||||
* These node properties are used with @ref EN_getnodevalue and @ref EN_setnodevalue.
|
||||
* Those marked as read only are computed values that can only be retrieved.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum {
|
||||
EN_ELEVATION = 0, //!< Elevation
|
||||
EN_BASEDEMAND = 1, //!< Primary demand baseline value
|
||||
EN_PATTERN = 2, //!< Primary demand time pattern index
|
||||
@@ -62,8 +60,13 @@ typedef enum {
|
||||
EN_TANK_KBULK = 23, //!< Tank bulk decay coefficient
|
||||
EN_TANKVOLUME = 24, //!< Current computed tank volume (read only)
|
||||
EN_MAXVOLUME = 25, //!< Tank maximum volume (read only)
|
||||
EN_CANOVERFLOW = 26, //!< Tank can overflow (= 1) or not (= 0)
|
||||
EN_DEMANDDEFICIT = 27 //!< Amount that full demand is reduced under PDA (read only)
|
||||
EN_CANOVERFLOW = 26, //!< `EN_TRUE` (= 1) if the Tank can overflow, `EN_FALSE` (= 0) if it cannot
|
||||
EN_DEMANDDEFICIT = 27,//!< Amount that full demand is reduced under PDA (read only)
|
||||
EN_NODE_INCONTROL = 28, //!< `EN_TRUE` (= 1) if the node appears in any control, `EN_FALSE` (= 0) if not
|
||||
EN_EMITTERFLOW = 29, //!< Current emitter flow (read only)
|
||||
EN_LEAKAGEFLOW = 30, //!< Current leakage flow (read only)
|
||||
EN_DEMANDFLOW = 31, //!< Current consumer demand delivered (read only)
|
||||
EN_FULLDEMAND = 32 //!< Current consumer demand requested (read only)
|
||||
} EN_NodeProperty;
|
||||
|
||||
/// Link properties
|
||||
@@ -78,7 +81,7 @@ typedef enum {
|
||||
EN_MINORLOSS = 3, //!< Pipe/valve minor loss coefficient
|
||||
EN_INITSTATUS = 4, //!< Initial status (see @ref EN_LinkStatusType)
|
||||
EN_INITSETTING = 5, //!< Initial pump speed or valve setting
|
||||
EN_KBULK = 6, //!< Bulk chemical reaction coefficient
|
||||
EN_KBULK = 6, //!< Bulk flow chemical reaction coefficient
|
||||
EN_KWALL = 7, //!< Pipe wall chemical reaction coefficient
|
||||
EN_FLOW = 8, //!< Current computed flow rate (read only)
|
||||
EN_VELOCITY = 9, //!< Current computed flow velocity (read only)
|
||||
@@ -94,7 +97,14 @@ typedef enum {
|
||||
EN_PUMP_HCURVE = 19, //!< Pump head v. flow curve index
|
||||
EN_PUMP_ECURVE = 20, //!< Pump efficiency v. flow curve index
|
||||
EN_PUMP_ECOST = 21, //!< Pump average energy price
|
||||
EN_PUMP_EPAT = 22 //!< Pump energy price time pattern index
|
||||
EN_PUMP_EPAT = 22, //!< Pump energy price time pattern index
|
||||
EN_LINK_INCONTROL = 23, //!< Is present in any simple or rule-based control (= 1) or not (= 0)
|
||||
EN_GPV_CURVE = 24, //!< GPV head loss v. flow curve index
|
||||
EN_PCV_CURVE = 25, //!< PCV characteristic curve index
|
||||
EN_LEAK_AREA = 26, //!< Pipe leak area (sq mm per 100 length units)
|
||||
EN_LEAK_EXPAN = 27, //!< Leak expansion rate (sq mm per unit of pressure head)
|
||||
EN_LINK_LEAKAGE = 28, //!< Current leakage rate (read only)
|
||||
EN_VALVE_TYPE = 29 //!< Type of valve (see @ref EN_LinkType)
|
||||
} EN_LinkProperty;
|
||||
|
||||
/// Time parameters
|
||||
@@ -122,6 +132,18 @@ typedef enum {
|
||||
EN_NEXTEVENTTANK = 15 //!< Index of tank with shortest time to become empty or full (read only)
|
||||
} EN_TimeParameter;
|
||||
|
||||
/// Time step events
|
||||
/**
|
||||
These are the types of events that can cause a new time step to be taken.
|
||||
**/
|
||||
typedef enum {
|
||||
EN_STEP_REPORT = 0, //!< A reporting time step has ended
|
||||
EN_STEP_HYD = 1, //!< A hydraulic time step has ended
|
||||
EN_STEP_WQ = 2, //!< A water quality time step has ended
|
||||
EN_STEP_TANKEVENT = 3, //!< A tank has become empty or full
|
||||
EN_STEP_CONTROLEVENT = 4 //!< A link control needs to be activated
|
||||
} EN_TimestepEvent;
|
||||
|
||||
/// Analysis convergence statistics
|
||||
/**
|
||||
These statistics report the convergence criteria for the most current hydraulic analysis
|
||||
@@ -135,7 +157,8 @@ typedef enum {
|
||||
EN_MAXFLOWCHANGE = 3, //!< Largest flow change in links
|
||||
EN_MASSBALANCE = 4, //!< Cumulative water quality mass balance ratio
|
||||
EN_DEFICIENTNODES = 5, //!< Number of pressure deficient nodes
|
||||
EN_DEMANDREDUCTION = 6 //!< % demand reduction at pressure deficient nodes
|
||||
EN_DEMANDREDUCTION = 6, //!< % demand reduction at pressure deficient nodes
|
||||
EN_LEAKAGELOSS = 7 //!< % flow lost to system leakage
|
||||
} EN_AnalysisStatistic;
|
||||
|
||||
/// Types of network objects
|
||||
@@ -188,25 +211,26 @@ typedef enum {
|
||||
EN_PBV = 5, //!< Pressure breaker valve
|
||||
EN_FCV = 6, //!< Flow control valve
|
||||
EN_TCV = 7, //!< Throttle control valve
|
||||
EN_GPV = 8 //!< General purpose valve
|
||||
EN_GPV = 8, //!< General purpose valve
|
||||
EN_PCV = 9 //!< Positional control valve
|
||||
} EN_LinkType;
|
||||
|
||||
/// Link status
|
||||
/**
|
||||
One of these values is returned when @ref EN_getlinkvalue is used to retrieve a link's
|
||||
initial status ( \b EN_INITSTATUS ) or its current status ( \b EN_STATUS ). These options are
|
||||
initial status (`EN_INITSTATUS`) or its current status (`EN_STATUS`). These options are
|
||||
also used with @ref EN_setlinkvalue to set values for these same properties.
|
||||
*/
|
||||
typedef enum {
|
||||
EN_CLOSED = 0,
|
||||
EN_OPEN = 1
|
||||
EN_CLOSED = 0, //!< Link is closed and cannot convey any flow
|
||||
EN_OPEN = 1 //!< Link is open and is able to convey flow
|
||||
} EN_LinkStatusType;
|
||||
|
||||
/// Pump states
|
||||
/**
|
||||
One of these codes is returned when @ref EN_getlinkvalue is used to retrieve a pump's
|
||||
current operating state ( \b EN_PUMP_STATE ). \b EN_PUMP_XHEAD indicates that the pump has been
|
||||
shut down because it is being asked to deliver more than its shutoff head. \b EN_PUMP_XFLOW
|
||||
current operating state (`EN_PUMP_STATE`). `EN_PUMP_XHEAD` indicates that the pump has been
|
||||
shut down because it is being asked to deliver more than its shutoff head. `EN_PUMP_XFLOW`
|
||||
indicates that the pump is being asked to deliver more than its maximum flow.
|
||||
*/
|
||||
typedef enum {
|
||||
@@ -231,7 +255,7 @@ typedef enum {
|
||||
/// Water quality source types
|
||||
/**
|
||||
These are the different types of external water quality sources that can be assigned
|
||||
to a node's \b EN_SOURCETYPE property as used by @ref EN_getnodevalue and @ref EN_setnodevalue.
|
||||
to a node's `EN_SOURCETYPE` property as used by @ref EN_getnodevalue and @ref EN_setnodevalue.
|
||||
*/
|
||||
typedef enum {
|
||||
EN_CONCEN = 0, //!< Sets the concentration of external inflow entering a node
|
||||
@@ -242,9 +266,9 @@ typedef enum {
|
||||
|
||||
/// Head loss formulas
|
||||
/**
|
||||
The available choices for the \b EN_HEADLOSSFORM option in @ref EN_getoption and
|
||||
The available choices for the `EN_HEADLOSSFORM` option in @ref EN_getoption and
|
||||
@ref EN_setoption. They are also used for the head loss type argument in @ref EN_init.
|
||||
Each head loss formula uses a different type of roughness coefficient ( \b EN_ROUGHNESS )
|
||||
Each head loss formula uses a different type of roughness coefficient (`EN_ROUGHNESS`)
|
||||
that can be set with @ref EN_setlinkvalue.
|
||||
*/
|
||||
typedef enum {
|
||||
@@ -257,7 +281,7 @@ typedef enum {
|
||||
/**
|
||||
These choices for flow units are used with @ref EN_getflowunits and @ref EN_setflowunits.
|
||||
They are also used for the flow units type argument in @ref EN_init. If flow units are
|
||||
expressed in US Customary units ( \b EN_CFS through \b EN_AFD ) then all other quantities are
|
||||
expressed in US Customary units (`EN_CFS` through `EN_AFD`) then all other quantities are
|
||||
in US Customary units. Otherwise they are in metric units.
|
||||
*/
|
||||
typedef enum {
|
||||
@@ -270,9 +294,23 @@ typedef enum {
|
||||
EN_LPM = 6, //!< Liters per minute
|
||||
EN_MLD = 7, //!< Million liters per day
|
||||
EN_CMH = 8, //!< Cubic meters per hour
|
||||
EN_CMD = 9 //!< Cubic meters per day
|
||||
EN_CMD = 9, //!< Cubic meters per day
|
||||
EN_CMS = 10 //!< Cubic meters per second
|
||||
} EN_FlowUnits;
|
||||
|
||||
/// Pressure units
|
||||
/**
|
||||
The available choices for pressure units for the `EN_PRESS_UNITS` option in @ref EN_getoption
|
||||
and @ref EN_setoption.
|
||||
*/
|
||||
typedef enum {
|
||||
EN_PSI = 0, //!< Pounds per square inch
|
||||
EN_KPA = 1, //!< Kilopascals
|
||||
EN_METERS = 2, //!< Meters
|
||||
EN_BAR = 3, //!< Bar
|
||||
EN_FEET = 4 //!< Feet
|
||||
} EN_PressUnits;
|
||||
|
||||
/// Demand models
|
||||
/**
|
||||
These choices for modeling consumer demands are used with @ref EN_getdemandmodel
|
||||
@@ -317,7 +355,11 @@ typedef enum {
|
||||
EN_BULKORDER = 19, //!< Bulk water reaction order for pipes
|
||||
EN_WALLORDER = 20, //!< Wall reaction order for pipes (either 0 or 1)
|
||||
EN_TANKORDER = 21, //!< Bulk water reaction order for tanks
|
||||
EN_CONCENLIMIT = 22 //!< Limiting concentration for growth reactions
|
||||
EN_CONCENLIMIT = 22, //!< Limiting concentration for growth reactions
|
||||
EN_DEMANDPATTERN = 23, //!< Name of default demand pattern
|
||||
EN_EMITBACKFLOW = 24, //!< `EN_TRUE` (= 1) if emitters can backflow, `EN_FALSE` (= 0) if not
|
||||
EN_PRESS_UNITS = 25, //!< Pressure units (see @ref EN_PressUnits)
|
||||
EN_STATUS_REPORT = 26 //!< Type of status report to produce (see @ref EN_StatusReport)
|
||||
} EN_Option;
|
||||
|
||||
/// Simple control types
|
||||
@@ -336,9 +378,10 @@ typedef enum {
|
||||
/// Reporting statistic choices
|
||||
/**
|
||||
These options determine what kind of statistical post-processing should be done on
|
||||
the time series of simulation results generated before they are reported using
|
||||
@ref EN_report. An option can be chosen by using \b STATISTIC _option_ as the argument
|
||||
to @ref EN_setreport.
|
||||
the time series of simulation results before they are reported using @ref EN_report
|
||||
or saved to the project's binary output file. These options are used in the
|
||||
@ref EN_gettimeparam and @ref EN_settimeparam functions when `EN_STATISTIC` is the
|
||||
time parameter being set or retrieved.
|
||||
*/
|
||||
typedef enum {
|
||||
EN_SERIES = 0, //!< Report all time series points
|
||||
@@ -351,7 +394,7 @@ typedef enum {
|
||||
/// Tank mixing models
|
||||
/**
|
||||
These are the different types of models that describe water quality mixing in storage tanks.
|
||||
The choice of model is accessed with the \b EN_MIXMODEL property of a Tank node using
|
||||
The choice of model is accessed with the `EN_MIXMODEL` property of a Tank node using
|
||||
@ref EN_getnodevalue and @ref EN_setnodevalue.
|
||||
*/
|
||||
typedef enum {
|
||||
@@ -393,7 +436,8 @@ typedef enum {
|
||||
EN_PUMP_CURVE = 1, //!< Pump head v. flow curve
|
||||
EN_EFFIC_CURVE = 2, //!< Pump efficiency v. flow curve
|
||||
EN_HLOSS_CURVE = 3, //!< Valve head loss v. flow curve
|
||||
EN_GENERIC_CURVE = 4 //!< Generic curve
|
||||
EN_GENERIC_CURVE = 4, //!< Generic curve
|
||||
EN_VALVE_CURVE = 5 //!< % of fully open flow v. % open
|
||||
} EN_CurveType;
|
||||
|
||||
/// Deletion action codes
|
||||
@@ -403,14 +447,15 @@ should be taken if the node or link being deleted appears in any simple or rule-
|
||||
controls or if a deleted node has any links connected to it.
|
||||
*/
|
||||
typedef enum {
|
||||
EN_UNCONDITIONAL = 0, //!< Delete all controls and connecing links
|
||||
EN_UNCONDITIONAL = 0, //!< Delete all controls and connecting links
|
||||
EN_CONDITIONAL = 1 //!< Cancel object deletion if it appears in controls or has connecting links
|
||||
} EN_ActionCodeType;
|
||||
|
||||
/// Status reporting levels
|
||||
/**
|
||||
These choices specify the level of status reporting written to a project's report
|
||||
file during a hydraulic analysis. The level is set using the @ref EN_setstatusreport function.
|
||||
file during a hydraulic analysis. The level is set using the @ref EN_setstatusreport
|
||||
or the @ref EN_setoption functions.
|
||||
*/
|
||||
typedef enum {
|
||||
EN_NO_REPORT = 0, //!< No status reporting
|
||||
@@ -463,6 +508,11 @@ typedef enum {
|
||||
EN_R_IS_ACTIVE = 3 //!< Control valve is active
|
||||
} EN_RuleStatus;
|
||||
|
||||
#define EN_MISSING -1.E10 //!< Missing value indicator
|
||||
#define EN_MISSING -1.E10 //!< Missing value indicator
|
||||
#define EN_SET_CLOSED -1.E10 //!< Link set closed indicator
|
||||
#define EN_SET_OPEN 1.E10 //!< Link set open indicator
|
||||
|
||||
#define EN_FALSE 0 //!< boolean false
|
||||
#define EN_TRUE 1 //!< boolean true
|
||||
|
||||
#endif //EPANET2_ENUMS_H
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# EPANET COMMAND LINE EXECUTABLE
|
||||
cmake_minimum_required (VERSION 2.8.8)
|
||||
cmake_minimum_required (VERSION 3.8.0)
|
||||
|
||||
|
||||
# Sets for output directory for executables and libraries.
|
||||
@@ -31,3 +31,4 @@ if(NOT WIN32)
|
||||
else(NOT WIN32)
|
||||
target_link_libraries(runepanet LINK_PUBLIC epanet2)
|
||||
endif(NOT WIN32)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: main.c
|
||||
Description: main stub for a command line executable version of EPANET
|
||||
Authors: see AUTHORS
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
*****************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: enumstxt.h
|
||||
Description: text strings for enumerated data types
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 06/20/2019
|
||||
Last Updated: 03/10/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,8 @@ char *LinkTxt[] = {w_CV,
|
||||
w_PBV,
|
||||
w_FCV,
|
||||
w_TCV,
|
||||
w_GPV};
|
||||
w_GPV,
|
||||
w_PCV};
|
||||
|
||||
char *StatTxt[] = {t_XHEAD,
|
||||
t_TEMPCLOSED,
|
||||
@@ -58,7 +59,8 @@ char *RptFlowUnitsTxt[] = {u_CFS,
|
||||
u_LPM,
|
||||
u_MLD,
|
||||
u_CMH,
|
||||
u_CMD};
|
||||
u_CMD,
|
||||
u_CMS};
|
||||
|
||||
char *FlowUnitsTxt[] = {w_CFS,
|
||||
w_GPM,
|
||||
@@ -69,11 +71,14 @@ char *FlowUnitsTxt[] = {w_CFS,
|
||||
w_LPM,
|
||||
w_MLD,
|
||||
w_CMH,
|
||||
w_CMD};
|
||||
w_CMD,
|
||||
w_CMS};
|
||||
|
||||
char *PressUnitsTxt[] = {w_PSI,
|
||||
w_KPA,
|
||||
w_METERS};
|
||||
w_METERS,
|
||||
w_BAR,
|
||||
w_FEET};
|
||||
|
||||
char *DemandModelTxt[] = { w_DDA,
|
||||
w_PDA,
|
||||
@@ -110,6 +115,18 @@ char *MixTxt[] = {w_MIXED,
|
||||
char *RptFlagTxt[] = {w_NO,
|
||||
w_YES,
|
||||
w_FULL};
|
||||
|
||||
char *BackflowTxt[] = {w_NO,
|
||||
w_YES,
|
||||
NULL};
|
||||
|
||||
char *CurveTypeTxt[] = {c_VOLUME,
|
||||
c_PUMP,
|
||||
c_EFFIC,
|
||||
c_HEADLOSS,
|
||||
c_GENERIC,
|
||||
c_VALVE,
|
||||
NULL};
|
||||
|
||||
char *SectTxt[] = {s_TITLE, s_JUNCTIONS, s_RESERVOIRS,
|
||||
s_TANKS, s_PIPES, s_PUMPS,
|
||||
@@ -120,7 +137,7 @@ char *SectTxt[] = {s_TITLE, s_JUNCTIONS, s_RESERVOIRS,
|
||||
s_REACTIONS, s_MIXING, s_REPORT,
|
||||
s_TIMES, s_OPTIONS, s_COORDS,
|
||||
s_VERTICES, s_LABELS, s_BACKDROP,
|
||||
s_TAGS, s_END,
|
||||
s_TAGS, s_LEAKAGE, s_END,
|
||||
NULL};
|
||||
|
||||
char *Fldname[] = {t_ELEV, t_DEMAND, t_HEAD,
|
||||
|
||||
1100
src/epanet.c
1100
src/epanet.c
File diff suppressed because it is too large
Load Diff
160
src/epanet2.c
160
src/epanet2.c
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: epanet2.c
|
||||
Description: implementation of the legacy EPANET API functions
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/02/2019
|
||||
Last Updated: 02/14/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -99,12 +99,20 @@ int DLLEXPORT ENopen(const char *inpFile, const char *rptFile, const char *outFi
|
||||
return errcode;
|
||||
}
|
||||
|
||||
int DLLEXPORT ENopenX(const char *inpFile, const char *rptFile, const char *outFile)
|
||||
{
|
||||
int errcode = 0;
|
||||
createtmpfiles();
|
||||
errcode = EN_openX(_defaultProject, inpFile, rptFile, outFile);
|
||||
return errcode;
|
||||
}
|
||||
|
||||
int DLLEXPORT ENgettitle(char *line1, char *line2, char *line3)
|
||||
{
|
||||
return EN_gettitle(_defaultProject, line1, line2, line3) ;
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsettitle(char *line1, char *line2, char *line3)
|
||||
int DLLEXPORT ENsettitle(const char *line1, const char *line2, const char *line3)
|
||||
{
|
||||
return EN_settitle(_defaultProject, line1, line2, line3) ;
|
||||
}
|
||||
@@ -114,11 +122,20 @@ int DLLEXPORT ENgetcomment(int object, int index, char *comment)
|
||||
return EN_getcomment(_defaultProject, object, index, comment);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetcomment(int object, int index, char *comment)
|
||||
int DLLEXPORT ENsetcomment(int object, int index, const char *comment)
|
||||
{
|
||||
return EN_setcomment(_defaultProject, object, index, comment);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENgettag(int object, int index, char *tag)
|
||||
{
|
||||
return EN_gettag(_defaultProject, object, index, tag);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsettag(int object, int index, const char *tag)
|
||||
{
|
||||
return EN_settag(_defaultProject, object, index, tag);
|
||||
}
|
||||
int DLLEXPORT ENgetcount(int object, int *count)
|
||||
{
|
||||
return EN_getcount(_defaultProject, object, count);
|
||||
@@ -156,12 +173,12 @@ int DLLEXPORT ENnextH(long *tStep) { return EN_nextH(_defaultProject, tStep); }
|
||||
|
||||
int DLLEXPORT ENcloseH() { return EN_closeH(_defaultProject); }
|
||||
|
||||
int DLLEXPORT ENsavehydfile(char *filename)
|
||||
int DLLEXPORT ENsavehydfile(const char *filename)
|
||||
{
|
||||
return EN_savehydfile(_defaultProject, filename);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENusehydfile(char *filename)
|
||||
int DLLEXPORT ENusehydfile(const char *filename)
|
||||
{
|
||||
return EN_usehydfile(_defaultProject, filename);
|
||||
}
|
||||
@@ -192,11 +209,11 @@ int DLLEXPORT ENcloseQ() { return EN_closeQ(_defaultProject); }
|
||||
|
||||
********************************************************************/
|
||||
|
||||
int DLLEXPORT ENwriteline(char *line) { return EN_writeline(_defaultProject, line); }
|
||||
int DLLEXPORT ENwriteline(const char *line) { return EN_writeline(_defaultProject, line); }
|
||||
|
||||
int DLLEXPORT ENreport() { return EN_report(_defaultProject); }
|
||||
|
||||
int DLLEXPORT ENcopyreport(char *filename)
|
||||
int DLLEXPORT ENcopyreport(const char *filename)
|
||||
{
|
||||
return EN_copyreport(_defaultProject, filename);
|
||||
}
|
||||
@@ -205,13 +222,23 @@ int DLLEXPORT ENclearreport() { return EN_clearreport(_defaultProject); }
|
||||
|
||||
int DLLEXPORT ENresetreport() { return EN_resetreport(_defaultProject); }
|
||||
|
||||
int DLLEXPORT ENsetreport(char *format) { return EN_setreport(_defaultProject, format); }
|
||||
int DLLEXPORT ENsetreport(const char *format) { return EN_setreport(_defaultProject, format); }
|
||||
|
||||
int DLLEXPORT ENsetstatusreport(int level)
|
||||
{
|
||||
return EN_setstatusreport(_defaultProject, level);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetreportcallback(void (*callback)(void *userData, void *EN_projectHandle, const char*))
|
||||
{
|
||||
return EN_setreportcallback(_defaultProject, callback);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetreportcallbackuserdata(void *userData)
|
||||
{
|
||||
return EN_setreportcallbackuserdata(_defaultProject, userData);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENgetversion(int *version) { return EN_getversion(version); }
|
||||
|
||||
int DLLEXPORT ENgeterror(int errcode, char *errmsg, int maxLen)
|
||||
@@ -232,6 +259,10 @@ int DLLEXPORT ENgetresultindex(int type, int index, int *value)
|
||||
return EN_getresultindex(_defaultProject, type, index, value);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENtimetonextevent(int *eventType, long *duration, int *elementIndex)
|
||||
{
|
||||
return EN_timetonextevent(_defaultProject, eventType, duration, elementIndex);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
||||
@@ -283,8 +314,8 @@ int DLLEXPORT ENgetqualtype(int *qualType, int *traceNode)
|
||||
return EN_getqualtype(_defaultProject, qualType, traceNode);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetqualtype(int qualType, char *chemName, char *chemUnits,
|
||||
char *traceNode)
|
||||
int DLLEXPORT ENsetqualtype(int qualType, const char *chemName,
|
||||
const char *chemUnits, const char *traceNode)
|
||||
{
|
||||
return EN_setqualtype(_defaultProject, qualType, chemName, chemUnits, traceNode);
|
||||
}
|
||||
@@ -295,7 +326,7 @@ int DLLEXPORT ENsetqualtype(int qualType, char *chemName, char *chemUnits,
|
||||
|
||||
********************************************************************/
|
||||
|
||||
int DLLEXPORT ENaddnode(char *id, int nodeType, int *index)
|
||||
int DLLEXPORT ENaddnode(const char *id, int nodeType, int *index)
|
||||
{
|
||||
return EN_addnode(_defaultProject, id, nodeType, index);
|
||||
}
|
||||
@@ -305,7 +336,7 @@ int DLLEXPORT ENdeletenode(int index, int actionCode)
|
||||
return EN_deletenode(_defaultProject, index, actionCode);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENgetnodeindex(char *id, int *index)
|
||||
int DLLEXPORT ENgetnodeindex(const char *id, int *index)
|
||||
{
|
||||
return EN_getnodeindex(_defaultProject, id, index);
|
||||
}
|
||||
@@ -315,7 +346,7 @@ int DLLEXPORT ENgetnodeid(int index, char *id)
|
||||
return EN_getnodeid(_defaultProject, index, id);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetnodeid(int index, char *newid)
|
||||
int DLLEXPORT ENsetnodeid(int index, const char *newid)
|
||||
{
|
||||
return EN_setnodeid(_defaultProject, index, newid);
|
||||
}
|
||||
@@ -333,13 +364,27 @@ int DLLEXPORT ENgetnodevalue(int index, int property, EN_API_FLOAT_TYPE *value)
|
||||
return errcode;
|
||||
}
|
||||
|
||||
int DLLEXPORT ENgetnodevalues(int property, EN_API_FLOAT_TYPE *values)
|
||||
{
|
||||
int i, errcode = 0;
|
||||
EN_API_FLOAT_TYPE value;
|
||||
|
||||
for (i = 1; i <= _defaultProject->network.Nnodes; i++)
|
||||
{
|
||||
errcode = ENgetnodevalue(i, property, &value);
|
||||
values[i-1] = value;
|
||||
if (errcode != 0) return errcode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetnodevalue(int index, int property, EN_API_FLOAT_TYPE value)
|
||||
{
|
||||
return EN_setnodevalue(_defaultProject, index, property, value);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetjuncdata(int index, EN_API_FLOAT_TYPE elev, EN_API_FLOAT_TYPE dmnd,
|
||||
char *dmndpat)
|
||||
const char *dmndpat)
|
||||
{
|
||||
return EN_setjuncdata(_defaultProject, index, elev, dmnd, dmndpat);
|
||||
}
|
||||
@@ -347,7 +392,7 @@ int DLLEXPORT ENsetjuncdata(int index, EN_API_FLOAT_TYPE elev, EN_API_FLOAT_TYPE
|
||||
int DLLEXPORT ENsettankdata(int index, EN_API_FLOAT_TYPE elev,
|
||||
EN_API_FLOAT_TYPE initlvl, EN_API_FLOAT_TYPE minlvl,
|
||||
EN_API_FLOAT_TYPE maxlvl, EN_API_FLOAT_TYPE diam,
|
||||
EN_API_FLOAT_TYPE minvol, char *volcurve)
|
||||
EN_API_FLOAT_TYPE minvol, const char *volcurve)
|
||||
{
|
||||
return EN_settankdata(_defaultProject, index, elev, initlvl, minlvl, maxlvl,
|
||||
diam, minvol, volcurve);
|
||||
@@ -387,7 +432,7 @@ int DLLEXPORT ENsetdemandmodel(int model, EN_API_FLOAT_TYPE pmin,
|
||||
}
|
||||
|
||||
int DLLEXPORT ENadddemand(int nodeIndex, EN_API_FLOAT_TYPE baseDemand,
|
||||
char *demandPattern, char *demandName)
|
||||
const char *demandPattern, const char *demandName)
|
||||
{
|
||||
return EN_adddemand(_defaultProject, nodeIndex, baseDemand, demandPattern, demandName);
|
||||
}
|
||||
@@ -397,7 +442,7 @@ int DLLEXPORT ENdeletedemand(int nodeIndex, int demandIndex)
|
||||
return EN_deletedemand(_defaultProject, nodeIndex, demandIndex);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENgetdemandindex(int nodeIndex, char *demandName, int *demandIndex)
|
||||
int DLLEXPORT ENgetdemandindex(int nodeIndex, const char *demandName, int *demandIndex)
|
||||
{
|
||||
return EN_getdemandindex(_defaultProject, nodeIndex, demandName, demandIndex);
|
||||
}
|
||||
@@ -437,7 +482,7 @@ int DLLEXPORT ENgetdemandname(int nodeIndex, int demandIndex, char *demandName)
|
||||
return EN_getdemandname(_defaultProject, nodeIndex, demandIndex, demandName);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetdemandname(int nodeIndex, int demandIndex, char *demandName)
|
||||
int DLLEXPORT ENsetdemandname(int nodeIndex, int demandIndex, const char *demandName)
|
||||
{
|
||||
return EN_setdemandname(_defaultProject, nodeIndex, demandIndex, demandName);
|
||||
}
|
||||
@@ -448,7 +493,8 @@ int DLLEXPORT ENsetdemandname(int nodeIndex, int demandIndex, char *demandName)
|
||||
|
||||
********************************************************************/
|
||||
|
||||
int DLLEXPORT ENaddlink(char *id, int linkType, char *fromNode, char *toNode, int *index)
|
||||
int DLLEXPORT ENaddlink(const char *id, int linkType, const char *fromNode,
|
||||
const char *toNode, int *index)
|
||||
{
|
||||
return EN_addlink(_defaultProject, id, linkType, fromNode, toNode, index);
|
||||
}
|
||||
@@ -458,7 +504,7 @@ int DLLEXPORT ENdeletelink(int index, int actionCode)
|
||||
return EN_deletelink(_defaultProject, index, actionCode);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENgetlinkindex(char *id, int *index)
|
||||
int DLLEXPORT ENgetlinkindex(const char *id, int *index)
|
||||
{
|
||||
return EN_getlinkindex(_defaultProject, id, index);
|
||||
}
|
||||
@@ -468,7 +514,7 @@ int DLLEXPORT ENgetlinkid(int index, char *id)
|
||||
return EN_getlinkid(_defaultProject, index, id);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetlinkid(int index, char *newid)
|
||||
int DLLEXPORT ENsetlinkid(int index, const char *newid)
|
||||
{
|
||||
return EN_setlinkid(_defaultProject, index, newid);
|
||||
}
|
||||
@@ -500,6 +546,19 @@ int DLLEXPORT ENgetlinkvalue(int index, int property, EN_API_FLOAT_TYPE *value)
|
||||
*value = (EN_API_FLOAT_TYPE)v;
|
||||
return errcode;
|
||||
}
|
||||
int DLLEXPORT ENgetlinkvalues(int property, EN_API_FLOAT_TYPE *values)
|
||||
{
|
||||
int i, errcode = 0;
|
||||
EN_API_FLOAT_TYPE value;
|
||||
|
||||
for (i = 1; i <= _defaultProject->network.Nlinks; i++)
|
||||
{
|
||||
errcode = ENgetlinkvalue(i, property, &value);
|
||||
values[i-1] = value;
|
||||
if (errcode != 0) return errcode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetlinkvalue(int index, int property, EN_API_FLOAT_TYPE value)
|
||||
{
|
||||
@@ -516,16 +575,21 @@ int DLLEXPORT ENgetvertexcount(int index, int *count)
|
||||
{
|
||||
return EN_getvertexcount(_defaultProject, index, count);
|
||||
}
|
||||
|
||||
|
||||
int DLLEXPORT ENgetvertex(int index, int vertex, double *x, double *y)
|
||||
{
|
||||
return EN_getvertex(_defaultProject, index, vertex, x, y);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetvertex(int index, int vertex, double x, double y)
|
||||
{
|
||||
return EN_setvertex(_defaultProject, index, vertex, x, y);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetvertices(int index, double *x, double *y, int count)
|
||||
{
|
||||
return EN_setvertices(_defaultProject, index, x, y, count);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
||||
@@ -554,7 +618,7 @@ int DLLEXPORT ENsetheadcurveindex(int linkIndex, int curveIndex)
|
||||
|
||||
********************************************************************/
|
||||
|
||||
int DLLEXPORT ENaddpattern(char *id)
|
||||
int DLLEXPORT ENaddpattern(const char *id)
|
||||
{
|
||||
return EN_addpattern(_defaultProject, id);
|
||||
}
|
||||
@@ -564,7 +628,7 @@ int DLLEXPORT ENdeletepattern(int index)
|
||||
return EN_deletepattern(_defaultProject, index);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENgetpatternindex(char *id, int *index)
|
||||
int DLLEXPORT ENgetpatternindex(const char *id, int *index)
|
||||
{
|
||||
return EN_getpatternindex(_defaultProject, id, index);
|
||||
}
|
||||
@@ -574,7 +638,7 @@ int DLLEXPORT ENgetpatternid(int index, char *id)
|
||||
return EN_getpatternid(_defaultProject, index, id);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetpatternid(int index, char *id)
|
||||
int DLLEXPORT ENsetpatternid(int index, const char *id)
|
||||
{
|
||||
return EN_setpatternid(_defaultProject, index, id);
|
||||
}
|
||||
@@ -621,13 +685,18 @@ int DLLEXPORT ENsetpattern(int index, EN_API_FLOAT_TYPE *values, int len)
|
||||
return errcode;
|
||||
}
|
||||
|
||||
int DLLEXPORT ENloadpatternfile(const char *filename, const char *id)
|
||||
{
|
||||
return EN_loadpatternfile(_defaultProject, filename, id);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
||||
Data Curve Functions
|
||||
|
||||
********************************************************************/
|
||||
|
||||
int DLLEXPORT ENaddcurve(char *id)
|
||||
int DLLEXPORT ENaddcurve(const char *id)
|
||||
{
|
||||
return EN_addcurve(_defaultProject, id);
|
||||
}
|
||||
@@ -637,7 +706,7 @@ int DLLEXPORT ENdeletecurve(int index)
|
||||
return EN_deletecurve(_defaultProject, index);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENgetcurveindex(char *id, int *index)
|
||||
int DLLEXPORT ENgetcurveindex(const char *id, int *index)
|
||||
{
|
||||
return EN_getcurveindex(_defaultProject, id, index);
|
||||
}
|
||||
@@ -647,7 +716,7 @@ int DLLEXPORT ENgetcurveid(int index, char *id)
|
||||
return EN_getcurveid(_defaultProject, index, id);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetcurveid(int index, char *id)
|
||||
int DLLEXPORT ENsetcurveid(int index, const char *id)
|
||||
{
|
||||
return EN_setcurveid(_defaultProject, index, id);
|
||||
}
|
||||
@@ -662,6 +731,11 @@ int DLLEXPORT ENgetcurvetype(int index, int *type)
|
||||
return EN_getcurvetype(_defaultProject, index, type);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetcurvetype(int index, int type)
|
||||
{
|
||||
return EN_setcurvetype(_defaultProject, index, type);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENgetcurvevalue(int curveIndex, int pointIndex, EN_API_FLOAT_TYPE *x,
|
||||
EN_API_FLOAT_TYPE *y)
|
||||
{
|
||||
@@ -704,10 +778,10 @@ int DLLEXPORT ENsetcurve(int index, EN_API_FLOAT_TYPE *xValues,
|
||||
double *xx = NULL;
|
||||
double *yy = NULL;
|
||||
int i, errcode = 0;
|
||||
|
||||
|
||||
if (xValues == NULL || yValues == NULL) return 206;
|
||||
if (nPoints < 1) return 202;
|
||||
|
||||
|
||||
xx = (double *)calloc(nPoints, sizeof(double));
|
||||
yy = (double *)calloc(nPoints, sizeof(double));
|
||||
if (xx && yy)
|
||||
@@ -761,6 +835,17 @@ int DLLEXPORT ENsetcontrol(int index, int type, int linkIndex,
|
||||
nodeIndex, level);
|
||||
}
|
||||
|
||||
|
||||
int DLLEXPORT ENgetcontrolenabled(int index, int *out_enabled)
|
||||
{
|
||||
return EN_getcontrolenabled(_defaultProject, index, out_enabled);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetcontrolenabled(int index, int enabled)
|
||||
{
|
||||
return EN_setcontrolenabled(_defaultProject, index, enabled);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
||||
Rule-Based Controls Functions
|
||||
@@ -863,3 +948,14 @@ int DLLEXPORT ENsetrulepriority(int index, EN_API_FLOAT_TYPE priority)
|
||||
{
|
||||
return EN_setrulepriority(_defaultProject, index, priority);
|
||||
}
|
||||
|
||||
|
||||
int DLLEXPORT ENgetruleenabled(int index, int *out_enabled)
|
||||
{
|
||||
return EN_getruleenabled(_defaultProject, index, out_enabled);
|
||||
}
|
||||
|
||||
int DLLEXPORT ENsetruleenabled(int index, int enabled)
|
||||
{
|
||||
return EN_setruleenabled(_defaultProject, index, enabled);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ DAT(120,"cannot solve water quality transport equations")
|
||||
// These errors apply only to an input file
|
||||
DAT(200,"one or more errors in input file")
|
||||
DAT(201,"syntax error")
|
||||
DAT(299,"invalid section keyword")
|
||||
|
||||
// These errors apply to both an input file and to API functions
|
||||
DAT(202,"illegal numeric value")
|
||||
@@ -43,7 +44,10 @@ DAT(225,"invalid lower/upper levels for tank")
|
||||
DAT(226,"no head curve or power rating for pump")
|
||||
DAT(227,"invalid head curve for pump")
|
||||
DAT(230,"nonincreasing x-values for curve")
|
||||
DAT(233,"network has unconnected node")
|
||||
DAT(231,"no data provided for curve")
|
||||
DAT(232,"no data provided for pattern")
|
||||
DAT(233,"network has unconnected nodes")
|
||||
DAT(234,"network has an unconnected node with ID: ")
|
||||
|
||||
// These errors apply only to API functions
|
||||
DAT(240,"nonexistent source")
|
||||
@@ -60,6 +64,8 @@ DAT(259,"attempt to delete a node that still has links connected to it")
|
||||
DAT(260,"attempt to delete node assigned as a Trace Node")
|
||||
DAT(261,"attempt to delete a node or link contained in a control")
|
||||
DAT(262,"attempt to modify network structure while solver is active")
|
||||
DAT(263,"node is not a tank")
|
||||
DAT(264,"link is not a valve")
|
||||
|
||||
// File errors
|
||||
DAT(301,"identical file names")
|
||||
|
||||
186
src/flowbalance.c
Normal file
186
src/flowbalance.c
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.3
|
||||
Module: flowbalance.c
|
||||
Description: computes components of network's flow balance
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 06/26/2024
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
|
||||
// Exported functions (declared in funcs.h)
|
||||
//void startflowbalance(Project *);
|
||||
//void updateflowbalance(Project *, long);
|
||||
//void endflowbalance(Project *);
|
||||
|
||||
void startflowbalance(Project *pr)
|
||||
/*
|
||||
**-------------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: initializes components of the network's flow balance.
|
||||
**-------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
hyd->FlowBalance.totalInflow = 0.0;
|
||||
hyd->FlowBalance.totalOutflow = 0.0;
|
||||
hyd->FlowBalance.consumerDemand = 0.0;
|
||||
hyd->FlowBalance.emitterDemand = 0.0;
|
||||
hyd->FlowBalance.leakageDemand = 0.0;
|
||||
hyd->FlowBalance.deficitDemand = 0.0;
|
||||
hyd->FlowBalance.storageDemand = 0.0;
|
||||
hyd->FlowBalance.ratio = 0.0;
|
||||
}
|
||||
|
||||
void updateflowbalance(Project *pr, long hstep)
|
||||
/*
|
||||
**-------------------------------------------------------------------
|
||||
** Input: hstep = time step (sec)
|
||||
** Output: none
|
||||
** Purpose: updates components of the system flow balance.
|
||||
**-------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Times *time = &pr->times;
|
||||
|
||||
int i, j;
|
||||
double v, dt, deficit, fullDemand;
|
||||
SflowBalance flowBalance;
|
||||
|
||||
// Determine current time interval in seconds
|
||||
if (time->Dur == 0) dt = 1.0;
|
||||
else if (time->Htime < time->Dur)
|
||||
{
|
||||
dt = (double) hstep;
|
||||
}
|
||||
else return;
|
||||
|
||||
// Initialize local flow balance
|
||||
flowBalance.totalInflow = 0.0;
|
||||
flowBalance.totalOutflow = 0.0;
|
||||
flowBalance.consumerDemand = 0.0;
|
||||
flowBalance.emitterDemand = 0.0;
|
||||
flowBalance.leakageDemand = 0.0;
|
||||
flowBalance.deficitDemand = 0.0;
|
||||
flowBalance.storageDemand = 0.0;
|
||||
fullDemand = 0.0;
|
||||
|
||||
// Initialize leakage loss
|
||||
hyd->LeakageLoss = 0.0;
|
||||
|
||||
// Examine each junction node
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
// Accumulate consumer demand flow
|
||||
v = hyd->DemandFlow[i];
|
||||
if (v < 0.0)
|
||||
flowBalance.totalInflow += (-v);
|
||||
else
|
||||
{
|
||||
fullDemand += hyd->FullDemand[i];
|
||||
flowBalance.consumerDemand += v;
|
||||
flowBalance.totalOutflow += v;
|
||||
}
|
||||
|
||||
// Accumulate emitter and leakage flow
|
||||
v = hyd->EmitterFlow[i];
|
||||
flowBalance.emitterDemand += v;
|
||||
flowBalance.totalOutflow += v;
|
||||
v = hyd->LeakageFlow[i];
|
||||
flowBalance.leakageDemand += v;
|
||||
flowBalance.totalOutflow += v;
|
||||
|
||||
// Accumulate demand deficit flow
|
||||
if (hyd->DemandModel == PDA && hyd->FullDemand[i] > 0.0)
|
||||
{
|
||||
deficit = hyd->FullDemand[i] - hyd->DemandFlow[i];
|
||||
if (deficit > 0.0)
|
||||
flowBalance.deficitDemand += deficit;
|
||||
}
|
||||
}
|
||||
|
||||
// Examine each tank/reservoir node
|
||||
for (j = 1; j <= net->Ntanks; j++)
|
||||
{
|
||||
i = net->Tank[j].Node;
|
||||
v = hyd->NodeDemand[i];
|
||||
|
||||
// For a reservoir node
|
||||
if (net->Tank[j].A == 0.0)
|
||||
{
|
||||
if (v >= 0.0)
|
||||
flowBalance.totalOutflow += v;
|
||||
else
|
||||
flowBalance.totalInflow += (-v);
|
||||
}
|
||||
|
||||
// For tank
|
||||
else
|
||||
flowBalance.storageDemand += v;
|
||||
}
|
||||
|
||||
// Find % leakage for current period
|
||||
v = flowBalance.totalInflow;
|
||||
if (flowBalance.storageDemand < 0.0) v += (-flowBalance.storageDemand);
|
||||
if (v > 0.0)
|
||||
hyd->LeakageLoss = flowBalance.leakageDemand / v * 100.0;
|
||||
|
||||
// Update flow balance for entire run
|
||||
hyd->FlowBalance.totalInflow += flowBalance.totalInflow * dt;
|
||||
hyd->FlowBalance.totalOutflow += flowBalance.totalOutflow * dt;
|
||||
hyd->FlowBalance.consumerDemand += flowBalance.consumerDemand * dt;
|
||||
hyd->FlowBalance.emitterDemand += flowBalance.emitterDemand * dt;
|
||||
hyd->FlowBalance.leakageDemand += flowBalance.leakageDemand * dt;
|
||||
hyd->FlowBalance.deficitDemand += flowBalance.deficitDemand * dt;
|
||||
hyd->FlowBalance.storageDemand += flowBalance.storageDemand * dt;
|
||||
}
|
||||
|
||||
void endflowbalance(Project *pr)
|
||||
/*
|
||||
**-------------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: finalizes components of the system flow balance.
|
||||
**-------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Times *time = &pr->times;
|
||||
|
||||
double seconds, qin, qout, qstor, r;
|
||||
|
||||
if (time->Htime > 0)
|
||||
seconds = time->Htime;
|
||||
else
|
||||
seconds = 1.0;
|
||||
hyd->FlowBalance.totalInflow /= seconds;
|
||||
hyd->FlowBalance.totalOutflow /= seconds;
|
||||
hyd->FlowBalance.consumerDemand /= seconds;
|
||||
hyd->FlowBalance.emitterDemand /= seconds;
|
||||
hyd->FlowBalance.leakageDemand /= seconds;
|
||||
hyd->FlowBalance.deficitDemand /= seconds;
|
||||
hyd->FlowBalance.storageDemand /= seconds;
|
||||
|
||||
qin = hyd->FlowBalance.totalInflow;
|
||||
qout = hyd->FlowBalance.totalOutflow;
|
||||
qstor = hyd->FlowBalance.storageDemand;
|
||||
if (qstor > 0.0)
|
||||
qout += qstor;
|
||||
else
|
||||
qin -= qstor;
|
||||
if (qin == qout)
|
||||
r = 1.0;
|
||||
else if (qin > 0.0)
|
||||
r = qout / qin;
|
||||
else
|
||||
r = 0.0;
|
||||
hyd->FlowBalance.ratio = r;
|
||||
}
|
||||
54
src/funcs.h
54
src/funcs.h
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: funcs.h
|
||||
Description: prototypes of external functions called by various modules
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/15/2019
|
||||
Last Updated: 04/23/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
#ifndef FUNCS_H
|
||||
@@ -19,6 +19,7 @@ void initpointers(Project *);
|
||||
int allocdata(Project *);
|
||||
void freedata(Project *);
|
||||
|
||||
int openproject(Project *, const char *, const char *, const char *, int);
|
||||
int openfiles(Project *, const char *, const char *,const char *);
|
||||
int openhydfile(Project *);
|
||||
int openoutfile(Project *);
|
||||
@@ -28,17 +29,20 @@ int buildadjlists(Network *);
|
||||
void freeadjlists(Network *);
|
||||
|
||||
int incontrols(Project *, int, int);
|
||||
int changevalvetype(Project *, int, int);
|
||||
int valvecheck(Project *, int, int, int, int);
|
||||
int findnode(Network *, char *);
|
||||
int findlink(Network *, char *);
|
||||
int unlinked(Project *);
|
||||
|
||||
int findnode(Network *, const char *);
|
||||
int findlink(Network *, const char *);
|
||||
int findtank(Network *, int);
|
||||
int findvalve(Network *, int);
|
||||
int findpump(Network *, int);
|
||||
int findpattern(Network *, char *);
|
||||
int findcurve(Network *, char *);
|
||||
int findpattern(Network *, const char *);
|
||||
int findcurve(Network *, const char *);
|
||||
|
||||
Pdemand finddemand(Pdemand, int);
|
||||
int adddemand(Snode *, double, int, char *);
|
||||
int adddemand(Snode *, double, int, const char *);
|
||||
void freedemands(Snode *);
|
||||
|
||||
int addlinkvertex(Slink *, double, double);
|
||||
@@ -46,11 +50,13 @@ void freelinkvertices(Slink *);
|
||||
|
||||
void adjustpatterns(Network *, int);
|
||||
void adjustcurves(Network *, int);
|
||||
int adjustpumpparams(Project *, int);
|
||||
int resizecurve(Scurve *, int);
|
||||
int setcontrol(Project *, int, int, double, int, double, Scontrol *);
|
||||
|
||||
int getcomment(Network *, int, int, char *);
|
||||
int setcomment(Network *, int, int, const char *);
|
||||
int gettag(Network *, int, int, char *);
|
||||
int settag(Network *, int, int, const char *);
|
||||
|
||||
int namevalid(const char *);
|
||||
void getTmpName(char *);
|
||||
@@ -67,7 +73,7 @@ int getdata(Project *);
|
||||
void setdefaults(Project *);
|
||||
void initreport(Report *);
|
||||
void adjustdata(Project *);
|
||||
int inittanks(Project *);
|
||||
void inittanks(Project *);
|
||||
void initunits(Project *);
|
||||
void convertunits(Project *);
|
||||
|
||||
@@ -75,7 +81,6 @@ void convertunits(Project *);
|
||||
|
||||
int netsize(Project *);
|
||||
int readdata(Project *);
|
||||
int updatepumpparams(Project *, int);
|
||||
int findmatch(char *, char *[]);
|
||||
int match(const char *, const char *);
|
||||
int gettokens(char *, char **, int, char *);
|
||||
@@ -98,6 +103,7 @@ int controldata(Project *);
|
||||
int energydata(Project *);
|
||||
int sourcedata(Project *);
|
||||
int emitterdata(Project *);
|
||||
int leakagedata(Project *);
|
||||
int qualdata(Project *);
|
||||
int reactdata(Project *);
|
||||
int mixingdata(Project *);
|
||||
@@ -106,6 +112,7 @@ int reportdata(Project *);
|
||||
int timedata(Project *);
|
||||
int optiondata(Project *);
|
||||
int vertexdata(Project *);
|
||||
int tagdata(Project *);
|
||||
|
||||
// ------- RULES.C ------------------
|
||||
|
||||
@@ -117,28 +124,30 @@ void freerules(Project *);
|
||||
int ruledata(Project *);
|
||||
void ruleerrmsg(Project *);
|
||||
void adjustrules(Project *, int, int);
|
||||
void adjusttankrules(Project *);
|
||||
void adjusttankrules(Project *, int);
|
||||
Spremise *getpremise(Spremise *, int);
|
||||
Saction *getaction(Saction *, int);
|
||||
int writerule(Project *, FILE *, int);
|
||||
int checkrules(Project *, long);
|
||||
void updateruleunits(Project *pr, double dcf, double pcf, double hcf, double qcf);
|
||||
|
||||
// ------- REPORT.C -----------------
|
||||
|
||||
int clearreport(Project *);
|
||||
int copyreport(Project *, char *);
|
||||
int copyreport(Project *, const char *);
|
||||
int writereport(Project *);
|
||||
void writelogo(Project *);
|
||||
void writesummary(Project *);
|
||||
void writehydstat(Project *, int, double);
|
||||
void writeheader(Project *, int,int);
|
||||
void writeline(Project *, char *);
|
||||
void writeline(Project *, const char *);
|
||||
void writerelerr(Project *, int, double);
|
||||
void writestatchange(Project *, int,char,char);
|
||||
void writecontrolaction(Project *, int, int);
|
||||
void writeruleaction(Project *, int, char *);
|
||||
int writehydwarn(Project *, int,double);
|
||||
void writehyderr(Project *, int);
|
||||
void writeflowbalance(Project *);
|
||||
void writemassbalance(Project *);
|
||||
void writetime(Project *, char *);
|
||||
char *clocktime(char *, long);
|
||||
@@ -153,6 +162,7 @@ void closehyd(Project *);
|
||||
void setlinkstatus(Project *, int, char, StatusType *, double *);
|
||||
void setlinksetting(Project *, int, double, StatusType *, double *);
|
||||
int tanktimestep(Project *, long *);
|
||||
int controltimestep(Project *, long *);
|
||||
void getenergy(Project *, int, double *, double *);
|
||||
double tankvolume(Project *, int, double);
|
||||
double tankgrade(Project *, int, double);
|
||||
@@ -162,8 +172,9 @@ double tankgrade(Project *, int, double);
|
||||
void resistcoeff(Project *, int);
|
||||
void headlosscoeffs(Project *);
|
||||
void matrixcoeffs(Project *);
|
||||
void emitterheadloss(Project *, int, double *, double *);
|
||||
void emitterheadloss(Project *, int, double *, double *);
|
||||
void demandheadloss(Project *, int, double, double, double *, double *);
|
||||
double pcvlosscoeff(Project *, int, double);
|
||||
|
||||
// ------- QUALITY.C --------------------
|
||||
|
||||
@@ -190,4 +201,19 @@ int savefinaloutput(Project *);
|
||||
|
||||
int saveinpfile(Project *, const char *);
|
||||
|
||||
// ------- LEAKAGE.C --------------------
|
||||
|
||||
int openleakage(Project *);
|
||||
void closeleakage(Project *);
|
||||
double findlinkleakage(Project *, int);
|
||||
void leakagecoeffs(Project *);
|
||||
double leakageflowchange(Project *, int);
|
||||
int leakagehasconverged(Project *);
|
||||
|
||||
// ------- FLOWBALANCE.C-----------------
|
||||
|
||||
void startflowbalance(Project *);
|
||||
void updateflowbalance(Project *, long);
|
||||
void endflowbalance(Project *);
|
||||
|
||||
#endif
|
||||
|
||||
14
src/hash.c
14
src/hash.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: hash.c
|
||||
Description: implementation of a simple hash table
|
||||
Authors: see AUTHORS
|
||||
@@ -26,7 +26,7 @@ typedef struct DataEntryStruct
|
||||
} DataEntry;
|
||||
|
||||
// Hash a string to an integer
|
||||
unsigned int gethash(char *str)
|
||||
unsigned int gethash(const char *str)
|
||||
{
|
||||
unsigned int hash = 5381;
|
||||
unsigned int retHash;
|
||||
@@ -61,7 +61,7 @@ HashTable *hashtable_create()
|
||||
}
|
||||
|
||||
// Insert an entry into the hash table
|
||||
int hashtable_insert(HashTable *ht, char *key, int data)
|
||||
int hashtable_insert(HashTable *ht, const char *key, int data)
|
||||
{
|
||||
unsigned int i = gethash(key);
|
||||
DataEntry *entry;
|
||||
@@ -76,7 +76,7 @@ int hashtable_insert(HashTable *ht, char *key, int data)
|
||||
}
|
||||
|
||||
// Change the hash table's data entry for a particular key
|
||||
int hashtable_update(HashTable *ht, char *key, int new_data)
|
||||
int hashtable_update(HashTable *ht, const char *key, int new_data)
|
||||
{
|
||||
unsigned int i = gethash(key);
|
||||
DataEntry *entry;
|
||||
@@ -96,7 +96,7 @@ int hashtable_update(HashTable *ht, char *key, int new_data)
|
||||
}
|
||||
|
||||
// Delete an entry in the hash table
|
||||
int hashtable_delete(HashTable *ht, char *key)
|
||||
int hashtable_delete(HashTable *ht, const char *key)
|
||||
{
|
||||
unsigned int i = gethash(key);
|
||||
DataEntry *entry, *preventry;
|
||||
@@ -122,7 +122,7 @@ int hashtable_delete(HashTable *ht, char *key)
|
||||
}
|
||||
|
||||
// Find the data for a particular key
|
||||
int hashtable_find(HashTable *ht, char *key)
|
||||
int hashtable_find(HashTable *ht, const char *key)
|
||||
{
|
||||
unsigned int i = gethash(key);
|
||||
DataEntry *entry;
|
||||
@@ -141,7 +141,7 @@ int hashtable_find(HashTable *ht, char *key)
|
||||
}
|
||||
|
||||
// Find a particular key in the hash table
|
||||
char *hashtable_findkey(HashTable *ht, char *key)
|
||||
char *hashtable_findkey(HashTable *ht, const char *key)
|
||||
{
|
||||
unsigned int i = gethash(key);
|
||||
DataEntry *entry;
|
||||
|
||||
12
src/hash.h
12
src/hash.h
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: hash.h
|
||||
Description: header for a simple hash table
|
||||
Authors: see AUTHORS
|
||||
@@ -18,11 +18,11 @@
|
||||
typedef struct DataEntryStruct *HashTable;
|
||||
|
||||
HashTable *hashtable_create(void);
|
||||
int hashtable_insert(HashTable *, char *, int);
|
||||
int hashtable_find(HashTable *, char *);
|
||||
char *hashtable_findkey(HashTable *, char *);
|
||||
int hashtable_insert(HashTable *, const char *, int);
|
||||
int hashtable_find(HashTable *, const char *);
|
||||
char *hashtable_findkey(HashTable *, const char *);
|
||||
void hashtable_free(HashTable *);
|
||||
int hashtable_update(HashTable *ht, char *key, int new_data);
|
||||
int hashtable_delete(HashTable *ht, char *key);
|
||||
int hashtable_update(HashTable *ht, const char *key, int new_data);
|
||||
int hashtable_delete(HashTable *ht, const char *key);
|
||||
|
||||
#endif
|
||||
|
||||
232
src/hydcoeffs.c
232
src/hydcoeffs.c
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: hydcoeffs.c
|
||||
Description: computes coefficients for a hydraulic solution matrix
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 10/04/2019
|
||||
Last Updated: 06/15/2024
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -36,6 +36,7 @@ const double CBIG = 1.e8;
|
||||
|
||||
// Exported functions
|
||||
//void resistcoeff(Project *, int );
|
||||
//double pcvlosscoeff(Project *, int, double);
|
||||
//void headlosscoeffs(Project *);
|
||||
//void matrixcoeffs(Project *);
|
||||
//void emitterheadloss(Project *, int, double *, double *);
|
||||
@@ -59,11 +60,47 @@ static void valvecoeff(Project *pr, int k);
|
||||
static void gpvcoeff(Project *pr, int k);
|
||||
static void pbvcoeff(Project *pr, int k);
|
||||
static void tcvcoeff(Project *pr, int k);
|
||||
static void pcvcoeff(Project *pr, int k);
|
||||
static void prvcoeff(Project *pr, int k, int n1, int n2);
|
||||
static void psvcoeff(Project *pr, int k, int n1, int n2);
|
||||
static void fcvcoeff(Project *pr, int k, int n1, int n2);
|
||||
|
||||
|
||||
void addlowerbarrier(double dq, double* hloss, double* hgrad)
|
||||
/*
|
||||
**--------------------------------------------------------------------
|
||||
** Input: dq = difference between current flow and lower flow limit
|
||||
** Output: hloss = updated head loss value
|
||||
** hgrad = updated head loss gradient value
|
||||
** Purpose: adds a head loss barrier to prevent flow from falling
|
||||
** below a given lower limit.
|
||||
**--------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
double a = 1.e9 * dq;
|
||||
double b = sqrt(a*a + 1.e-6);
|
||||
*hloss += (a - b) / 2.;
|
||||
*hgrad += (1.e9 / 2.) * ( 1.0 - a / b);
|
||||
}
|
||||
|
||||
void addupperbarrier(double dq, double* hloss, double* hgrad)
|
||||
/*
|
||||
**--------------------------------------------------------------------
|
||||
** Input: dq = difference between current flow and upper flow limit
|
||||
** Output: hloss = updated head loss value
|
||||
** hgrad = updated head loss gradient value
|
||||
** Purpose: adds a head loss barrier to prevent flow from exceeding
|
||||
** a given upper limit.
|
||||
**--------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
double a = 1.e9 * dq;
|
||||
double b = sqrt(a*a + 1.e-6);
|
||||
*hloss += (a + b) / 2.;
|
||||
*hgrad += (1.e9 / 2.) * ( 1.0 + a / b);
|
||||
}
|
||||
|
||||
|
||||
void resistcoeff(Project *pr, int k)
|
||||
/*
|
||||
**--------------------------------------------------------------------
|
||||
@@ -107,6 +144,10 @@ void resistcoeff(Project *pr, int k)
|
||||
case PUMP:
|
||||
link->R = CBIG;
|
||||
break;
|
||||
|
||||
case PCV:
|
||||
link->R = pcvlosscoeff(pr, k, link->Kc);
|
||||
break;
|
||||
|
||||
// ... For all other links (e.g. valves) use a small resistance
|
||||
default:
|
||||
@@ -116,6 +157,87 @@ void resistcoeff(Project *pr, int k)
|
||||
}
|
||||
|
||||
|
||||
double pcvlosscoeff(Project* pr, int k, double s)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
** s = valve percent open setting
|
||||
** Output: returns a valve loss coefficient
|
||||
** Purpose: finds a Positional Control Valve's loss
|
||||
** coefficient from its percent open setting.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network* net = &pr->network;
|
||||
|
||||
int v = findvalve(net, k); // valve index
|
||||
int c = net->Valve[v].Curve; // Kv curve index
|
||||
double d; // valve diameter
|
||||
double kmo; // fully open loss coeff.
|
||||
double km; // partly open loss coeff.
|
||||
double kvr; // Kv / Kvo (Kvo = Kv at fully open)
|
||||
double *x, *y; // points on kvr v. percent open curve
|
||||
int k1, k2, npts;
|
||||
Scurve *curve;
|
||||
|
||||
// Valve has no setting so return 0
|
||||
if (s == MISSING) return 0.0;
|
||||
|
||||
// Valve is completely open so return its Km value
|
||||
d = net->Link[k].Diam;
|
||||
kmo = net->Link[k].Km;
|
||||
if (s >= 100.0) return kmo;
|
||||
|
||||
// Valve is completely closed so return a large coeff.
|
||||
if (s <= 0.0) return CBIG;
|
||||
|
||||
// Valve has no assigned curve so assume a linear one
|
||||
if (c == 0) kvr = s;
|
||||
|
||||
else
|
||||
{
|
||||
// Valve curve data
|
||||
curve = &net->Curve[c];
|
||||
npts = curve->Npts;
|
||||
x = curve->X; // x = % open
|
||||
y = curve->Y; // y = Kv / Kvo as a %
|
||||
|
||||
// s lies below first point of curve
|
||||
if (s < x[0])
|
||||
kvr = s / x[0] * y[0];
|
||||
|
||||
// s lies above last point of curve
|
||||
else if (s > x[npts-1])
|
||||
{
|
||||
k2 = npts - 1;
|
||||
kvr = (s - x[k2]) / (1. - x[k2]) * (1. - y[k2]) + y[k2];
|
||||
}
|
||||
|
||||
// Otherwise interpolate over curve segment that brackets s
|
||||
else
|
||||
{
|
||||
k2 = 0;
|
||||
while (k2 < npts && x[k2] < s) k2++;
|
||||
if (k2 == 0) k2++;
|
||||
else if (k2 == npts) k2--;
|
||||
k1 = k2 - 1;
|
||||
kvr = (y[k2] - y[k1]) / (x[k2] - x[k1]);
|
||||
kvr = y[k1] + kvr * (s - x[k1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert kvr from % to fraction
|
||||
kvr /= 100.;
|
||||
kvr = MIN(kvr, 1.0);
|
||||
kvr = MAX(kvr, CSMALL);
|
||||
|
||||
// Convert from Kv ratio to minor loss coeff.
|
||||
km = kmo / (kvr * kvr);
|
||||
km = MIN(km, CBIG);
|
||||
return km;
|
||||
}
|
||||
|
||||
|
||||
void headlosscoeffs(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
@@ -148,6 +270,9 @@ void headlosscoeffs(Project *pr)
|
||||
case TCV:
|
||||
tcvcoeff(pr, k);
|
||||
break;
|
||||
case PCV:
|
||||
pcvcoeff(pr, k);
|
||||
break;
|
||||
case GPV:
|
||||
gpvcoeff(pr, k);
|
||||
break;
|
||||
@@ -185,6 +310,7 @@ void matrixcoeffs(Project *pr)
|
||||
linkcoeffs(pr);
|
||||
emittercoeffs(pr);
|
||||
demandcoeffs(pr);
|
||||
if (hyd->HasLeakage) leakagecoeffs(pr);
|
||||
|
||||
// Update nodal flow balances with demands and add onto r.h.s. coeffs.
|
||||
nodecoeffs(pr);
|
||||
@@ -381,7 +507,7 @@ void emitterheadloss(Project *pr, int i, double *hloss, double *hgrad)
|
||||
** Input: i = node index
|
||||
** Output: hloss = head loss across node's emitter
|
||||
** hgrad = head loss gradient
|
||||
** Purpose: computes an emitters's head loss and gradient.
|
||||
** Purpose: computes an emitter's head loss and gradient.
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
@@ -400,12 +526,18 @@ void emitterheadloss(Project *pr, int i, double *hloss, double *hgrad)
|
||||
// Use linear head loss function for small gradient
|
||||
if (*hgrad < hyd->RQtol)
|
||||
{
|
||||
*hgrad = hyd->RQtol;
|
||||
*hgrad = hyd->RQtol / hyd->Qexp;
|
||||
*hloss = (*hgrad) * q;
|
||||
}
|
||||
|
||||
// Otherwise use normal emitter head loss function
|
||||
else *hloss = (*hgrad) * q / hyd->Qexp;
|
||||
|
||||
// Prevent negative flow if backflow not allowed
|
||||
if (hyd->EmitBackFlag == 0)
|
||||
{
|
||||
addlowerbarrier(q, hloss, hgrad);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -443,7 +575,7 @@ void demandcoeffs(Project *pr)
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
// Skip junctions with non-positive demands
|
||||
if (hyd->NodeDemand[i] <= 0.0) continue;
|
||||
if (hyd->FullDemand[i] <= 0.0) continue;
|
||||
|
||||
// Find head loss for demand outflow at node's elevation
|
||||
demandheadloss(pr, i, dp, n, &hloss, &hgrad);
|
||||
@@ -475,35 +607,17 @@ void demandheadloss(Project *pr, int i, double dp, double n,
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
double d = hyd->DemandFlow[i];
|
||||
double dfull = hyd->NodeDemand[i];
|
||||
double dfull = hyd->FullDemand[i];
|
||||
double r = d / dfull;
|
||||
|
||||
// Use lower barrier function for negative demand
|
||||
if (r <= 0)
|
||||
{
|
||||
*hgrad = CBIG;
|
||||
*hloss = CBIG * d;
|
||||
}
|
||||
|
||||
// Use power head loss function for demand less than full
|
||||
else if (r < 1.0)
|
||||
{
|
||||
*hgrad = n * dp * pow(r, n - 1.0) / dfull;
|
||||
// ... use linear function for very small gradient
|
||||
if (*hgrad < hyd->RQtol)
|
||||
{
|
||||
*hgrad = hyd->RQtol;
|
||||
*hloss = (*hgrad) * d;
|
||||
}
|
||||
else *hloss = (*hgrad) * d / n;
|
||||
}
|
||||
// Evaluate inverted demand function
|
||||
r = fabs(d) / dfull;
|
||||
*hgrad = n * dp * pow(r, n - 1.0) / dfull;
|
||||
*hloss = (*hgrad) * d / n;
|
||||
|
||||
// Use upper barrier function for demand above full value
|
||||
else
|
||||
{
|
||||
*hgrad = CBIG;
|
||||
*hloss = dp + CBIG * (d - dfull);
|
||||
}
|
||||
// Add barrier functions
|
||||
addlowerbarrier(d, hloss, hgrad);
|
||||
addupperbarrier(d-dfull, hloss, hgrad);
|
||||
}
|
||||
|
||||
|
||||
@@ -553,7 +667,7 @@ void pipecoeff(Project *pr, int k)
|
||||
// ... use linear function for very small gradient
|
||||
if (hgrad < hyd->RQtol)
|
||||
{
|
||||
hgrad = hyd->RQtol;
|
||||
hgrad = hyd->RQtol / hyd->Hexp;
|
||||
hloss = hgrad * q;
|
||||
}
|
||||
// ... otherwise use original formula
|
||||
@@ -744,17 +858,23 @@ void pumpcoeff(Project *pr, int k)
|
||||
{
|
||||
// ... compute pump curve's gradient
|
||||
hgrad = -r / q / q;
|
||||
// ... use linear curve if gradient too large or too small
|
||||
|
||||
// ... treat as closed link if gradient too large
|
||||
if (hgrad > CBIG)
|
||||
{
|
||||
hgrad = CBIG;
|
||||
hloss = -hgrad * hyd->LinkFlow[k];
|
||||
hyd->P[k] = 1.0 / CBIG;
|
||||
hyd->Y[k] = hyd->LinkFlow[k];
|
||||
return;
|
||||
}
|
||||
else if (hgrad < hyd->RQtol)
|
||||
|
||||
// ... treat as open valve if gradient too small
|
||||
else if (hgrad < CSMALL)
|
||||
{
|
||||
hgrad = hyd->RQtol;
|
||||
hloss = -hgrad * hyd->LinkFlow[k];
|
||||
}
|
||||
hyd->P[k] = 1.0 / CSMALL;
|
||||
hyd->Y[k] = hyd->LinkFlow[k];
|
||||
return;
|
||||
}
|
||||
|
||||
// ... otherwise compute head loss from pump curve
|
||||
else
|
||||
{
|
||||
@@ -939,6 +1059,36 @@ void tcvcoeff(Project *pr, int k)
|
||||
}
|
||||
|
||||
|
||||
void pcvcoeff(Project *pr, int k)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
** Output: none
|
||||
** Purpose: computes P & Y coeffs. for positional control valve
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
double km;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Slink *link = &pr->network.Link[k];
|
||||
|
||||
// Save original loss coeff. for open valve
|
||||
km = link->Km;
|
||||
|
||||
// If valve not fixed OPEN or CLOSED, compute its loss coeff.
|
||||
if (hyd->LinkSetting[k] != MISSING)
|
||||
{
|
||||
link->Km = link->R;
|
||||
}
|
||||
|
||||
// Then apply usual valve formula
|
||||
valvecoeff(pr, k);
|
||||
|
||||
// Restore original loss coeff.
|
||||
link->Km = km;
|
||||
}
|
||||
|
||||
|
||||
void prvcoeff(Project *pr, int k, int n1, int n2)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
@@ -1029,6 +1179,8 @@ void psvcoeff(Project *pr, int k, int n1, int n2)
|
||||
{
|
||||
sm->F[j] += hyd->Xflow[n1];
|
||||
}
|
||||
sm->Aij[sm->Ndx[k]] -= 1.0 / CBIG; // Preserve connectivity
|
||||
sm->Aii[j] += 1.0 / CBIG;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1131,7 +1283,7 @@ void valvecoeff(Project *pr, int k)
|
||||
// Guard against too small a head loss gradient
|
||||
if (hgrad < hyd->RQtol)
|
||||
{
|
||||
hgrad = hyd->RQtol;
|
||||
hgrad = hyd->RQtol / 2.0;
|
||||
hloss = flow * hgrad;
|
||||
}
|
||||
else hloss = flow * hgrad / 2.0;
|
||||
|
||||
147
src/hydraul.c
147
src/hydraul.c
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: hydraul.c
|
||||
Description: implements EPANET's hydraulic engine
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 12/05/2019
|
||||
Last Updated: 04/19/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
const double QZERO = 1.e-6; // Equivalent to zero flow in cfs
|
||||
|
||||
// Imported functions
|
||||
extern int validateproject(Project *);
|
||||
extern int createsparse(Project *);
|
||||
extern void freesparse(Project *);
|
||||
extern int hydsolve(Project *, int *, double *);
|
||||
@@ -34,11 +35,11 @@ void initlinkflow(Project *, int, char, double);
|
||||
void demands(Project *);
|
||||
int controls(Project *);
|
||||
long timestep(Project *);
|
||||
void controltimestep(Project *, long *);
|
||||
void ruletimestep(Project *, long *);
|
||||
void addenergy(Project *, long);
|
||||
void tanklevels(Project *, long);
|
||||
void resetpumpflow(Project *, int);
|
||||
void getallpumpsenergy(Project *);
|
||||
|
||||
int openhyd(Project *pr)
|
||||
/*
|
||||
@@ -52,33 +53,27 @@ int openhyd(Project *pr)
|
||||
int i;
|
||||
int errcode = 0;
|
||||
Slink *link;
|
||||
|
||||
// Check for too few nodes & no fixed grade nodes
|
||||
if (pr->network.Nnodes < 2) errcode = 223;
|
||||
else if (pr->network.Ntanks == 0) errcode = 224;
|
||||
|
||||
// Check for valid project data (see VALIDATE.C)
|
||||
errcode = validateproject(pr);
|
||||
if (errcode > 0) return errcode;
|
||||
|
||||
// Allocate memory for sparse matrix structures (see SMATRIX.C)
|
||||
ERRCODE(createsparse(pr));
|
||||
|
||||
// Allocate memory for hydraulic variables
|
||||
ERRCODE(allocmatrix(pr));
|
||||
|
||||
|
||||
// Check for unconnected nodes
|
||||
if (!errcode) for (i = 1; i <= pr->network.Njuncs; i++)
|
||||
{
|
||||
if (pr->network.Adjlist[i] == NULL)
|
||||
{
|
||||
errcode = 233;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ERRCODE(unlinked(pr));
|
||||
|
||||
// Initialize link flows
|
||||
if (!errcode) for (i = 1; i <= pr->network.Nlinks; i++)
|
||||
{
|
||||
link = &pr->network.Link[i];
|
||||
initlinkflow(pr, i, link->Status, link->Kc);
|
||||
initlinkflow(pr, i, link->InitStatus, link->Kc);
|
||||
}
|
||||
else closehyd(pr);
|
||||
return errcode;
|
||||
}
|
||||
|
||||
@@ -112,8 +107,10 @@ void inithyd(Project *pr, int initflag)
|
||||
hyd->OldStatus[net->Nlinks+i] = TEMPCLOSED;
|
||||
}
|
||||
|
||||
// Initialize emitter flows
|
||||
// Initialize node outflows
|
||||
memset(hyd->DemandFlow,0,(net->Nnodes+1)*sizeof(double));
|
||||
memset(hyd->EmitterFlow,0,(net->Nnodes+1)*sizeof(double));
|
||||
memset(hyd->LeakageFlow,0,(net->Nnodes+1)*sizeof(double));
|
||||
for (i = 1; i <= net->Nnodes; i++)
|
||||
{
|
||||
net->Node[i].ResultIndex = i;
|
||||
@@ -127,9 +124,22 @@ void inithyd(Project *pr, int initflag)
|
||||
link->ResultIndex = i;
|
||||
|
||||
// Initialize status and setting
|
||||
hyd->LinkStatus[i] = link->Status;
|
||||
hyd->LinkSetting[i] = link->Kc;
|
||||
|
||||
hyd->LinkStatus[i] = link->InitStatus;
|
||||
hyd->LinkSetting[i] = link->InitSetting;
|
||||
|
||||
// Setting of non-ACTIVE FCV, PRV, PSV valves is "MISSING"
|
||||
switch (link->Type)
|
||||
{
|
||||
case FCV:
|
||||
case PRV:
|
||||
case PSV:
|
||||
if (link->InitStatus != ACTIVE)
|
||||
{
|
||||
link->Kc = MISSING;
|
||||
hyd->LinkSetting[i] = MISSING;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute flow resistance
|
||||
resistcoeff(pr, i);
|
||||
|
||||
@@ -163,7 +173,12 @@ void inithyd(Project *pr, int initflag)
|
||||
pump->Energy.KwHrsPerFlow = 0.0;
|
||||
pump->Energy.MaxKwatts = 0.0;
|
||||
pump->Energy.TotalCost = 0.0;
|
||||
pump->Energy.CurrentPower = 0.0;
|
||||
pump->Energy.CurrentEffic = 0.0;
|
||||
}
|
||||
|
||||
// Initialize flow balance
|
||||
startflowbalance(pr);
|
||||
|
||||
// Re-position hydraulics file
|
||||
if (pr->outfile.Saveflag)
|
||||
@@ -196,7 +211,7 @@ int runhyd(Project *pr, long *t)
|
||||
int iter; // Iteration count
|
||||
int errcode; // Error code
|
||||
double relerr; // Solution accuracy
|
||||
|
||||
|
||||
// Find new demands & control actions
|
||||
*t = time->Htime;
|
||||
demands(pr);
|
||||
@@ -239,6 +254,9 @@ int nexthyd(Project *pr, long *tstep)
|
||||
long hydstep; // Actual time step
|
||||
int errcode = 0; // Error code
|
||||
|
||||
// Compute current power and efficiency of all pumps
|
||||
getallpumpsenergy(pr);
|
||||
|
||||
// Save current results to hydraulics file and
|
||||
// force end of simulation if Haltflag is active
|
||||
if (pr->outfile.Saveflag) errcode = savehyd(pr, &time->Htime);
|
||||
@@ -250,9 +268,12 @@ int nexthyd(Project *pr, long *tstep)
|
||||
if (time->Htime < time->Dur) hydstep = timestep(pr);
|
||||
if (pr->outfile.Saveflag) errcode = savehydstep(pr,&hydstep);
|
||||
|
||||
// Compute pumping energy
|
||||
// Accumulate pumping energy
|
||||
if (time->Dur == 0) addenergy(pr,0);
|
||||
else if (time->Htime < time->Dur) addenergy(pr,hydstep);
|
||||
|
||||
// Update flow balance
|
||||
updateflowbalance(pr, hydstep);
|
||||
|
||||
// More time remains - update current time
|
||||
if (time->Htime < time->Dur)
|
||||
@@ -267,6 +288,8 @@ int nexthyd(Project *pr, long *tstep)
|
||||
// No more time remains - force completion of analysis
|
||||
else
|
||||
{
|
||||
endflowbalance(pr);
|
||||
if (pr->report.Statflag) writeflowbalance(pr);
|
||||
time->Htime++;
|
||||
if (pr->quality.OpenQflag) time->Qtime++;
|
||||
}
|
||||
@@ -286,6 +309,7 @@ void closehyd(Project *pr)
|
||||
{
|
||||
freesparse(pr);
|
||||
freematrix(pr);
|
||||
freeadjlists(&pr->network);
|
||||
}
|
||||
|
||||
|
||||
@@ -305,16 +329,12 @@ int allocmatrix(Project *pr)
|
||||
|
||||
hyd->P = (double *) calloc(net->Nlinks+1,sizeof(double));
|
||||
hyd->Y = (double *) calloc(net->Nlinks+1,sizeof(double));
|
||||
hyd->DemandFlow = (double *) calloc(net->Nnodes + 1, sizeof(double));
|
||||
hyd->EmitterFlow = (double *) calloc(net->Nnodes+1, sizeof(double));
|
||||
hyd->Xflow = (double *) calloc(MAX((net->Nnodes+1), (net->Nlinks+1)),
|
||||
sizeof(double));
|
||||
hyd->OldStatus = (StatusType *) calloc(net->Nlinks+net->Ntanks+1,
|
||||
sizeof(StatusType));
|
||||
ERRCODE(MEMCHECK(hyd->P));
|
||||
ERRCODE(MEMCHECK(hyd->Y));
|
||||
ERRCODE(MEMCHECK(hyd->DemandFlow));
|
||||
ERRCODE(MEMCHECK(hyd->EmitterFlow));
|
||||
ERRCODE(MEMCHECK(hyd->Xflow));
|
||||
ERRCODE(MEMCHECK(hyd->OldStatus));
|
||||
return errcode;
|
||||
@@ -334,8 +354,6 @@ void freematrix(Project *pr)
|
||||
|
||||
free(hyd->P);
|
||||
free(hyd->Y);
|
||||
free(hyd->DemandFlow);
|
||||
free(hyd->EmitterFlow);
|
||||
free(hyd->Xflow);
|
||||
free(hyd->OldStatus);
|
||||
}
|
||||
@@ -397,7 +415,7 @@ void setlinkstatus(Project *pr, int index, char value, StatusType *s, double *k
|
||||
if (t == PUMP)
|
||||
{
|
||||
*k = 1.0;
|
||||
// Check if a re-opened pump needs its flow reset
|
||||
// Check if a re-opened pump needs its flow reset
|
||||
if (*s == CLOSED) resetpumpflow(pr, index);
|
||||
}
|
||||
if (t > PUMP && t != GPV) *k = MISSING;
|
||||
@@ -457,6 +475,7 @@ void setlinksetting(Project *pr, int index, double value, StatusType *s,
|
||||
else
|
||||
{
|
||||
if (*k == MISSING && *s <= CLOSED) *s = OPEN;
|
||||
if (t == PCV) link->R = pcvlosscoeff(pr, index, link->Kc);
|
||||
*k = value;
|
||||
}
|
||||
}
|
||||
@@ -492,12 +511,14 @@ void demands(Project *pr)
|
||||
{
|
||||
// pattern period (k) = (elapsed periods) modulus (periods per pattern)
|
||||
j = demand->Pat;
|
||||
if (j == 0)
|
||||
j = hyd->DefPat;
|
||||
k = p % (long)net->Pattern[j].Length;
|
||||
djunc = (demand->Base) * net->Pattern[j].F[k] * hyd->Dmult;
|
||||
if (djunc > 0.0) hyd->Dsystem += djunc;
|
||||
sum += djunc;
|
||||
}
|
||||
hyd->NodeDemand[i] = sum;
|
||||
hyd->FullDemand[i] = sum;
|
||||
|
||||
// Initialize pressure dependent demand
|
||||
hyd->DemandFlow[i] = sum;
|
||||
@@ -562,6 +583,10 @@ int controls(Project *pr)
|
||||
{
|
||||
// Make sure that link is defined
|
||||
control = &net->Control[i];
|
||||
if (!control->isEnabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
reset = 0;
|
||||
if ( (k = control->Link) <= 0) continue;
|
||||
link = &net->Link[k];
|
||||
@@ -601,15 +626,16 @@ int controls(Project *pr)
|
||||
k1 = hyd->LinkSetting[k];
|
||||
k2 = k1;
|
||||
if (link->Type > PIPE) k2 = control->Setting;
|
||||
|
||||
|
||||
// Check if a re-opened pump needs its flow reset
|
||||
if (link->Type == PUMP && s1 == CLOSED && s2 == OPEN)
|
||||
resetpumpflow(pr, k);
|
||||
|
||||
|
||||
if (s1 != s2 || k1 != k2)
|
||||
{
|
||||
hyd->LinkStatus[k] = s2;
|
||||
hyd->LinkSetting[k] = k2;
|
||||
if (link->Type == PCV) link->R = pcvlosscoeff(pr, k, k2);
|
||||
if (pr->report.Statflag) writecontrolaction(pr,k,i);
|
||||
setsum++;
|
||||
}
|
||||
@@ -673,7 +699,7 @@ int tanktimestep(Project *pr, long *tstep)
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
int i, n, tankIdx = 0;
|
||||
double h, q, v;
|
||||
double h, q, v, xt;
|
||||
long t;
|
||||
Stank *tank;
|
||||
|
||||
@@ -696,7 +722,9 @@ int tanktimestep(Project *pr, long *tstep)
|
||||
else continue;
|
||||
|
||||
// Find time to fill/drain tank
|
||||
t = (long)ROUND(v / q);
|
||||
xt = v / q;
|
||||
if (ABS(xt) > *tstep + 1) continue;
|
||||
t = (long)ROUND(xt);
|
||||
if (t > 0 && t < *tstep)
|
||||
{
|
||||
*tstep = t;
|
||||
@@ -707,7 +735,7 @@ int tanktimestep(Project *pr, long *tstep)
|
||||
}
|
||||
|
||||
|
||||
void controltimestep(Project *pr, long *tstep)
|
||||
int controltimestep(Project *pr, long *tstep)
|
||||
/*
|
||||
**------------------------------------------------------------------
|
||||
** Input: *tstep = current time step
|
||||
@@ -720,7 +748,7 @@ void controltimestep(Project *pr, long *tstep)
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
int i, j, k, n;
|
||||
int i, j, k, n, controlIndex = 0;
|
||||
double h, q, v;
|
||||
long t, t1, t2;
|
||||
Slink *link;
|
||||
@@ -731,7 +759,10 @@ void controltimestep(Project *pr, long *tstep)
|
||||
{
|
||||
t = 0;
|
||||
control = &net->Control[i];
|
||||
|
||||
if (!control->isEnabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Control depends on a tank level
|
||||
if ( (n = control->Node) > 0)
|
||||
{
|
||||
@@ -777,9 +808,14 @@ void controltimestep(Project *pr, long *tstep)
|
||||
k = control->Link;
|
||||
link = &net->Link[k];
|
||||
if ( (link->Type > PIPE && hyd->LinkSetting[k] != control->Setting)
|
||||
|| (hyd->LinkStatus[k] != control->Status) ) *tstep = t;
|
||||
|| (hyd->LinkStatus[k] != control->Status) )
|
||||
{
|
||||
*tstep = t;
|
||||
controlIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return controlIndex;
|
||||
}
|
||||
|
||||
|
||||
@@ -902,7 +938,7 @@ void addenergy(Project *pr, long hstep)
|
||||
// Skip closed pumps
|
||||
pump = &net->Pump[j];
|
||||
k = pump->Link;
|
||||
if (hyd->LinkStatus[k] <= CLOSED) continue;
|
||||
if (pump->Energy.CurrentEffic == 0.0) continue;
|
||||
q = MAX(QZERO, ABS(hyd->LinkFlow[k]));
|
||||
|
||||
// Find pump-specific energy cost
|
||||
@@ -915,11 +951,10 @@ void addenergy(Project *pr, long hstep)
|
||||
}
|
||||
else c *= f0;
|
||||
|
||||
// Find pump energy & efficiency
|
||||
getenergy(pr, k, &p, &e);
|
||||
psum += p;
|
||||
|
||||
// Update pump's cumulative statistics
|
||||
p = pump->Energy.CurrentPower;
|
||||
e = pump->Energy.CurrentEffic;
|
||||
psum += p;
|
||||
pump->Energy.TimeOnLine += dt;
|
||||
pump->Energy.Efficiency += e * dt;
|
||||
pump->Energy.KwHrsPerFlow += p / q * dt;
|
||||
@@ -995,6 +1030,27 @@ void getenergy(Project *pr, int k, double *kw, double *eff)
|
||||
}
|
||||
|
||||
|
||||
void getallpumpsenergy(Project *pr)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: finds the current power and efficiency for each pump.
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int j;
|
||||
Spump *pump;
|
||||
|
||||
for (j = 1; j <= pr->network.Npumps; j++)
|
||||
{
|
||||
pump = &(pr->network.Pump[j]);
|
||||
getenergy(pr, pump->Link, &(pump->Energy.CurrentPower),
|
||||
&(pump->Energy.CurrentEffic));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void tanklevels(Project *pr, long tstep)
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
@@ -1112,6 +1168,5 @@ void resetpumpflow(Project *pr, int i)
|
||||
Network *net = &pr->network;
|
||||
Spump *pump = &net->Pump[findpump(net, i)];
|
||||
if (pump->Ptype == CONST_HP)
|
||||
pr->hydraul.LinkFlow[i] = pump->Q0;
|
||||
pr->hydraul.LinkFlow[i] = pump->Q0;
|
||||
}
|
||||
|
||||
|
||||
109
src/hydsolver.c
109
src/hydsolver.c
@@ -1,14 +1,14 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: hydsolver.c
|
||||
Description: computes flows and pressures throughout a pipe network using
|
||||
Todini's Global Gradient Algorithm
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 07/15/2019
|
||||
Last Updated: 06/26/2024
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -47,6 +47,7 @@ static double newflows(Project *, Hydbalance *);
|
||||
static void newlinkflows(Project *, Hydbalance *, double *, double *);
|
||||
static void newemitterflows(Project *, Hydbalance *, double *, double *);
|
||||
static void newdemandflows(Project *, Hydbalance *, double *, double *);
|
||||
static void newleakageflows(Project *, Hydbalance *, double *, double *);
|
||||
|
||||
static void checkhydbalance(Project *, Hydbalance *);
|
||||
static int hasconverged(Project *, double *, Hydbalance *);
|
||||
@@ -93,7 +94,6 @@ int hydsolve(Project *pr, int *iter, double *relerr)
|
||||
int valveChange; // Valve status change flag
|
||||
int statChange; // Non-valve status change flag
|
||||
Hydbalance hydbal; // Hydraulic balance errors
|
||||
double fullDemand; // Full demand for a node (cfs)
|
||||
|
||||
// Initialize status checking & relaxation factor
|
||||
nextcheck = hyd->CheckFreq;
|
||||
@@ -178,7 +178,7 @@ int hydsolve(Project *pr, int *iter, double *relerr)
|
||||
nextcheck = *iter + hyd->CheckFreq;
|
||||
}
|
||||
|
||||
// No convergence yet - see if its time for a periodic status
|
||||
// No convergence yet - see if it's time for a periodic status
|
||||
// check on pumps, CV's, and pipes connected to tank
|
||||
else if (*iter <= hyd->MaxCheck && *iter == nextcheck)
|
||||
{
|
||||
@@ -195,12 +195,12 @@ int hydsolve(Project *pr, int *iter, double *relerr)
|
||||
errcode = 110;
|
||||
}
|
||||
|
||||
// Store actual junction outflow in NodeDemand & full demand in DemandFlow
|
||||
// Save total outflow (NodeDemand) at each junction
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
fullDemand = hyd->NodeDemand[i];
|
||||
hyd->NodeDemand[i] = hyd->DemandFlow[i] + hyd->EmitterFlow[i];
|
||||
hyd->DemandFlow[i] = fullDemand;
|
||||
hyd->NodeDemand[i] = hyd->DemandFlow[i] +
|
||||
hyd->EmitterFlow[i] +
|
||||
hyd->LeakageFlow[i];
|
||||
}
|
||||
|
||||
// Save convergence info
|
||||
@@ -381,6 +381,7 @@ double newflows(Project *pr, Hydbalance *hbal)
|
||||
newlinkflows(pr, hbal, &qsum, &dqsum);
|
||||
newemitterflows(pr, hbal, &qsum, &dqsum);
|
||||
newdemandflows(pr, hbal, &qsum, &dqsum);
|
||||
if (hyd->HasLeakage) newleakageflows(pr, hbal, &qsum, &dqsum);
|
||||
|
||||
// Return ratio of total flow corrections to total flow
|
||||
if (qsum > hyd->Hacc) return (dqsum / qsum);
|
||||
@@ -514,6 +515,45 @@ void newemitterflows(Project *pr, Hydbalance *hbal, double *qsum,
|
||||
}
|
||||
|
||||
|
||||
void newleakageflows(Project *pr, Hydbalance *hbal, double *qsum,
|
||||
double *dqsum)
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
** Input: hbal = ptr. to hydraulic balance information
|
||||
** qsum = sum of current system flows
|
||||
** dqsum = sum of system flow changes
|
||||
** Output: updates hbal, qsum and dqsum
|
||||
** Purpose: updates nodal leakage flows after new nodal heads computed
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
int i;
|
||||
double dq;
|
||||
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
// Update leakage flow at node i
|
||||
dq = leakageflowchange(pr, i);
|
||||
if (dq == 0.0) continue;
|
||||
|
||||
// Update system flow summation
|
||||
*qsum += ABS(hyd->LeakageFlow[i]);
|
||||
*dqsum += ABS(dq);
|
||||
|
||||
// Update identity of element with max. flow change
|
||||
if (ABS(dq) > hbal->maxflowchange)
|
||||
{
|
||||
hbal->maxflowchange = ABS(dq);
|
||||
hbal->maxflownode = i;
|
||||
hbal->maxflowlink = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void newdemandflows(Project *pr, Hydbalance *hbal, double *qsum, double *dqsum)
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
@@ -546,13 +586,17 @@ void newdemandflows(Project *pr, Hydbalance *hbal, double *qsum, double *dqsum)
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
// Skip junctions with no positive demand
|
||||
if (hyd->NodeDemand[i] <= 0.0) continue;
|
||||
if (hyd->FullDemand[i] <= 0.0) continue;
|
||||
|
||||
// Find change in demand flow (see hydcoeffs.c)
|
||||
demandheadloss(pr, i, dp, n, &hloss, &hgrad);
|
||||
dh = hyd->NodeHead[i] - net->Node[i].El - hyd->Pmin;
|
||||
dq = (hloss - dh) / hgrad;
|
||||
dq *= hyd->RelaxFactor;
|
||||
|
||||
// Prevent a flow change greater than full demand
|
||||
if (fabs(dq) > 0.4 * hyd->FullDemand[i])
|
||||
dq = 0.4 * SGN(dq) * hyd->FullDemand[i];
|
||||
hyd->DemandFlow[i] -= dq;
|
||||
|
||||
// Update system flow summation
|
||||
@@ -637,11 +681,15 @@ int hasconverged(Project *pr, double *relerr, Hydbalance *hbal)
|
||||
if (hyd->FlowChangeLimit > 0.0 &&
|
||||
hbal->maxflowchange > hyd->FlowChangeLimit) return 0;
|
||||
|
||||
// Check for node leakage convergence
|
||||
if (hyd->HasLeakage && !leakagehasconverged(pr)) return 0;
|
||||
|
||||
// Check for pressure driven analysis convergence
|
||||
if (hyd->DemandModel == PDA) return pdaconverged(pr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int pdaconverged(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
@@ -654,33 +702,46 @@ int pdaconverged(Project *pr)
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
const double TOL = 0.001;
|
||||
const double QTOL = 0.0001; // 0.0001 cfs ~= 0.05 gpm ~= 0.2 lpm)
|
||||
int i, converged = 1;
|
||||
|
||||
double totalDemand = 0.0, totalReduction = 0.0;
|
||||
|
||||
double dp = hyd->Preq - hyd->Pmin;
|
||||
double p, q, r;
|
||||
|
||||
hyd->DeficientNodes = 0;
|
||||
hyd->DemandReduction = 0.0;
|
||||
|
||||
// Add up number of junctions with demand deficits
|
||||
|
||||
// Examine each network junction
|
||||
for (i = 1; i <= pr->network.Njuncs; i++)
|
||||
{
|
||||
// Skip nodes whose required demand is non-positive
|
||||
if (hyd->NodeDemand[i] <= 0.0) continue;
|
||||
if (hyd->FullDemand[i] <= 0.0) continue;
|
||||
|
||||
// Evaluate demand equation at current pressure solution
|
||||
p = hyd->NodeHead[i] - pr->network.Node[i].El;
|
||||
if (p <= hyd->Pmin)
|
||||
q = 0.0;
|
||||
else if (p >= hyd->Preq)
|
||||
q = hyd->FullDemand[i];
|
||||
else
|
||||
{
|
||||
r = (p - hyd->Pmin) / dp;
|
||||
q = hyd->FullDemand[i] * pow(r, hyd->Pexp);
|
||||
}
|
||||
|
||||
// Check for negative demand flow or positive demand flow at negative pressure
|
||||
if (hyd->DemandFlow[i] < -TOL) converged = 0;
|
||||
if (hyd->DemandFlow[i] > TOL &&
|
||||
hyd->NodeHead[i] - pr->network.Node[i].El - hyd->Pmin < -TOL)
|
||||
// Check if demand has not converged
|
||||
if (fabs(q - hyd->DemandFlow[i]) > QTOL)
|
||||
converged = 0;
|
||||
|
||||
// Accumulate total required demand and demand deficit
|
||||
if (hyd->DemandFlow[i] + 0.0001 < hyd->NodeDemand[i])
|
||||
|
||||
// Accumulate demand deficient node count and demand deficit
|
||||
if (hyd->DemandFlow[i] + QTOL < hyd->FullDemand[i])
|
||||
{
|
||||
hyd->DeficientNodes++;
|
||||
totalDemand += hyd->NodeDemand[i];
|
||||
totalReduction += hyd->NodeDemand[i] - hyd->DemandFlow[i];
|
||||
totalDemand += hyd->FullDemand[i];
|
||||
totalReduction += hyd->FullDemand[i] - hyd->DemandFlow[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (totalDemand > 0.0)
|
||||
hyd->DemandReduction = totalReduction / totalDemand * 100.0;
|
||||
return converged;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: hydstatus.c
|
||||
Description: updates hydraulic status of network elements
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 05/15/2019
|
||||
Last Updated: 02/03/2023
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,7 @@ static StatusType pumpstatus(Project *, int, double);
|
||||
static StatusType prvstatus(Project *, int, StatusType, double, double, double);
|
||||
static StatusType psvstatus(Project *, int, StatusType, double, double, double);
|
||||
static StatusType fcvstatus(Project *, int, StatusType, double, double);
|
||||
static void tankstatus(Project *, int, int, int);
|
||||
static void tankstatus(Project *, int, int, double);
|
||||
|
||||
|
||||
int valvestatus(Project *pr)
|
||||
@@ -155,10 +155,8 @@ int linkstatus(Project *pr)
|
||||
}
|
||||
|
||||
// Check for flow into (out of) full (empty) tanks
|
||||
if (n1 > net->Njuncs || n2 > net->Njuncs)
|
||||
{
|
||||
tankstatus(pr, k, n1, n2);
|
||||
}
|
||||
if (n1 > net->Njuncs) tankstatus(pr, k, n1, hyd->LinkFlow[k]);
|
||||
if (n2 > net->Njuncs) tankstatus(pr, k, n2, -hyd->LinkFlow[k]);
|
||||
|
||||
// Note any change in link status; do not revise link flow
|
||||
if (status != hyd->LinkStatus[k])
|
||||
@@ -224,6 +222,7 @@ StatusType pumpstatus(Project *pr, int k, double dh)
|
||||
{
|
||||
// Use huge value for constant HP pump
|
||||
hmax = BIG;
|
||||
if (hyd->LinkFlow[k] < TINY) return TEMPCLOSED;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -394,16 +393,25 @@ StatusType fcvstatus(Project *pr, int k, StatusType s, double h1, double h2)
|
||||
{
|
||||
status = ACTIVE;
|
||||
}
|
||||
|
||||
// Active valve's loss coeff. can't be < fully open loss coeff.
|
||||
else if (status == ACTIVE)
|
||||
{
|
||||
if ((h1 - h2) / SQR(hyd->LinkFlow[k]) < pr->network.Link[k].Km)
|
||||
{
|
||||
status = XFCV;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void tankstatus(Project *pr, int k, int n1, int n2)
|
||||
void tankstatus(Project *pr, int k, int n, double q)
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
** n1 = start node of link
|
||||
** n2 = end node of link
|
||||
** Input: k = link index
|
||||
** n = tank node index
|
||||
** q = link flow rate out of (+) or into (-) tank
|
||||
** Output: none
|
||||
** Purpose: closes link flowing into full or out of empty tank
|
||||
**----------------------------------------------------------------
|
||||
@@ -412,65 +420,23 @@ void tankstatus(Project *pr, int k, int n1, int n2)
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
int i, n;
|
||||
double h, q;
|
||||
int i;
|
||||
Stank *tank;
|
||||
Slink *link = &net->Link[k];
|
||||
|
||||
// Return if link is closed
|
||||
if (hyd->LinkStatus[k] <= CLOSED) return;
|
||||
|
||||
// Make node n1 be the tank, reversing flow (q) if need be
|
||||
q = hyd->LinkFlow[k];
|
||||
i = n1 - net->Njuncs;
|
||||
if (i <= 0)
|
||||
{
|
||||
i = n2 - net->Njuncs;
|
||||
if (i <= 0) return;
|
||||
n = n1;
|
||||
n1 = n2;
|
||||
n2 = n;
|
||||
q = -q;
|
||||
}
|
||||
|
||||
// Ignore reservoirs
|
||||
i = n - net->Njuncs;
|
||||
tank = &net->Tank[i];
|
||||
if (tank->A == 0.0) return;
|
||||
|
||||
// Find head difference across link
|
||||
h = hyd->NodeHead[n1] - hyd->NodeHead[n2];
|
||||
|
||||
// If tank is full, then prevent flow into it
|
||||
if (hyd->NodeHead[n1] >= tank->Hmax - hyd->Htol && !tank->CanOverflow)
|
||||
{
|
||||
// Case 1: Link is a pump discharging into tank
|
||||
if (link->Type == PUMP)
|
||||
{
|
||||
if (link->N2 == n1) hyd->LinkStatus[k] = TEMPCLOSED;
|
||||
}
|
||||
|
||||
// Case 2: Downstream head > tank head
|
||||
// (e.g., an open outflow check valve would close)
|
||||
else if (cvstatus(pr, OPEN, h, q) == CLOSED)
|
||||
{
|
||||
hyd->LinkStatus[k] = TEMPCLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
// If tank is empty, then prevent flow out of it
|
||||
if (hyd->NodeHead[n1] <= tank->Hmin + hyd->Htol)
|
||||
{
|
||||
// Case 1: Link is a pump discharging from tank
|
||||
if (link->Type == PUMP)
|
||||
{
|
||||
if (link->N1 == n1) hyd->LinkStatus[k] = TEMPCLOSED;
|
||||
}
|
||||
|
||||
// Case 2: Tank head > downstream head
|
||||
// (e.g., a closed outflow check valve would open)
|
||||
else if (cvstatus(pr, CLOSED, h, q) == OPEN)
|
||||
{
|
||||
hyd->LinkStatus[k] = TEMPCLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
// Can't add flow to a full tank
|
||||
if (hyd->NodeHead[n] >= tank->Hmax && !tank->CanOverflow && q < 0.0)
|
||||
hyd->LinkStatus[k] = TEMPCLOSED;
|
||||
|
||||
// Can't remove flow from an empty tank
|
||||
else if (hyd->NodeHead[n] <= tank->Hmin && q > 0.0)
|
||||
hyd->LinkStatus[k] = TEMPCLOSED;
|
||||
}
|
||||
|
||||
232
src/inpfile.c
232
src/inpfile.c
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: inpfile.c
|
||||
Description: saves network data to an EPANET formatted text file
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 10/29/2019
|
||||
Last Updated: 04/19/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -33,17 +33,18 @@ extern char *MixTxt[];
|
||||
extern char *TstatTxt[];
|
||||
extern char *RptFlagTxt[];
|
||||
extern char *SectTxt[];
|
||||
extern char *BackflowTxt[];
|
||||
extern char *CurveTypeTxt[];
|
||||
|
||||
void saveauxdata(Project *pr, FILE *f)
|
||||
/*
|
||||
------------------------------------------------------------
|
||||
Writes auxilary data from original input file to new file.
|
||||
Writes auxiliary data from original input file to new file.
|
||||
------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int sect, newsect;
|
||||
char *tok;
|
||||
char write;
|
||||
char line[MAXLINE + 1];
|
||||
char s[MAXLINE + 1];
|
||||
FILE *InFile = pr->parser.InFile;
|
||||
@@ -78,31 +79,23 @@ void saveauxdata(Project *pr, FILE *f)
|
||||
{
|
||||
case _LABELS:
|
||||
case _BACKDROP:
|
||||
case _TAGS:
|
||||
fprintf(f, "\n%s", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write line of auxilary data to file
|
||||
// Write line of auxiliary data to file
|
||||
else
|
||||
{
|
||||
write = FALSE;
|
||||
switch (sect)
|
||||
{
|
||||
case _TAGS:
|
||||
if (*tok == ';' ||
|
||||
(match("NODE", tok) && findnode(&pr->network, strtok(NULL, SEPSTR))) ||
|
||||
(match("LINK", tok) && findlink(&pr->network, strtok(NULL, SEPSTR))))
|
||||
write = TRUE;
|
||||
break;
|
||||
case _LABELS:
|
||||
case _BACKDROP:
|
||||
write = TRUE; break;
|
||||
fprintf(f, "%s", line);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (write) fprintf(f, "%s", line);
|
||||
}
|
||||
}
|
||||
fclose(InFile);
|
||||
@@ -151,40 +144,46 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
// (Leave demands for [DEMANDS] section)
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_JUNCTIONS);
|
||||
fprintf(f, "\n;;%-31s\t%-12s\t%-12s\t%-31s",
|
||||
"ID", "Elev", "Demand", "Pattern");
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
node = &net->Node[i];
|
||||
fprintf(f, "\n %-31s %12.4f", node->ID, node->El * pr->Ucf[ELEV]);
|
||||
if (node->Comment) fprintf(f, " ;%s", node->Comment);
|
||||
fprintf(f, "\n %-31s\t%-12.4f", node->ID, node->El * pr->Ucf[ELEV]);
|
||||
if (node->Comment) fprintf(f, "\t;%s", node->Comment);
|
||||
}
|
||||
|
||||
// Write [RESERVOIRS] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_RESERVOIRS);
|
||||
fprintf(f, "\n;;%-31s\t%-12s\t%-31s",
|
||||
"ID", "Head", "Pattern");
|
||||
for (i = 1; i <= net->Ntanks; i++)
|
||||
{
|
||||
tank = &net->Tank[i];
|
||||
if (tank->A == 0.0)
|
||||
{
|
||||
node = &net->Node[tank->Node];
|
||||
sprintf(s, " %-31s %12.4f", node->ID, node->El * pr->Ucf[ELEV]);
|
||||
if ((j = tank->Pat) > 0) sprintf(s1, " %s", net->Pattern[j].ID);
|
||||
sprintf(s, " %-31s\t%-12.4f", node->ID, node->El * pr->Ucf[ELEV]);
|
||||
if ((j = tank->Pat) > 0) sprintf(s1, "%s", net->Pattern[j].ID);
|
||||
else strcpy(s1, " ");
|
||||
fprintf(f, "\n%s %-31s", s, s1);
|
||||
if (node->Comment) fprintf(f, " ;%s", node->Comment);
|
||||
fprintf(f, "\n%s\t%-31s", s, s1);
|
||||
if (node->Comment) fprintf(f, "\t;%s", node->Comment);
|
||||
}
|
||||
}
|
||||
|
||||
// Write [TANKS] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_TANKS);
|
||||
fprintf(f, "\n;;%-31s\t%-12s\t%-12s\t%-12s\t%-12s\t%-12s\t%-12s\t%-31s\t%-12s",
|
||||
"ID", "Elevation", "InitLevel", "MinLevel", "MaxLevel", "Diameter", "MinVol", "VolCurve", "Overflow");
|
||||
for (i = 1; i <= net->Ntanks; i++)
|
||||
{
|
||||
tank = &net->Tank[i];
|
||||
if (tank->A > 0.0)
|
||||
{
|
||||
node = &net->Node[tank->Node];
|
||||
sprintf(s, " %-31s %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f",
|
||||
sprintf(s, " %-31s\t%-12.4f\t%-12.4f\t%-12.4f\t%-12.4f\t%-12.4f\t%-12.4f",
|
||||
node->ID, node->El * pr->Ucf[ELEV],
|
||||
(tank->H0 - node->El) * pr->Ucf[ELEV],
|
||||
(tank->Hmin - node->El) * pr->Ucf[ELEV],
|
||||
@@ -194,55 +193,59 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
if ((j = tank->Vcurve) > 0) sprintf(s1, "%s", net->Curve[j].ID);
|
||||
else if (tank->CanOverflow) strcpy(s1, "*");
|
||||
else strcpy(s1, " ");
|
||||
fprintf(f, "\n%s %-31s", s, s1);
|
||||
if (tank->CanOverflow) fprintf(f, " YES ");
|
||||
if (node->Comment) fprintf(f, " ;%s", node->Comment);
|
||||
fprintf(f, "\n%s\t%-31s", s, s1);
|
||||
if (tank->CanOverflow) fprintf(f, "\t%-12s", "YES");
|
||||
if (node->Comment) fprintf(f, "\t;%s", node->Comment);
|
||||
}
|
||||
}
|
||||
|
||||
// Write [PIPES] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_PIPES);
|
||||
fprintf(f, "\n;;%-31s\t%-31s\t%-31s\t%-12s\t%-12s\t%-12s\t%-12s\t%-6s",
|
||||
"ID", "Node1", "Node2", "Length", "Diameter", "Roughness", "MinorLoss", "Status");
|
||||
for (i = 1; i <= net->Nlinks; i++)
|
||||
{
|
||||
link = &net->Link[i];
|
||||
if (link->Type <= PIPE)
|
||||
{
|
||||
d = link->Diam;
|
||||
kc = link->Kc;
|
||||
kc = link->InitSetting;
|
||||
if (hyd->Formflag == DW) kc = kc * pr->Ucf[ELEV] * 1000.0;
|
||||
km = link->Km * SQR(d) * SQR(d) / 0.02517;
|
||||
|
||||
sprintf(s, " %-31s %-31s %-31s %12.4f %12.4f %12.4f %12.4f",
|
||||
sprintf(s, " %-31s\t%-31s\t%-31s\t%-12.4f\t%-12.4f\t%-12.4f\t%-12.4f",
|
||||
link->ID, net->Node[link->N1].ID, net->Node[link->N2].ID,
|
||||
link->Len * pr->Ucf[LENGTH], d * pr->Ucf[DIAM], kc, km);
|
||||
|
||||
if (link->Type == CVPIPE) sprintf(s2, "CV");
|
||||
else if (link->Status == CLOSED) sprintf(s2, "CLOSED");
|
||||
else if (link->InitStatus == CLOSED) sprintf(s2, "CLOSED");
|
||||
else strcpy(s2, " ");
|
||||
fprintf(f, "\n%s %-6s", s, s2);
|
||||
if (link->Comment) fprintf(f, " ;%s", link->Comment);
|
||||
fprintf(f, "\n%s\t%-6s", s, s2);
|
||||
if (link->Comment) fprintf(f, "\t;%s", link->Comment);
|
||||
}
|
||||
}
|
||||
|
||||
// Write [PUMPS] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_PUMPS);
|
||||
fprintf(f, "\n;;%-31s\t%-31s\t%-31s\t%-12s",
|
||||
"ID", "Node1", "Node2", "Parameters");
|
||||
for (i = 1; i <= net->Npumps; i++)
|
||||
{
|
||||
n = net->Pump[i].Link;
|
||||
link = &net->Link[n];
|
||||
pump = &net->Pump[i];
|
||||
sprintf(s, " %-31s %-31s %-31s", link->ID, net->Node[link->N1].ID,
|
||||
sprintf(s, " %-31s\t%-31s\t%-31s", link->ID, net->Node[link->N1].ID,
|
||||
net->Node[link->N2].ID);
|
||||
|
||||
// Pump has constant power
|
||||
if (pump->Ptype == CONST_HP) sprintf(s1, " POWER %.4f", link->Km);
|
||||
if (pump->Ptype == CONST_HP) sprintf(s1, "\tPOWER %.4f", link->Km);
|
||||
|
||||
// Pump has a head curve
|
||||
else if ((j = pump->Hcurve) > 0)
|
||||
{
|
||||
sprintf(s1, " HEAD %s", net->Curve[j].ID);
|
||||
sprintf(s1, "\tHEAD %s", net->Curve[j].ID);
|
||||
}
|
||||
|
||||
// Old format used for pump curve
|
||||
@@ -259,25 +262,26 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
// Optional speed pattern
|
||||
if ((j = pump->Upat) > 0)
|
||||
{
|
||||
sprintf(s1, " PATTERN %s", net->Pattern[j].ID);
|
||||
sprintf(s1, "\tPATTERN %s", net->Pattern[j].ID);
|
||||
strcat(s, s1);
|
||||
}
|
||||
|
||||
// Optional speed setting
|
||||
if (link->Kc != 1.0)
|
||||
if (link->InitSetting != 1.0)
|
||||
{
|
||||
sprintf(s1, " SPEED %.4f", link->Kc);
|
||||
sprintf(s1, "\tSPEED %.4f", link->InitSetting);
|
||||
strcat(s, s1);
|
||||
}
|
||||
|
||||
fprintf(f, "\n%s", s);
|
||||
if (link->Comment) fprintf(f, " ;%s", link->Comment);
|
||||
|
||||
if (link->Comment) fprintf(f, "\t;%s", link->Comment);
|
||||
}
|
||||
|
||||
// Write [VALVES] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_VALVES);
|
||||
fprintf(f, "\n;;%-31s\t%-31s\t%-31s\t%-12s\t%-6s\t%-12s\t%-12s",
|
||||
"ID", "Node1", "Node2", "Diameter", "Type", "Setting", "MinorLoss");
|
||||
for (i = 1; i <= net->Nvalves; i++)
|
||||
{
|
||||
n = net->Valve[i].Link;
|
||||
@@ -285,8 +289,7 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
d = link->Diam;
|
||||
|
||||
// Valve setting
|
||||
kc = link->Kc;
|
||||
if (kc == MISSING) kc = 0.0;
|
||||
kc = link->InitSetting;
|
||||
switch (link->Type)
|
||||
{
|
||||
case FCV:
|
||||
@@ -302,36 +305,44 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
}
|
||||
km = link->Km * SQR(d) * SQR(d) / 0.02517;
|
||||
|
||||
sprintf(s, " %-31s %-31s %-31s %12.4f %5s",
|
||||
sprintf(s, " %-31s\t%-31s\t%-31s\t%-12.4f\t%-6s",
|
||||
link->ID, net->Node[link->N1].ID,
|
||||
net->Node[link->N2].ID, d * pr->Ucf[DIAM],
|
||||
LinkTxt[link->Type]);
|
||||
|
||||
// For GPV, setting = head curve index
|
||||
if (link->Type == GPV && (j = ROUND(link->Kc)) > 0)
|
||||
if (link->Type == GPV && (j = ROUND(kc)) > 0)
|
||||
{
|
||||
sprintf(s1, "%-31s %12.4f", net->Curve[j].ID, km);
|
||||
sprintf(s1, "%-31s\t%-12.4f", net->Curve[j].ID, km);
|
||||
}
|
||||
else sprintf(s1, "%12.4f %12.4f", kc, km);
|
||||
fprintf(f, "\n%s %s", s, s1);
|
||||
if (link->Comment) fprintf(f, " ;%s", link->Comment);
|
||||
// For PCV add loss curve if present
|
||||
else if (link->Type == PCV && (j = net->Valve[i].Curve) > 0)
|
||||
{
|
||||
sprintf(s1, "%-12.4f\t%-12.4f\t%-31s", kc, km, net->Curve[j].ID);
|
||||
}
|
||||
else sprintf(s1, "%-12.4f\t%-12.4f", kc, km);
|
||||
fprintf(f, "\n%s\t%s", s, s1);
|
||||
if (link->Comment) fprintf(f, "\t;%s", link->Comment);
|
||||
}
|
||||
|
||||
|
||||
// Write [DEMANDS] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_DEMANDS);
|
||||
fprintf(f, "\n;;%-31s\t%-14s\t%-31s\t%-31s",
|
||||
"Junction", "Demand", "Pattern", "Category");
|
||||
ucf = pr->Ucf[DEMAND];
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
node = &net->Node[i];
|
||||
for (demand = node->D; demand != NULL; demand = demand->next)
|
||||
{
|
||||
sprintf(s, " %-31s %14.6f", node->ID, ucf * demand->Base);
|
||||
if ((j = demand->Pat) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID);
|
||||
if (demand->Base == 0.0) continue;
|
||||
sprintf(s, " %-31s\t%-14.6f", node->ID, ucf * demand->Base);
|
||||
if ((j = demand->Pat) > 0) sprintf(s1, "%-31s", net->Pattern[j].ID);
|
||||
else strcpy(s1, " ");
|
||||
fprintf(f, "\n%s %-31s", s, s1);
|
||||
if (demand->Name) fprintf(f, " ;%s", demand->Name);
|
||||
fprintf(f, "\n%s\t%-31s", s, s1);
|
||||
if (demand->Name) fprintf(f, "\t;%s", demand->Name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,25 +350,42 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
// Write [EMITTERS] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_EMITTERS);
|
||||
fprintf(f, "\n;;%-31s\t%-14s",
|
||||
"Junction", "Coefficient");
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
node = &net->Node[i];
|
||||
if (node->Ke == 0.0) continue;
|
||||
ke = pr->Ucf[FLOW] / pow(pr->Ucf[PRESSURE] * node->Ke, (1.0 / hyd->Qexp));
|
||||
fprintf(f, "\n %-31s %14.6f", node->ID, ke);
|
||||
fprintf(f, "\n %-31s\t%-14.6f", node->ID, ke);
|
||||
}
|
||||
|
||||
// Write [LEAKAGE] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_LEAKAGE);
|
||||
fprintf(f, "\n;;%-31s\t%-14s\t%-14s",
|
||||
"Pipe", "Leak Area", "Leak Expansion");
|
||||
for (i = 1; i <= net->Nlinks; i++)
|
||||
{
|
||||
link = &net->Link[i];
|
||||
if (link->LeakArea == 0.0 && link->LeakExpan == 0.0) continue;
|
||||
fprintf(f, "\n %-31s %14.6f %14.6f", link->ID,
|
||||
link->LeakArea * pr->Ucf[LENGTH], link->LeakExpan * pr->Ucf[LENGTH]);
|
||||
}
|
||||
|
||||
// Write [STATUS] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_STATUS);
|
||||
fprintf(f, "\n;;%-31s\t%-12s",
|
||||
"ID", "Status/Setting");
|
||||
for (i = 1; i <= net->Nlinks; i++)
|
||||
{
|
||||
link = &net->Link[i];
|
||||
if (link->Type <= PUMP)
|
||||
{
|
||||
if (link->Status == CLOSED)
|
||||
if (link->InitStatus == CLOSED)
|
||||
{
|
||||
fprintf(f, "\n %-31s %s", link->ID, StatTxt[CLOSED]);
|
||||
fprintf(f, "\n %-31s\t%s", link->ID, StatTxt[CLOSED]);
|
||||
}
|
||||
|
||||
// Write pump speed here for pumps with old-style pump curve input
|
||||
@@ -366,23 +394,23 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
n = findpump(net, i);
|
||||
pump = &net->Pump[n];
|
||||
if (pump->Hcurve == 0 && pump->Ptype != CONST_HP &&
|
||||
link->Kc != 1.0)
|
||||
link->InitSetting != 1.0)
|
||||
{
|
||||
fprintf(f, "\n %-31s %-.4f", link->ID, link->Kc);
|
||||
fprintf(f, "\n %-31s\t%-.4f", link->ID, link->InitSetting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write fixed-status PRVs & PSVs (setting = MISSING)
|
||||
else if (link->Kc == MISSING)
|
||||
// Write fixed-status valves
|
||||
else
|
||||
{
|
||||
if (link->Status == OPEN)
|
||||
if (link->InitStatus == OPEN)
|
||||
{
|
||||
fprintf(f, "\n %-31s %s", link->ID, StatTxt[OPEN]);
|
||||
fprintf(f, "\n %-31s\t%s", link->ID, StatTxt[OPEN]);
|
||||
}
|
||||
if (link->Status == CLOSED)
|
||||
if (link->InitStatus == CLOSED)
|
||||
{
|
||||
fprintf(f, "\n%-31s %s", link->ID, StatTxt[CLOSED]);
|
||||
fprintf(f, "\n%-31s\t%s", link->ID, StatTxt[CLOSED]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,26 +419,35 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
// (Use 6 pattern factors per line)
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_PATTERNS);
|
||||
fprintf(f, "\n;;%-31s\t%-12s",
|
||||
"ID", "Multipliers");
|
||||
for (i = 1; i <= net->Npats; i++)
|
||||
{
|
||||
if (net->Pattern[i].Comment) fprintf(f, "\n;%s", net->Pattern[i].Comment);
|
||||
for (j = 0; j < net->Pattern[i].Length; j++)
|
||||
{
|
||||
if (j % 6 == 0) fprintf(f, "\n %-31s", net->Pattern[i].ID);
|
||||
fprintf(f, " %12.4f", net->Pattern[i].F[j]);
|
||||
fprintf(f, "\t%-12.4f", net->Pattern[i].F[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// Write [CURVES] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_CURVES);
|
||||
fprintf(f, "\n;;%-31s\t%-12s\t%-12s", "ID", "X-Value", "Y-Value");
|
||||
for (i = 1; i <= net->Ncurves; i++)
|
||||
{
|
||||
if (net->Curve[i].Comment) fprintf(f, "\n;%s", net->Curve[i].Comment);
|
||||
for (j = 0; j < net->Curve[i].Npts; j++)
|
||||
curve = &net->Curve[i];
|
||||
if (curve->Comment) fprintf(f, "\n;%s", curve->Comment);
|
||||
if (curve->Npts > 0)
|
||||
{
|
||||
curve = &net->Curve[i];
|
||||
fprintf(f, "\n %-31s %12.4f %12.4f", curve->ID, curve->X[j], curve->Y[j]);
|
||||
fprintf(f, "\n %-31s\t%-12.4f\t%-12.4f\t%s", curve->ID,
|
||||
curve->X[0], curve->Y[0], CurveTypeTxt[curve->Type]);
|
||||
for (j = 1; j < curve->Npts; j++)
|
||||
{
|
||||
fprintf(f, "\n %-31s\t%-12.4f\t%-12.4f", curve->ID,
|
||||
curve->X[j], curve->Y[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,7 +462,12 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
link = &net->Link[j];
|
||||
|
||||
// Get text of control's link status/setting
|
||||
if (control->Setting == MISSING)
|
||||
if (control->Setting == MISSING || link->Type == GPV || link->Type == PIPE)
|
||||
{
|
||||
sprintf(s, " LINK %s %s ", link->ID, StatTxt[control->Status]);
|
||||
}
|
||||
else if (link->Type == PUMP &&
|
||||
(control->Setting == 0.0 || control->Setting == 1.0))
|
||||
{
|
||||
sprintf(s, " LINK %s %s ", link->ID, StatTxt[control->Status]);
|
||||
}
|
||||
@@ -473,7 +515,10 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
fprintf(f, "\n%s AT %s %s", s, ControlTxt[TIMEOFDAY],
|
||||
clocktime(rpt->Atime, control->Time));
|
||||
break;
|
||||
|
||||
default: continue;
|
||||
}
|
||||
if (control->isEnabled == FALSE) fprintf(f, " DISABLED");
|
||||
}
|
||||
|
||||
// Write [RULES] section
|
||||
@@ -483,6 +528,7 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
{
|
||||
fprintf(f, "\nRULE %s", pr->network.Rule[i].label);
|
||||
writerule(pr, f, i); // see RULES.C
|
||||
if (pr->network.Rule[i].isEnabled == FALSE) fprintf(f, "\nDISABLED");
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
@@ -490,40 +536,43 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
// (Skip nodes with default quality of 0)
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_QUALITY);
|
||||
fprintf(f, "\n;;%-31s\t%-14s", "ID", "InitQual");
|
||||
for (i = 1; i <= net->Nnodes; i++)
|
||||
{
|
||||
node = &net->Node[i];
|
||||
if (node->C0 == 0.0) continue;
|
||||
fprintf(f, "\n %-31s %14.6f", node->ID, node->C0 * pr->Ucf[QUALITY]);
|
||||
fprintf(f, "\n %-31s\t%-14.6f", node->ID, node->C0 * pr->Ucf[QUALITY]);
|
||||
}
|
||||
|
||||
// Write [SOURCES] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_SOURCES);
|
||||
fprintf(f, "\n;;%-31s\t%-9s\t%-14s\t%-31s", "ID", "Type", "Quality", "Pattern");
|
||||
for (i = 1; i <= net->Nnodes; i++)
|
||||
{
|
||||
node = &net->Node[i];
|
||||
source = node->S;
|
||||
if (source == NULL) continue;
|
||||
sprintf(s, " %-31s %-8s %14.6f", node->ID, SourceTxt[source->Type],
|
||||
sprintf(s, " %-31s\t%-9s\t%-14.6f", node->ID, SourceTxt[source->Type],
|
||||
source->C0);
|
||||
if ((j = source->Pat) > 0)
|
||||
{
|
||||
sprintf(s1, "%s", net->Pattern[j].ID);
|
||||
}
|
||||
else strcpy(s1, "");
|
||||
fprintf(f, "\n%s %s", s, s1);
|
||||
fprintf(f, "\n%s\t%s", s, s1);
|
||||
}
|
||||
|
||||
// Write [MIXING] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_MIXING);
|
||||
fprintf(f, "\n;;%-31s\t%-8s", "ID", "Model");
|
||||
for (i = 1; i <= net->Ntanks; i++)
|
||||
{
|
||||
tank = &net->Tank[i];
|
||||
if (tank->A == 0.0) continue;
|
||||
fprintf(f, "\n %-31s %-8s %12.4f", net->Node[tank->Node].ID,
|
||||
MixTxt[tank->MixModel], (tank->V1max / tank->Vmax));
|
||||
fprintf(f, "\n %-31s\t%-8s\t%12.4f", net->Node[tank->Node].ID,
|
||||
MixTxt[tank->MixModel], tank->V1frac);
|
||||
}
|
||||
|
||||
// Write [REACTIONS] section
|
||||
@@ -546,6 +595,10 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
fprintf(f, "\n ROUGHNESS CORRELATION %-.6f", qual->Rfactor);
|
||||
}
|
||||
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_REACTIONS);
|
||||
fprintf(f, "\n;%-9s\t%-31s\t%-12s", "Type", "Pipe/Tank", "Coefficient");
|
||||
|
||||
// Pipe-specific parameters
|
||||
for (i = 1; i <= net->Nlinks; i++)
|
||||
{
|
||||
@@ -553,11 +606,11 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
if (link->Type > PIPE) continue;
|
||||
if (link->Kb != qual->Kbulk)
|
||||
{
|
||||
fprintf(f, "\n BULK %-31s %-.6f", link->ID, link->Kb * SECperDAY);
|
||||
fprintf(f, "\n %-9s\t%-31s\t%-.6f", "BULK", link->ID, link->Kb * SECperDAY);
|
||||
}
|
||||
if (link->Kw != qual->Kwall)
|
||||
{
|
||||
fprintf(f, "\n WALL %-31s %-.6f", link->ID, link->Kw * SECperDAY);
|
||||
fprintf(f, "\n %-9s\t%-31s\t%-.6f", "WALL", link->ID, link->Kw * SECperDAY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,7 +621,7 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
if (tank->A == 0.0) continue;
|
||||
if (tank->Kb != qual->Kbulk)
|
||||
{
|
||||
fprintf(f, "\n TANK %-31s %-.6f", net->Node[tank->Node].ID,
|
||||
fprintf(f, "\n %-9s\t%-31s\t%-.6f", "TANK", net->Node[tank->Node].ID,
|
||||
tank->Kb * SECperDAY);
|
||||
}
|
||||
}
|
||||
@@ -666,8 +719,11 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
break;
|
||||
}
|
||||
|
||||
if (hyd->DefPat > 0)
|
||||
fprintf(f, "\n PATTERN %s", net->Pattern[hyd->DefPat].ID);
|
||||
fprintf(f, "\n DEMAND MULTIPLIER %-.4f", hyd->Dmult);
|
||||
fprintf(f, "\n EMITTER EXPONENT %-.4f", 1.0 / hyd->Qexp);
|
||||
fprintf(f, "\n BACKFLOW ALLOWED %s", BackflowTxt[hyd->EmitBackFlag]);
|
||||
fprintf(f, "\n VISCOSITY %-.6f", hyd->Viscos / VISCOS);
|
||||
fprintf(f, "\n DIFFUSIVITY %-.6f", qual->Diffus / DIFFUS);
|
||||
fprintf(f, "\n SPECIFIC GRAVITY %-.6f", hyd->SpGrav);
|
||||
@@ -774,32 +830,50 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
}
|
||||
else fprintf(f, "\n %-20sNO",field->Name);
|
||||
}
|
||||
|
||||
|
||||
// Write [TAGS] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_TAGS);
|
||||
fprintf(f, "\n;;%-8s\t%-31s\t%s", "Object", "ID", "Tag");
|
||||
for (i = 1; i <= net->Nnodes; i++)
|
||||
{
|
||||
node = &net->Node[i];
|
||||
if (node->Tag == NULL || strlen(node->Tag) == 0) continue;
|
||||
fprintf(f, "\n %-8s\t%-31s\t%s", "NODE", node->ID, node->Tag);
|
||||
}
|
||||
for (i = 1; i <= net->Nlinks; i++)
|
||||
{
|
||||
link = &net->Link[i];
|
||||
if (link->Tag == NULL || strlen(link->Tag) == 0) continue;
|
||||
fprintf(f, "\n %-8s\t%-31s\t%s", "LINK", link->ID, link->Tag);
|
||||
}
|
||||
// Write [COORDINATES] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_COORDS);
|
||||
fprintf(f, "\n;;%-31s\t%-14s\t%-14s", "ID", "X-Coord", "Y-Coord");
|
||||
for (i = 1; i <= net->Nnodes; i++)
|
||||
{
|
||||
node = &net->Node[i];
|
||||
if (node->X == MISSING || node->Y == MISSING) continue;
|
||||
fprintf(f, "\n %-31s %14.6f %14.6f", node->ID, node->X, node->Y);
|
||||
fprintf(f, "\n %-31s\t%-14.6f\t%-14.6f", node->ID, node->X, node->Y);
|
||||
}
|
||||
|
||||
// Write [VERTICES] section
|
||||
fprintf(f, "\n\n");
|
||||
fprintf(f, s_VERTICES);
|
||||
fprintf(f, "\n;;%-31s\t%-14s\t%-14s", "ID", "X-Coord", "Y-Coord");
|
||||
for (i = 1; i <= net->Nlinks; i++)
|
||||
{
|
||||
link = &net->Link[i];
|
||||
if (link->Vertices != NULL)
|
||||
{
|
||||
for (j = 0; j < link->Vertices->Npts; j++)
|
||||
fprintf(f, "\n %-31s %14.6f %14.6f",
|
||||
fprintf(f, "\n %-31s\t%-14.6f\t%-14.6f",
|
||||
link->ID, link->Vertices->X[j], link->Vertices->Y[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// Save auxilary data to new input file
|
||||
// Save auxiliary data to new input file
|
||||
fprintf(f, "\n");
|
||||
saveauxdata(pr, f);
|
||||
|
||||
|
||||
153
src/input1.c
153
src/input1.c
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: input1.c
|
||||
Description: retrieves network data from an EPANET input file
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 07/08/2019
|
||||
Last Updated: 04/19/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -40,6 +40,9 @@ Last Updated: 07/08/2019
|
||||
// Defined in ENUMSTXT.H
|
||||
extern char *Fldname[];
|
||||
extern char *RptFlowUnitsTxt[];
|
||||
extern char *PressUnitsTxt[];
|
||||
extern void reindextanks(Project *pr);
|
||||
|
||||
|
||||
int getdata(Project *pr)
|
||||
/*
|
||||
@@ -58,13 +61,18 @@ int getdata(Project *pr)
|
||||
|
||||
// Read in network data
|
||||
rewind(pr->parser.InFile);
|
||||
ERRCODE(readdata(pr));
|
||||
|
||||
errcode = readdata(pr);
|
||||
|
||||
// Adjust data and convert it to internal units
|
||||
if (!errcode) adjustdata(pr);
|
||||
if (!errcode) initunits(pr);
|
||||
ERRCODE(inittanks(pr));
|
||||
if (!errcode) convertunits(pr);
|
||||
// (error code 200 means there are non-fatal errors in input file)
|
||||
if (errcode == 0 || errcode == 200)
|
||||
{
|
||||
reindextanks(pr);
|
||||
adjustdata(pr);
|
||||
inittanks(pr);
|
||||
initunits(pr);
|
||||
convertunits(pr);
|
||||
}
|
||||
return errcode;
|
||||
}
|
||||
|
||||
@@ -96,8 +104,7 @@ void setdefaults(Project *pr)
|
||||
pr->Warnflag = FALSE; // Warning flag is off
|
||||
parser->Unitsflag = US; // US unit system
|
||||
parser->Flowflag = GPM; // Flow units are gpm
|
||||
parser->Pressflag = PSI; // Pressure units are psi
|
||||
parser->DefPat = 0; // Default demand pattern index
|
||||
parser->Pressflag = DEFAULTUNIT; // Pressure units set based on unit system
|
||||
out->Hydflag = SCRATCH; // No external hydraulics file
|
||||
rpt->Tstatflag = SERIES; // Generate time series output
|
||||
|
||||
@@ -121,6 +128,8 @@ void setdefaults(Project *pr)
|
||||
hyd->Epump = EPUMP; // Default pump efficiency
|
||||
hyd->Emax = 0.0; // Zero peak energy usage
|
||||
hyd->Qexp = 2.0; // Flow exponent for emitters
|
||||
hyd->EmitBackFlag = 1; // Allow emitter backflow
|
||||
hyd->DefPat = 0; // Default demand pattern index
|
||||
hyd->Dmult = 1.0; // Demand multiplier
|
||||
hyd->RQtol = RQTOL; // Default hydraulics parameters
|
||||
hyd->CheckFreq = CHECKFREQ;
|
||||
@@ -212,9 +221,7 @@ void adjustdata(Project *pr)
|
||||
|
||||
int i;
|
||||
double ucf; // Unit conversion factor
|
||||
Pdemand demand; // Pointer to demand record
|
||||
Slink *link;
|
||||
Snode *node;
|
||||
Stank *tank;
|
||||
|
||||
// Use 1 hr pattern & report time step if none specified
|
||||
@@ -229,9 +236,6 @@ void adjustdata(Project *pr)
|
||||
// Report start time cannot be greater than simulation duration
|
||||
if (time->Rstart > time->Dur) time->Rstart = 0;
|
||||
|
||||
// No water quality analysis for single period run
|
||||
if (time->Dur == 0) qual->Qualflag = NONE;
|
||||
|
||||
// If no quality timestep, then make it 1/10 of hydraulic timestep
|
||||
if (time->Qstep == 0) time->Qstep = time->Hstep / 10;
|
||||
|
||||
@@ -258,6 +262,7 @@ void adjustdata(Project *pr)
|
||||
case MLD: // megaliters/day
|
||||
case CMH: // cubic meters/hr
|
||||
case CMD: // cubic meters/day
|
||||
case CMS: // cubic meters/second
|
||||
parser->Unitsflag = SI;
|
||||
break;
|
||||
default:
|
||||
@@ -265,8 +270,11 @@ void adjustdata(Project *pr)
|
||||
}
|
||||
|
||||
// Revise pressure units depending on flow units
|
||||
if (parser->Unitsflag != SI) parser->Pressflag = PSI;
|
||||
else if (parser->Pressflag == PSI) parser->Pressflag = METERS;
|
||||
if (parser->Pressflag == DEFAULTUNIT)
|
||||
{
|
||||
if (parser->Unitsflag == SI) parser->Pressflag = METERS;
|
||||
else parser->Pressflag = PSI;
|
||||
}
|
||||
|
||||
// Store value of viscosity & diffusivity
|
||||
ucf = 1.0;
|
||||
@@ -322,26 +330,20 @@ void adjustdata(Project *pr)
|
||||
if (tank->Kb == MISSING) tank->Kb = qual->Kbulk;
|
||||
}
|
||||
|
||||
// Use default pattern if none assigned to a demand
|
||||
parser->DefPat = findpattern(net, parser->DefPatID);
|
||||
if (parser->DefPat > 0) for (i = 1; i <= net->Nnodes; i++)
|
||||
{
|
||||
node = &net->Node[i];
|
||||
for (demand = node->D; demand != NULL; demand = demand->next)
|
||||
{
|
||||
if (demand->Pat == 0) demand->Pat = parser->DefPat;
|
||||
}
|
||||
}
|
||||
// Set default pattern index
|
||||
i = findpattern(net, parser->DefPatID);
|
||||
if (i > 0)
|
||||
hyd->DefPat = i;
|
||||
|
||||
// Remove QUALITY as a reporting variable if no WQ analysis
|
||||
if (qual->Qualflag == NONE) rpt->Field[QUALITY].Enabled = FALSE;
|
||||
}
|
||||
|
||||
int inittanks(Project *pr)
|
||||
void inittanks(Project *pr)
|
||||
/*
|
||||
**---------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Output: none
|
||||
** Purpose: initializes volumes in non-cylindrical tanks
|
||||
**---------------------------------------------------------------
|
||||
*/
|
||||
@@ -350,7 +352,7 @@ int inittanks(Project *pr)
|
||||
|
||||
int i, j, n = 0;
|
||||
double a;
|
||||
int errcode = 0, levelerr;
|
||||
int errcode = 0;
|
||||
char errmsg[MAXMSG+1] = "";
|
||||
Stank *tank;
|
||||
Scurve *curve;
|
||||
@@ -360,47 +362,23 @@ int inittanks(Project *pr)
|
||||
tank = &net->Tank[j];
|
||||
if (tank->A == 0.0) continue; // Skip reservoirs
|
||||
|
||||
// Check for valid lower/upper tank levels
|
||||
levelerr = 0;
|
||||
if (tank->H0 > tank->Hmax ||
|
||||
tank->Hmin > tank->Hmax ||
|
||||
tank->H0 < tank->Hmin
|
||||
) levelerr = 1;
|
||||
|
||||
// Check that tank heights are within volume curve
|
||||
// See if tank has a volume curve
|
||||
i = tank->Vcurve;
|
||||
if (i > 0)
|
||||
{
|
||||
curve = &net->Curve[i];
|
||||
n = curve->Npts - 1;
|
||||
if (tank->Hmin < curve->X[0] || tank->Hmax > curve->X[n])
|
||||
{
|
||||
levelerr = 1;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Find min., max., and initial volumes from curve
|
||||
tank->Vmin = interp(curve->Npts, curve->X, curve->Y, tank->Hmin);
|
||||
tank->Vmax = interp(curve->Npts, curve->X, curve->Y, tank->Hmax);
|
||||
tank->V0 = interp(curve->Npts, curve->X, curve->Y, tank->H0);
|
||||
// Find min., max., and initial volumes from curve
|
||||
tank->Vmin = interp(curve->Npts, curve->X, curve->Y, tank->Hmin);
|
||||
tank->Vmax = interp(curve->Npts, curve->X, curve->Y, tank->Hmax);
|
||||
tank->V0 = interp(curve->Npts, curve->X, curve->Y, tank->H0);
|
||||
|
||||
// Find a "nominal" diameter for tank
|
||||
a = (curve->Y[n] - curve->Y[0]) / (curve->X[n] - curve->X[0]);
|
||||
tank->A = sqrt(4.0 * a / PI);
|
||||
}
|
||||
}
|
||||
|
||||
// Report error in levels if found
|
||||
if (levelerr)
|
||||
{
|
||||
sprintf(pr->Msg, "Error 225: %s node %s", geterrmsg(225, errmsg),
|
||||
net->Node[tank->Node].ID);
|
||||
writeline(pr, pr->Msg);
|
||||
errcode = 200;
|
||||
// Find a "nominal" diameter for tank
|
||||
a = (curve->Y[n] - curve->Y[0]) / (curve->X[n] - curve->X[0]);
|
||||
tank->A = sqrt(4.0 * a / PI);
|
||||
}
|
||||
}
|
||||
return errcode;
|
||||
}
|
||||
|
||||
void initunits(Project *pr)
|
||||
@@ -430,8 +408,6 @@ void initunits(Project *pr)
|
||||
strcpy(rpt->Field[DEMAND].Units, RptFlowUnitsTxt[parser->Flowflag]);
|
||||
strcpy(rpt->Field[ELEV].Units, u_METERS);
|
||||
strcpy(rpt->Field[HEAD].Units, u_METERS);
|
||||
if (parser->Pressflag == METERS) strcpy(rpt->Field[PRESSURE].Units, u_METERS);
|
||||
else strcpy(rpt->Field[PRESSURE].Units, u_KPA);
|
||||
strcpy(rpt->Field[LENGTH].Units, u_METERS);
|
||||
strcpy(rpt->Field[DIAM].Units, u_MMETERS);
|
||||
strcpy(rpt->Field[FLOW].Units, RptFlowUnitsTxt[parser->Flowflag]);
|
||||
@@ -446,10 +422,9 @@ void initunits(Project *pr)
|
||||
if (parser->Flowflag == MLD) qcf = MLDperCFS;
|
||||
if (parser->Flowflag == CMH) qcf = CMHperCFS;
|
||||
if (parser->Flowflag == CMD) qcf = CMDperCFS;
|
||||
if (parser->Flowflag == CMS) qcf = CMSperCFS;
|
||||
|
||||
hcf = MperFT;
|
||||
if (parser->Pressflag == METERS) pcf = MperFT * hyd->SpGrav;
|
||||
else pcf = KPAperPSI * PSIperFT * hyd->SpGrav;
|
||||
wcf = KWperHP;
|
||||
}
|
||||
else // US units
|
||||
@@ -457,7 +432,6 @@ void initunits(Project *pr)
|
||||
strcpy(rpt->Field[DEMAND].Units, RptFlowUnitsTxt[parser->Flowflag]);
|
||||
strcpy(rpt->Field[ELEV].Units, u_FEET);
|
||||
strcpy(rpt->Field[HEAD].Units, u_FEET);
|
||||
strcpy(rpt->Field[PRESSURE].Units, u_PSI);
|
||||
strcpy(rpt->Field[LENGTH].Units, u_FEET);
|
||||
strcpy(rpt->Field[DIAM].Units, u_INCHES);
|
||||
strcpy(rpt->Field[FLOW].Units, RptFlowUnitsTxt[parser->Flowflag]);
|
||||
@@ -473,10 +447,16 @@ void initunits(Project *pr)
|
||||
if (parser->Flowflag == IMGD) qcf = IMGDperCFS;
|
||||
if (parser->Flowflag == AFD) qcf = AFDperCFS;
|
||||
hcf = 1.0;
|
||||
pcf = PSIperFT * hyd->SpGrav;
|
||||
wcf = 1.0;
|
||||
}
|
||||
|
||||
strcpy(rpt->Field[PRESSURE].Units, PressUnitsTxt[parser->Pressflag]);
|
||||
pcf = PSIperFT * hyd->SpGrav; // Default to PSI
|
||||
if (parser->Pressflag == METERS) pcf = MperFT;
|
||||
if (parser->Pressflag == KPA) pcf = KPAperPSI * PSIperFT * hyd->SpGrav;
|
||||
if (parser->Pressflag == BAR) pcf = BARperPSI * PSIperFT * hyd->SpGrav;
|
||||
if (parser->Pressflag == FEET) pcf = 1.0;
|
||||
|
||||
strcpy(rpt->Field[QUALITY].Units, "");
|
||||
ccf = 1.0;
|
||||
if (qual->Qualflag == CHEM)
|
||||
@@ -533,12 +513,11 @@ void convertunits(Project *pr)
|
||||
Parser *parser = &pr->parser;
|
||||
|
||||
int i, j, k;
|
||||
double ucf; // Unit conversion factor
|
||||
double ucf, ecf; // Unit conversion factor
|
||||
Pdemand demand; // Pointer to demand record
|
||||
Snode *node;
|
||||
Stank *tank;
|
||||
Slink *link;
|
||||
Spump *pump;
|
||||
Scontrol *control;
|
||||
|
||||
// Convert nodal elevations & initial WQ
|
||||
@@ -565,7 +544,9 @@ void convertunits(Project *pr)
|
||||
hyd->Preq /= pr->Ucf[PRESSURE];
|
||||
|
||||
// Convert emitter discharge coeffs. to head loss coeff.
|
||||
ucf = pow(pr->Ucf[FLOW], hyd->Qexp) / pr->Ucf[PRESSURE];
|
||||
ecf = (parser->Unitsflag == US) ? (PSIperFT * hyd->SpGrav) : (MperFT);
|
||||
|
||||
ucf = pow(pr->Ucf[FLOW], hyd->Qexp) / ecf;
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
node = &net->Node[i];
|
||||
@@ -588,7 +569,6 @@ void convertunits(Project *pr)
|
||||
tank->Kb /= SECperDAY;
|
||||
tank->V = tank->V0;
|
||||
tank->C = node->C0;
|
||||
tank->V1max *= tank->Vmax;
|
||||
}
|
||||
|
||||
// Convert hydraulic convergence criteria
|
||||
@@ -620,33 +600,17 @@ void convertunits(Project *pr)
|
||||
// Convert units on reaction coeffs.
|
||||
link->Kb /= SECperDAY;
|
||||
link->Kw /= SECperDAY;
|
||||
|
||||
// Convert leakage parameters
|
||||
link->LeakArea /= pr->Ucf[LENGTH];
|
||||
link->LeakExpan /= pr->Ucf[LENGTH];
|
||||
}
|
||||
|
||||
else if (link->Type == PUMP)
|
||||
{
|
||||
// Convert units for pump curve parameters
|
||||
i = findpump(net, k);
|
||||
pump = &net->Pump[i];
|
||||
if (pump->Ptype == CONST_HP)
|
||||
{
|
||||
// For constant hp pump, convert kw to hp
|
||||
if (parser->Unitsflag == SI) pump->R /= pr->Ucf[POWER];
|
||||
}
|
||||
else
|
||||
{
|
||||
// For power curve pumps, convert shutoff head and flow coeff.
|
||||
if (pump->Ptype == POWER_FUNC)
|
||||
{
|
||||
pump->H0 /= pr->Ucf[HEAD];
|
||||
pump->R *= (pow(pr->Ucf[FLOW], pump->N) / pr->Ucf[HEAD]);
|
||||
}
|
||||
|
||||
// Convert flow range & max. head units
|
||||
pump->Q0 /= pr->Ucf[FLOW];
|
||||
pump->Qmax /= pr->Ucf[FLOW];
|
||||
pump->Hmax /= pr->Ucf[HEAD];
|
||||
}
|
||||
link->Km /= pr->Ucf[POWER];
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// For flow control valves, convert flow setting
|
||||
@@ -667,6 +631,7 @@ void convertunits(Project *pr)
|
||||
break;
|
||||
}
|
||||
}
|
||||
link->InitSetting = link->Kc;
|
||||
}
|
||||
|
||||
// Convert units on control settings
|
||||
|
||||
275
src/input2.c
275
src/input2.c
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: input2.c
|
||||
Description: reads and interprets network data from an EPANET input file
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 10/29/2019
|
||||
Last Updated: 02/19/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -21,24 +21,18 @@ Last Updated: 10/29/2019
|
||||
#include "hash.h"
|
||||
#include "text.h"
|
||||
|
||||
#define MAXERRS 10 // Max. input errors reported
|
||||
|
||||
extern char *SectTxt[]; // Input section keywords (see ENUMSTXT.H)
|
||||
|
||||
// Exported functions
|
||||
int addnodeID(Network *n, int, char *);
|
||||
int addlinkID(Network *n, int, char *);
|
||||
|
||||
// Imported functions
|
||||
extern int powercurve(double, double, double, double, double, double *,
|
||||
double *, double *);
|
||||
int addnodeID(Network *, int, char *);
|
||||
int addlinkID(Network *, int, char *);
|
||||
int getunitsoption(Project *, char *);
|
||||
int getheadlossoption(Project *, char *);
|
||||
|
||||
// Local functions
|
||||
static int newline(Project *, int, char *);
|
||||
static int addpattern(Network *, char *);
|
||||
static int addcurve(Network *, char *);
|
||||
static int unlinked(Project *);
|
||||
static int getpumpparams(Project *);
|
||||
static void inperrmsg(Project *, int, int, char *);
|
||||
|
||||
|
||||
@@ -101,7 +95,11 @@ int netsize(Project *pr)
|
||||
if (sect == _END) break;
|
||||
continue;
|
||||
}
|
||||
else continue;
|
||||
else
|
||||
{
|
||||
sect = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Add to count of current object
|
||||
@@ -123,6 +121,12 @@ int netsize(Project *pr)
|
||||
errcode = addcurve(&pr->network, tok);
|
||||
parser->MaxCurves = pr->network.Ncurves;
|
||||
break;
|
||||
case _OPTIONS:
|
||||
if (match(tok, w_UNITS))
|
||||
getunitsoption(pr, strtok(line, SEPSTR));
|
||||
else if (match(tok, w_HEADLOSS))
|
||||
getheadlossoption(pr, strtok(line, SEPSTR));
|
||||
break;
|
||||
}
|
||||
if (errcode) break;
|
||||
}
|
||||
@@ -130,11 +134,6 @@ int netsize(Project *pr)
|
||||
parser->MaxNodes = parser->MaxJuncs + parser->MaxTanks;
|
||||
parser->MaxLinks = parser->MaxPipes + parser->MaxPumps + parser->MaxValves;
|
||||
if (parser->MaxPats < 1) parser->MaxPats = 1;
|
||||
if (!errcode)
|
||||
{
|
||||
if (parser->MaxJuncs < 1) errcode = 223; // Not enough nodes
|
||||
else if (parser->MaxTanks == 0) errcode = 224; // No tanks
|
||||
}
|
||||
return errcode;
|
||||
}
|
||||
|
||||
@@ -152,6 +151,7 @@ int readdata(Project *pr)
|
||||
|
||||
char line[MAXLINE + 1], // Line from input data file
|
||||
wline[MAXLINE + 1]; // Working copy of input line
|
||||
char errmsg[MAXMSG + 1] = "";
|
||||
int sect, newsect, // Data sections
|
||||
errcode = 0, // Error code
|
||||
inperr, errsum; // Error code & total error count
|
||||
@@ -213,7 +213,7 @@ int readdata(Project *pr)
|
||||
// Check if max. line length exceeded
|
||||
if (strlen(line) >= MAXLINE)
|
||||
{
|
||||
sprintf(pr->Msg, "%s section: %s", geterrmsg(214, pr->Msg), SectTxt[sect]);
|
||||
sprintf(pr->Msg, "%s section: %s", geterrmsg(214, errmsg), SectTxt[sect]);
|
||||
writeline(pr, pr->Msg);
|
||||
writeline(pr, line);
|
||||
errsum++;
|
||||
@@ -231,9 +231,11 @@ int readdata(Project *pr)
|
||||
}
|
||||
else
|
||||
{
|
||||
inperrmsg(pr, 201, sect, line);
|
||||
sect = -1;
|
||||
parser->ErrTok = 0;
|
||||
errsum++;
|
||||
break;
|
||||
inperrmsg(pr, 299, sect, line);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,26 +251,13 @@ int readdata(Project *pr)
|
||||
errsum++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errcode = 200;
|
||||
break;
|
||||
}
|
||||
else continue;
|
||||
}
|
||||
|
||||
// Stop if reach end of file or max. error count
|
||||
if (errsum == MAXERRS) break;
|
||||
}
|
||||
|
||||
// Check for errors
|
||||
if (errsum > 0) errcode = 200;
|
||||
|
||||
// Check for unlinked nodes
|
||||
if (!errcode) errcode = unlinked(pr);
|
||||
|
||||
// Determine pump curve parameters
|
||||
if (!errcode) errcode = getpumpparams(pr);
|
||||
|
||||
// Free input buffer
|
||||
free(parser->X);
|
||||
return errcode;
|
||||
@@ -315,11 +304,13 @@ int newline(Project *pr, int sect, char *line)
|
||||
if (ruledata(pr) > 0)
|
||||
{
|
||||
ruleerrmsg(pr);
|
||||
deleterule(pr, pr->network.Nrules);
|
||||
return 200;
|
||||
}
|
||||
else return 0;
|
||||
case _SOURCES: return (sourcedata(pr));
|
||||
case _EMITTERS: return (emitterdata(pr));
|
||||
case _LEAKAGE: return (leakagedata(pr));
|
||||
case _QUALITY: return (qualdata(pr));
|
||||
case _STATUS: return (statusdata(pr));
|
||||
case _ROUGHNESS: return (0);
|
||||
@@ -329,139 +320,18 @@ int newline(Project *pr, int sect, char *line)
|
||||
case _REPORT: return (reportdata(pr));
|
||||
case _TIMES: return (timedata(pr));
|
||||
case _OPTIONS: return (optiondata(pr));
|
||||
case _TAGS: return (tagdata(pr));
|
||||
case _COORDS: return (coordata(pr));
|
||||
case _VERTICES: return (vertexdata(pr));
|
||||
|
||||
// Data in these sections are not used for any computations
|
||||
case _LABELS:
|
||||
case _TAGS:
|
||||
case _BACKDROP:
|
||||
return (0);
|
||||
}
|
||||
return 201;
|
||||
}
|
||||
|
||||
int getpumpparams(Project *pr)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: computes pump curve coefficients for all pumps
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
int i, k, errcode = 0;
|
||||
char errmsg[MAXMSG+1];
|
||||
|
||||
for (i = 1; i <= net->Npumps; i++)
|
||||
{
|
||||
errcode = updatepumpparams(pr, i);
|
||||
if (errcode)
|
||||
{
|
||||
k = net->Pump[i].Link;
|
||||
sprintf(pr->Msg, "Error %d: %s %s",
|
||||
errcode, geterrmsg(errcode, errmsg), net->Link[k].ID);
|
||||
writeline(pr, pr->Msg);
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int updatepumpparams(Project *pr, int pumpindex)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: pumpindex = index of a pump
|
||||
** Output: returns error code
|
||||
** Purpose: computes & checks a pump's head curve coefficients
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Spump *pump;
|
||||
Scurve *curve;
|
||||
|
||||
int m;
|
||||
int curveindex;
|
||||
int npts = 0;
|
||||
int errcode = 0;
|
||||
double a, b, c, h0 = 0.0, h1 = 0.0, h2 = 0.0, q1 = 0.0, q2 = 0.0;
|
||||
|
||||
pump = &net->Pump[pumpindex];
|
||||
if (pump->Ptype == CONST_HP) // Constant Hp pump
|
||||
{
|
||||
pump->H0 = 0.0;
|
||||
pump->R = -8.814 * net->Link[pump->Link].Km;
|
||||
pump->N = -1.0;
|
||||
pump->Hmax = BIG; // No head limit
|
||||
pump->Qmax = BIG; // No flow limit
|
||||
pump->Q0 = 1.0; // Init. flow = 1 cfs
|
||||
return errcode;
|
||||
}
|
||||
|
||||
else if (pump->Ptype == NOCURVE) // Pump curve specified
|
||||
{
|
||||
curveindex = pump->Hcurve;
|
||||
if (curveindex == 0) return 226;
|
||||
curve = &net->Curve[curveindex];
|
||||
curve->Type = PUMP_CURVE;
|
||||
npts = curve->Npts;
|
||||
|
||||
// Generic power function curve
|
||||
if (npts == 1)
|
||||
{
|
||||
pump->Ptype = POWER_FUNC;
|
||||
q1 = curve->X[0];
|
||||
h1 = curve->Y[0];
|
||||
h0 = 1.33334 * h1;
|
||||
q2 = 2.0 * q1;
|
||||
h2 = 0.0;
|
||||
}
|
||||
|
||||
// 3 point curve with shutoff head
|
||||
else if (npts == 3 && curve->X[0] == 0.0)
|
||||
{
|
||||
pump->Ptype = POWER_FUNC;
|
||||
h0 = curve->Y[0];
|
||||
q1 = curve->X[1];
|
||||
h1 = curve->Y[1];
|
||||
q2 = curve->X[2];
|
||||
h2 = curve->Y[2];
|
||||
}
|
||||
|
||||
// Custom pump curve
|
||||
else
|
||||
{
|
||||
pump->Ptype = CUSTOM;
|
||||
for (m = 1; m < npts; m++)
|
||||
{
|
||||
if (curve->Y[m] >= curve->Y[m - 1]) return 227;
|
||||
}
|
||||
pump->Qmax = curve->X[npts - 1];
|
||||
pump->Q0 = (curve->X[0] + pump->Qmax) / 2.0;
|
||||
pump->Hmax = curve->Y[0];
|
||||
}
|
||||
|
||||
// Compute shape factors & limits of power function curves
|
||||
if (pump->Ptype == POWER_FUNC)
|
||||
{
|
||||
if (!powercurve(h0, h1, h2, q1, q2, &a, &b, &c)) return 227;
|
||||
else
|
||||
{
|
||||
pump->H0 = -a;
|
||||
pump->R = -b;
|
||||
pump->N = c;
|
||||
pump->Q0 = q1;
|
||||
pump->Qmax = pow((-a / b), (1.0 / c));
|
||||
pump->Hmax = h0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int addnodeID(Network *net, int n, char *id)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
@@ -572,52 +442,49 @@ int addcurve(Network *network, char *id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unlinked(Project *pr)
|
||||
int getunitsoption(Project *pr, char *units)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code if any unlinked junctions found
|
||||
** Purpose: checks for unlinked junctions in network
|
||||
**
|
||||
** NOTE: unlinked tanks have no effect on computations.
|
||||
**-------------------------------------------------------------
|
||||
** Input: units = name of flow units to be used
|
||||
** Output: returns 1 if successful, 0 if not
|
||||
** Purpose: sets the flows units to be used by a project.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
int *marked;
|
||||
int i, err, errcode;
|
||||
Parser *parser = &pr->parser;
|
||||
if (match(units, w_CFS)) parser->Flowflag = CFS;
|
||||
else if (match(units, w_GPM)) parser->Flowflag = GPM;
|
||||
else if (match(units, w_AFD)) parser->Flowflag = AFD;
|
||||
else if (match(units, w_MGD)) parser->Flowflag = MGD;
|
||||
else if (match(units, w_IMGD)) parser->Flowflag = IMGD;
|
||||
else if (match(units, w_LPS)) parser->Flowflag = LPS;
|
||||
else if (match(units, w_LPM)) parser->Flowflag = LPM;
|
||||
else if (match(units, w_CMH)) parser->Flowflag = CMH;
|
||||
else if (match(units, w_CMD)) parser->Flowflag = CMD;
|
||||
else if (match(units, w_MLD)) parser->Flowflag = MLD;
|
||||
else if (match(units, w_CMS)) parser->Flowflag = CMS;
|
||||
else if (match(units, w_SI)) parser->Flowflag = LPS;
|
||||
else return 0;
|
||||
if (parser->Flowflag >= LPS) parser->Unitsflag = SI;
|
||||
else parser->Unitsflag = US;
|
||||
return 1;
|
||||
}
|
||||
|
||||
errcode = 0;
|
||||
err = 0;
|
||||
|
||||
// Create an array to record number of links incident on each node
|
||||
marked = (int *)calloc(net->Nnodes + 1, sizeof(int));
|
||||
ERRCODE(MEMCHECK(marked));
|
||||
if (errcode) return errcode;
|
||||
memset(marked, 0, (net->Nnodes + 1) * sizeof(int));
|
||||
|
||||
// Mark end nodes of each link
|
||||
for (i = 1; i <= net->Nlinks; i++)
|
||||
{
|
||||
marked[net->Link[i].N1]++;
|
||||
marked[net->Link[i].N2]++;
|
||||
}
|
||||
|
||||
// Check each junction
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
// If not marked then error
|
||||
if (marked[i] == 0)
|
||||
{
|
||||
err++;
|
||||
sprintf(pr->Msg, "Error 233: %s %s", geterrmsg(233, pr->Msg), net->Node[i].ID);
|
||||
writeline(pr, pr->Msg);
|
||||
}
|
||||
if (err >= MAXERRS) break;
|
||||
}
|
||||
if (err > 0) errcode = 200;
|
||||
free(marked);
|
||||
return errcode;
|
||||
int getheadlossoption(Project *pr, char *formula)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: formula = name of head loss formula to be used
|
||||
** Output: returns 1 if successful, 0 if not
|
||||
** Purpose: sets the head loss formula to be used by a project.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
if (match(formula, w_HW)) hyd->Formflag = HW;
|
||||
else if (match(formula, w_DW)) hyd->Formflag = DW;
|
||||
else if (match(formula, w_CM)) hyd->Formflag = CM;
|
||||
else return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int findmatch(char *line, char *keyword[])
|
||||
@@ -686,7 +553,7 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment)
|
||||
*/
|
||||
{
|
||||
int n;
|
||||
size_t len, m;
|
||||
int len, m;
|
||||
char *c, *c2;
|
||||
|
||||
// clear comment
|
||||
@@ -704,10 +571,10 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment)
|
||||
if (c2)
|
||||
{
|
||||
// there is a comment here, after the semi-colon.
|
||||
len = strlen(c2);
|
||||
len = (int)strlen(c2);
|
||||
if (len > 0)
|
||||
{
|
||||
len = strcspn(c2, "\n\r");
|
||||
len = (int)strcspn(c2, "\n\r");
|
||||
len = MIN(len, MAXMSG);
|
||||
strncpy(comment, c2, len);
|
||||
comment[MIN(len,MAXMSG)] = '\0';
|
||||
@@ -855,7 +722,11 @@ void inperrmsg(Project *pr, int err, int sect, char *line)
|
||||
else strcpy(tok, "");
|
||||
|
||||
// write error message to report file
|
||||
sprintf(pr->Msg, "Error %d: %s %s in %s section:",
|
||||
if (err == 299)
|
||||
sprintf(pr->Msg, "Error %d: %s %s: section contents ignored.",
|
||||
err, geterrmsg(err, errStr), tok);
|
||||
else
|
||||
sprintf(pr->Msg, "Error %d: %s %s in %s section:",
|
||||
err, geterrmsg(err, errStr), tok, SectTxt[sect]);
|
||||
writeline(pr, pr->Msg);
|
||||
|
||||
|
||||
805
src/input3.c
805
src/input3.c
File diff suppressed because it is too large
Load Diff
527
src/leakage.c
Normal file
527
src/leakage.c
Normal file
@@ -0,0 +1,527 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.3
|
||||
Module: leakage.c
|
||||
Description: models additional nodal demands due to pipe leaks.
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 06/14/2024
|
||||
******************************************************************************
|
||||
*/
|
||||
/*
|
||||
This module uses the FAVAD (Fixed and Variable Discharge) equation to model
|
||||
leaky pipes:
|
||||
|
||||
Q = Co * L * (Ao + m * H) * sqrt(H)
|
||||
|
||||
where Q = pipe leak flow rate, Co = an orifice coefficient (= 0.6*sqrt(2g)),
|
||||
L = pipe length, Ao = initial area of leak per unit of pipe length,
|
||||
m = change in leak area per unit of pressure head, and H = pressure head.
|
||||
|
||||
The inverted form of this equation is used to model the leakage demand from
|
||||
a pipe's end node using a pair of equivalent emitters as follows:
|
||||
|
||||
H = Cfa * Qfa^2
|
||||
H = Cva * Qva^(2/3)
|
||||
|
||||
where Qfa = fixed area node leakage rate, Qva = variable area node leakage rate,
|
||||
Cfa = 1 / SUM(Co*(L/2)*Ao)^2, Cva = 1 / SUM(Co*(L/2)*m)^2/3, and
|
||||
SUM(x) is the summation of x over all pipes connected to the node.
|
||||
|
||||
In implementing this model, the pipe property "LeakArea" represents Ao in
|
||||
sq. mm per 100 units of pipe length and "LeakExpan" represents m in sq. mm
|
||||
per unit of pressure head.
|
||||
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "funcs.h"
|
||||
|
||||
// Exported functions (declared in funcs.h)
|
||||
//int openleakage(Project *);
|
||||
//void closeleakage(Project *);
|
||||
//double findlinkleakage(Project *, int);
|
||||
//void leakagecoeffs(Project *);
|
||||
//double leakageflowchange(Project *, int);
|
||||
//int leakagehasconverged(Project *);
|
||||
|
||||
// Local functions
|
||||
static int check_for_leakage(Project *pr);
|
||||
static int create_leakage_objects(Project *pr);
|
||||
static void convert_pipe_to_node_leakage(Project *pr);
|
||||
static void init_node_leakage(Project *pr);
|
||||
static int leakage_headloss(Project* pr, int i, double *hfa,
|
||||
double *gfa, double *hva, double *gva);
|
||||
static void eval_leak_headloss(double q, double c,
|
||||
double n, double *hloss, double *hgrad);
|
||||
static void add_lower_barrier(double q, double *hloss, double *hgrad);
|
||||
|
||||
|
||||
int openleakage(Project *pr)
|
||||
/*-------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns an error code
|
||||
** Purpose: opens the pipe leakage modeling system
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
int err;
|
||||
|
||||
// Check if project includes leakage
|
||||
closeleakage(pr);
|
||||
hyd->HasLeakage = check_for_leakage(pr);
|
||||
if (!hyd->HasLeakage) return 0;
|
||||
|
||||
// Allocate memory for leakage data objects
|
||||
err = create_leakage_objects(pr);
|
||||
if (err > 0) return err;
|
||||
|
||||
// Convert pipe leakage coeffs. to node coeffs.
|
||||
convert_pipe_to_node_leakage(pr);
|
||||
init_node_leakage(pr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int check_for_leakage(Project *pr)
|
||||
/*-------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns TRUE if any pipes can leak, FALSE otherwise
|
||||
** Purpose: checks if any pipes can leak.
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
int i;
|
||||
Slink *link;
|
||||
|
||||
for (i = 1; i <= net->Nlinks; i++)
|
||||
{
|
||||
// Only pipes have leakage
|
||||
link = &net->Link[i];
|
||||
if (link->Type > PIPE) continue;
|
||||
if (link->LeakArea > 0.0 || link->LeakExpan > 0.0) return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int create_leakage_objects(Project *pr)
|
||||
/*-------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns an error code
|
||||
** Purpose: allocates an array of node leakage objects.
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
int i;
|
||||
|
||||
hyd->Leakage = (Sleakage *)calloc(net->Njuncs + 1, sizeof(Sleakage));
|
||||
if (hyd->Leakage == NULL) return 101;
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
hyd->Leakage[i].cfa = 0.0;
|
||||
hyd->Leakage[i].cva = 0.0;
|
||||
hyd->Leakage[i].qfa = 0.0;
|
||||
hyd->Leakage[i].qva = 0.0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void convert_pipe_to_node_leakage(Project *pr)
|
||||
/*-------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: converts pipe leakage parameters into node leakage
|
||||
** coefficients.
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
int i;
|
||||
double c_area, c_expan, c_orif, len;
|
||||
Slink *link;
|
||||
Snode *node1;
|
||||
Snode *node2;
|
||||
|
||||
// Orifice coeff. with conversion from sq. mm to sq. m
|
||||
c_orif = 4.8149866 * 1.e-6;
|
||||
|
||||
// Examine each link
|
||||
for (i = 1; i <= net->Nlinks; i++)
|
||||
{
|
||||
// Only pipes have leakage
|
||||
link = &net->Link[i];
|
||||
if (link->Type > PIPE) continue;
|
||||
|
||||
// Ignore leakage in a pipe connecting two tanks or
|
||||
// reservoirs (since those nodes don't have demands)
|
||||
node1 = &net->Node[link->N1];
|
||||
node2 = &net->Node[link->N2];
|
||||
if (node1->Type != JUNCTION && node2->Type != JUNCTION) continue;
|
||||
|
||||
// Get pipe's fixed and variable area leak coeffs.
|
||||
if (link->LeakArea == 0.0 && link->LeakExpan == 0.0) continue;
|
||||
c_area = c_orif * link->LeakArea / SQR(MperFT);
|
||||
c_expan = c_orif * link->LeakExpan;
|
||||
|
||||
// Adjust for number of 100-ft pipe sections
|
||||
len = link->Len * pr->Ucf[LENGTH] / 100.;
|
||||
if (node1->Type == JUNCTION && node2->Type == JUNCTION)
|
||||
{
|
||||
len *= 0.5;
|
||||
}
|
||||
c_area *= len;
|
||||
c_expan *= len;
|
||||
|
||||
// Add these coeffs. to pipe's end nodes
|
||||
if (node1->Type == JUNCTION)
|
||||
{
|
||||
hyd->Leakage[link->N1].cfa += c_area;
|
||||
hyd->Leakage[link->N1].cva += c_expan;
|
||||
}
|
||||
if (node2->Type == JUNCTION)
|
||||
{
|
||||
hyd->Leakage[link->N2].cfa += c_area;
|
||||
hyd->Leakage[link->N2].cva += c_expan;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init_node_leakage(Project *pr)
|
||||
/*-------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: initializes node leakage coeffs. and flows.
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
int i;
|
||||
double c_area, c_expan;
|
||||
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
// Coeff. for fixed area leakage
|
||||
c_area = hyd->Leakage[i].cfa;
|
||||
if (c_area > 0.0)
|
||||
hyd->Leakage[i].cfa = 1.0 / (c_area * c_area);
|
||||
else
|
||||
hyd->Leakage[i].cfa = 0.0;
|
||||
|
||||
// Coeff. for variable area leakage
|
||||
c_expan = hyd->Leakage[i].cva;
|
||||
if (c_expan > 0.0)
|
||||
hyd->Leakage[i].cva = 1.0 / pow(c_expan, 2./3.);
|
||||
else
|
||||
hyd->Leakage[i].cva = 0.0;
|
||||
|
||||
// Initialize leakage flow to a non-zero value (as required by
|
||||
// the hydraulic solver)
|
||||
if (hyd->Leakage[i].cfa > 0.0)
|
||||
hyd->Leakage[i].qfa = 0.001;
|
||||
if (hyd->Leakage[i].cva > 0.0)
|
||||
hyd->Leakage[i].qva = 0.001;
|
||||
}
|
||||
}
|
||||
|
||||
void closeleakage(Project *pr)
|
||||
/*-------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: frees memory for nodal leakage objects.
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
if (hyd->Leakage) free(hyd->Leakage);
|
||||
hyd->Leakage = NULL;
|
||||
hyd->HasLeakage = FALSE;
|
||||
}
|
||||
|
||||
double findlinkleakage(Project *pr, int i)
|
||||
/*-------------------------------------------------------------
|
||||
** Input: i = link index
|
||||
** Output: returns link leakage flow (cfs)
|
||||
** Purpose: computes leakage flow from link i at current
|
||||
** hydraulic solution.
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Smatrix *sm = &hyd->smatrix;
|
||||
Slink *link = &net->Link[i];
|
||||
|
||||
int n1, n2;
|
||||
double h1, h2, hsqrt, a, m, c, len, q1, q2;
|
||||
|
||||
// Only pipes can leak
|
||||
link = &net->Link[i];
|
||||
if (link->Type > PIPE) return 0.0;
|
||||
|
||||
// No leakage if area & expansion are 0
|
||||
if (link->LeakArea == 0.0 && link->LeakExpan == 0.0) return 0.0;
|
||||
|
||||
// No leakage if link's end nodes are both fixed grade
|
||||
n1 = link->N1;
|
||||
n2 = link->N2;
|
||||
if (n1 > net->Njuncs && n2 > net->Njuncs) return 0.0;
|
||||
|
||||
// Pressure head of end nodes
|
||||
h1 = hyd->NodeHead[n1] - net->Node[n1].El;
|
||||
h1 = MAX(h1, 0.0);
|
||||
h2 = hyd->NodeHead[n2] - net->Node[n2].El;
|
||||
h2 = MAX(h2, 0.0);
|
||||
|
||||
// Pipe leak parameters converted to feet
|
||||
a = link->LeakArea / SQR(MperFT);
|
||||
m = link->LeakExpan;
|
||||
len = link->Len * pr->Ucf[LENGTH] / 100.; // # 100 ft pipe lengths
|
||||
c = 4.8149866 * len / 2.0 * 1.e-6;
|
||||
|
||||
// Leakage from 1st half of pipe connected to node n1
|
||||
q1 = 0.0;
|
||||
if (n1 <= net->Njuncs)
|
||||
{
|
||||
hsqrt = sqrt(h1);
|
||||
q1 = c * (a + m * h1) * hsqrt;
|
||||
}
|
||||
|
||||
// Leakage from 2nd half of pipe connected to node n2
|
||||
q2 = 0.0;
|
||||
if (n2 <= net->Njuncs)
|
||||
{
|
||||
hsqrt = sqrt(h2);
|
||||
q2 = c * (a + m * h2) * hsqrt;
|
||||
}
|
||||
|
||||
// Adjust leakage flows to account for one node being fixed grade
|
||||
if (n2 > net->Njuncs) q1 *= 2.0;
|
||||
if (n1 > net->Njuncs) q2 *= 2.0;
|
||||
return q1 + q2;
|
||||
}
|
||||
|
||||
void leakagecoeffs(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: computes coeffs. of the linearized hydraulic eqns.
|
||||
** contributed by node leakages.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Smatrix *sm = &hyd->smatrix;
|
||||
|
||||
int i, row;
|
||||
double hfa, // head loss producing current fixed area leakage
|
||||
gfa, // gradient of fixed area head loss
|
||||
hva, // head loss producing current variable area leakage
|
||||
gva; // gradient of variable area head loss
|
||||
|
||||
Snode* node;
|
||||
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
// Skip junctions that don't leak
|
||||
node = &net->Node[i];
|
||||
if (!leakage_headloss(pr, i, &hfa, &gfa, &hva, &gva)) continue;
|
||||
|
||||
// Addition to matrix diagonal & r.h.s
|
||||
row = sm->Row[i];
|
||||
if (gfa > 0.0)
|
||||
{
|
||||
sm->Aii[row] += 1.0 / gfa;
|
||||
sm->F[row] += (hfa + node->El) / gfa;
|
||||
}
|
||||
if (gva > 0.0)
|
||||
{
|
||||
sm->Aii[row] += 1.0 / gva;
|
||||
sm->F[row] += (hva + node->El) / gva;
|
||||
}
|
||||
|
||||
// Update node's flow excess (inflow - outflow)
|
||||
hyd->Xflow[i] -= (hyd->Leakage[i].qfa + hyd->Leakage[i].qva);
|
||||
}
|
||||
}
|
||||
|
||||
double leakageflowchange(Project *pr, int i)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: i = node index
|
||||
** Output: returns change in leakage flow rate
|
||||
** Purpose: finds new leakage flow rate at a node after new
|
||||
** heads are computed by the hydraulic solver.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
double hfa, gfa, hva, gva; // same as defined in leakage_solvercoeffs()
|
||||
double h, dqfa, dqva; // pressure head, change in leakage flows
|
||||
|
||||
// Find the head loss and gradient of the inverted leakage
|
||||
// equation for both fixed and variable area leakage at the
|
||||
// current leakage flow rates
|
||||
if (!leakage_headloss(pr, i, &hfa, &gfa, &hva, &gva)) return 0.0;
|
||||
|
||||
// Pressure head using latest head solution
|
||||
h = hyd->NodeHead[i] - net->Node[i].El;
|
||||
|
||||
// GGA flow update formula for fixed area leakage
|
||||
dqfa = 0.0;
|
||||
if (gfa > 0.0)
|
||||
{
|
||||
dqfa = (hfa - h) / gfa * hyd->RelaxFactor;
|
||||
hyd->Leakage[i].qfa -= dqfa;
|
||||
}
|
||||
|
||||
// GGA flow update formula for variable area leakage
|
||||
dqva = 0.0;
|
||||
if (gva > 0.0)
|
||||
{
|
||||
dqva = (hva - h) / gva * hyd->RelaxFactor;
|
||||
hyd->Leakage[i].qva -= dqva;
|
||||
}
|
||||
|
||||
// New leakage flow at the node
|
||||
hyd->LeakageFlow[i] = hyd->Leakage[i].qfa + hyd->Leakage[i].qva;
|
||||
return dqfa + dqva;
|
||||
}
|
||||
|
||||
int leakagehasconverged(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns TRUE if leakage calculations converged,
|
||||
** FALSE if not
|
||||
** Purpose: checks if leakage calculations have converged.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
int i;
|
||||
double h, qref, qtest;
|
||||
const double QTOL = 0.0001; // 0.0001 cfs ~= 0.005 gpm ~= 0.2 lpm)
|
||||
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
// Skip junctions that don't leak
|
||||
if (hyd->Leakage[i].cfa == 0 && hyd->Leakage[i].cva == 0) continue;
|
||||
|
||||
// Evaluate node's pressure head
|
||||
h = hyd->NodeHead[i] - net->Node[i].El;
|
||||
|
||||
// Directly compute a reference leakage at this pressure head
|
||||
qref = 0.0;
|
||||
// Contribution from pipes with fixed area leaks
|
||||
if (hyd->Leakage[i].cfa > 0.0)
|
||||
qref = sqrt(h / hyd->Leakage[i].cfa);
|
||||
// Contribution from pipes with variable area leaks
|
||||
if (hyd->Leakage[i].cva > 0.0)
|
||||
qref += pow((h / hyd->Leakage[i].cva), 1.5);
|
||||
|
||||
// Compare reference leakage to solution leakage
|
||||
qtest = hyd->Leakage[i].qfa + hyd->Leakage[i].qva;
|
||||
if (fabs(qref - qtest) > QTOL) return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int leakage_headloss(Project* pr, int i, double *hfa, double *gfa,
|
||||
double *hva, double *gva)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: i = node index
|
||||
** Output: hfa = fixed area leak head loss (ft)
|
||||
** gfa = gradient of fixed area head loss (ft/cfs)
|
||||
** hva = variable area leak head loss (ft)
|
||||
** gva = gradient of variable area head loss (ft/cfs)
|
||||
** returns TRUE if node has leakage, FALSE otherwise
|
||||
** Purpose: finds head loss and its gradient for a node's
|
||||
** leakage as a function of leakage flow.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
if (hyd->Leakage[i].cfa == 0.0 && hyd->Leakage[i].cva == 0.0) return FALSE;
|
||||
if (hyd->Leakage[i].cfa == 0.0)
|
||||
{
|
||||
*hfa = 0.0;
|
||||
*gfa = 0.0;
|
||||
}
|
||||
else
|
||||
eval_leak_headloss(hyd->Leakage[i].qfa, hyd->Leakage[i].cfa,
|
||||
0.5, hfa, gfa);
|
||||
if (hyd->Leakage[i].cva == 0.0)
|
||||
{
|
||||
*hva = 0.0;
|
||||
*gva = 0.0;
|
||||
}
|
||||
else
|
||||
eval_leak_headloss(hyd->Leakage[i].qva, hyd->Leakage[i].cva,
|
||||
1.5, hva, gva);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void eval_leak_headloss(double q, double c, double n,
|
||||
double *hloss, double *hgrad)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: q = leakage flow rate (cfs)
|
||||
** c = leakage head loss coefficient
|
||||
** n = leakage head loss exponent
|
||||
** Output: hloss = leakage head loss (ft)
|
||||
** hgrad = gradient of leakage head loss (ft/cfs)
|
||||
** Purpose: evaluates inverted form of leakage equation to
|
||||
** compute head loss and its gradient as a function
|
||||
** flow.
|
||||
**
|
||||
** Note: Inverted leakage equation is:
|
||||
** hloss = c * q ^ (1/n)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
n = 1.0 / n;
|
||||
*hgrad = n * c * pow(fabs(q), n - 1.0);
|
||||
*hloss = (*hgrad) * q / n;
|
||||
|
||||
// Prevent leakage from going negative
|
||||
add_lower_barrier(q, hloss, hgrad);
|
||||
}
|
||||
|
||||
void add_lower_barrier(double q, double* hloss, double* hgrad)
|
||||
/*
|
||||
**--------------------------------------------------------------------
|
||||
** Input: q = current flow rate
|
||||
** Output: hloss = head loss value
|
||||
** hgrad = head loss gradient value
|
||||
** Purpose: adds a head loss barrier to prevent flow from falling
|
||||
** below 0.
|
||||
**--------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
double a = 1.e9 * q;
|
||||
double b = sqrt(a*a + 1.e-6);
|
||||
*hloss += (a - b) / 2.;
|
||||
*hgrad += (1.e9 / 2.) * ( 1.0 - a / b);
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: mempool.c
|
||||
Description: a simple fast poooled memory allocation package
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 05/15/2019
|
||||
Last Updated: 08/02/2023
|
||||
|
||||
This module is based code by Steve Hill in Graphics Gems III,
|
||||
This module is based on code by Steve Hill in Graphics Gems III,
|
||||
David Kirk (ed.), Academic Press, Boston, MA, 1992
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -72,7 +72,11 @@ struct Mempool * mempool_create()
|
||||
if (mempool == NULL) return NULL;
|
||||
mempool->first = createMemBlock();
|
||||
mempool->current = mempool->first;
|
||||
if (mempool->first == NULL) return NULL;
|
||||
if (mempool->first == NULL)
|
||||
{
|
||||
free(mempool);
|
||||
return NULL;
|
||||
}
|
||||
return mempool;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: mempool.h
|
||||
Description: header for a simple pooled memory allocator
|
||||
Authors: see AUTHORS
|
||||
|
||||
@@ -33,7 +33,8 @@ typedef enum {
|
||||
ENR_LPM = 6,
|
||||
ENR_MLD = 7,
|
||||
ENR_CMH = 8,
|
||||
ENR_CMD = 9
|
||||
ENR_CMD = 9,
|
||||
ENR_CMS = 10
|
||||
} ENR_FlowUnits;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
// epanet_output.c -- API for reading results from EPANET binary output file
|
||||
//
|
||||
// Version: 0.40
|
||||
// Date 04/02/2019
|
||||
// Date 08/02/2023
|
||||
// 04/02/2019
|
||||
// 09/06/2017
|
||||
// 06/17/2016
|
||||
// 08/05/2014
|
||||
@@ -121,7 +122,7 @@ int EXPORT_OUT_API ENR_close(ENR_Handle *p_handle)
|
||||
**
|
||||
** Returns: Error code 0 on success, -1 on failure
|
||||
**
|
||||
** Purpose: Close the output binary file, dellocate ENR_Handle struc
|
||||
** Purpose: Close the output binary file, deallocate ENR_Handle struct
|
||||
** and nullify pointer to ENR_Handle struct
|
||||
**
|
||||
** NOTE: ENR_close must be called before program end
|
||||
@@ -160,7 +161,7 @@ int EXPORT_OUT_API ENR_open(ENR_Handle p_handle, const char* path)
|
||||
** Returns: warning / error code
|
||||
** Purpose: Opens the output binary file and reads prologue and epilogue
|
||||
**
|
||||
** NOTE: ENR_init must be called before anyother ENR_* functions
|
||||
** NOTE: ENR_init must be called before any other ENR_* functions
|
||||
**-------------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
@@ -252,12 +253,15 @@ int EXPORT_OUT_API ENR_getNetSize(ENR_Handle p_handle, int** elementCount, int*
|
||||
*/
|
||||
{
|
||||
int errorcode = 0;
|
||||
int* temp = newIntArray(NELEMENTTYPES);
|
||||
int* temp;
|
||||
data_t* p_data;
|
||||
|
||||
p_data = (data_t*)p_handle;
|
||||
|
||||
if (p_data == NULL) return -1;
|
||||
// Check memory for count values
|
||||
else if MEMCHECK(temp = newIntArray(NELEMENTTYPES)) errorcode = 411;
|
||||
|
||||
else
|
||||
{
|
||||
temp[0] = p_data->nodeCount;
|
||||
@@ -295,6 +299,7 @@ int EXPORT_OUT_API ENR_getUnits(ENR_Handle p_handle, ENR_Units code, int* unitFl
|
||||
** 7 = megaliters/day
|
||||
** 8 = cubic meters/hour
|
||||
** 9 = cubic meters/day
|
||||
** 10 = cubic meters/sec
|
||||
**-------------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
@@ -458,6 +463,7 @@ int EXPORT_OUT_API ENR_getElementName(ENR_Handle p_handle, ENR_ElementType type,
|
||||
*name = temp;
|
||||
*length = MAXID_P1;
|
||||
}
|
||||
else free(temp);
|
||||
}
|
||||
|
||||
return set_error(p_data->error_handle, errorcode);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: output.c
|
||||
Description: binary file read/write routines
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 05/13/2019
|
||||
Last Updated: 08/13/2022
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -567,6 +567,7 @@ int linkoutput(Project *pr, int j, REAL4 *x, double ucf)
|
||||
case FCV:
|
||||
x[i] = (REAL4)(setting * pr->Ucf[FLOW]); break;
|
||||
case TCV:
|
||||
case PCV:
|
||||
x[i] = (REAL4)setting; break;
|
||||
default: x[i] = 0.0f;
|
||||
}
|
||||
@@ -587,8 +588,8 @@ int linkoutput(Project *pr, int j, REAL4 *x, double ucf)
|
||||
|
||||
case FRICTION: // Friction factor
|
||||
// f = 2ghd/(Lu^2) where f = friction factor
|
||||
// u = velocity, g = grav. accel., h = head loss
|
||||
//loss, d = diam., & L = pipe length
|
||||
// u = velocity, g = grav. accel., h = head
|
||||
// loss, d = diam., & L = pipe length
|
||||
for (i = 1; i <= net->Nlinks; i++)
|
||||
{
|
||||
if (net->Link[i].Type <= PIPE && ABS(hyd->LinkFlow[i]) > TINY)
|
||||
|
||||
482
src/project.c
482
src/project.c
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: project.c
|
||||
Description: project data management routines
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/15/2019
|
||||
Last Updated: 04/23/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -24,6 +24,81 @@
|
||||
#include "types.h"
|
||||
#include "funcs.h"
|
||||
|
||||
int openproject(Project *pr, const char *inpFile, const char *rptFile,
|
||||
const char *outFile, int allowerrors)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: inpFile = name of input file
|
||||
** rptFile = name of report file
|
||||
** outFile = name of binary output file
|
||||
** allowerrors = TRUE if project can be opened with errors
|
||||
** Output: none
|
||||
** Returns: error code
|
||||
** Purpose: opens an EPANET input file & reads in network data
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int errcode = 0;
|
||||
int hyderrcode = 0;
|
||||
int projectopened;
|
||||
|
||||
// Set system flags
|
||||
pr->Openflag = FALSE;
|
||||
pr->hydraul.OpenHflag = FALSE;
|
||||
pr->quality.OpenQflag = FALSE;
|
||||
pr->outfile.SaveHflag = FALSE;
|
||||
pr->outfile.SaveQflag = FALSE;
|
||||
pr->Warnflag = FALSE;
|
||||
pr->report.Messageflag = TRUE;
|
||||
pr->report.Rptflag = 1;
|
||||
|
||||
// Initialize data arrays to NULL
|
||||
initpointers(pr);
|
||||
|
||||
// Open input & report files
|
||||
ERRCODE(openfiles(pr, inpFile, rptFile, outFile));
|
||||
if (errcode > 0)
|
||||
{
|
||||
errmsg(pr, errcode);
|
||||
return errcode;
|
||||
}
|
||||
|
||||
// Allocate memory for project's data arrays
|
||||
ERRCODE(netsize(pr));
|
||||
ERRCODE(allocdata(pr));
|
||||
|
||||
// Read input data
|
||||
ERRCODE(getdata(pr));
|
||||
|
||||
// Close input file
|
||||
if (pr->parser.InFile != NULL)
|
||||
{
|
||||
fclose(pr->parser.InFile);
|
||||
pr->parser.InFile = NULL;
|
||||
}
|
||||
|
||||
// Input file read with no fatal errors
|
||||
if (allowerrors) projectopened = (errcode == 0 || errcode == 200);
|
||||
else projectopened = (errcode == 0);
|
||||
if (projectopened)
|
||||
{
|
||||
// If using previously saved hydraulics file then open it
|
||||
if (pr->outfile.Hydflag == USE)
|
||||
{
|
||||
hyderrcode = openhydfile(pr);
|
||||
if (hyderrcode > 0)
|
||||
{
|
||||
errmsg(pr, hyderrcode);
|
||||
pr->outfile.Hydflag = SCRATCH;
|
||||
}
|
||||
}
|
||||
|
||||
// Write input summary to report file
|
||||
if (pr->report.Summaryflag) writesummary(pr);
|
||||
pr->Openflag = TRUE;
|
||||
}
|
||||
errmsg(pr, errcode);
|
||||
return errcode;
|
||||
}
|
||||
|
||||
int openfiles(Project *pr, const char *f1, const char *f2, const char *f3)
|
||||
/*----------------------------------------------------------------
|
||||
@@ -93,10 +168,9 @@ int openhydfile(Project *pr)
|
||||
INT4 version;
|
||||
int errcode = 0;
|
||||
|
||||
// If HydFile currently open, then close it if its not a scratch file
|
||||
// If HydFile currently open, then close it
|
||||
if (pr->outfile.HydFile != NULL)
|
||||
{
|
||||
if (pr->outfile.Hydflag == SCRATCH) return 0;
|
||||
fclose(pr->outfile.HydFile);
|
||||
pr->outfile.HydFile = NULL;
|
||||
}
|
||||
@@ -253,6 +327,11 @@ void initpointers(Project *pr)
|
||||
pr->hydraul.P = NULL;
|
||||
pr->hydraul.Y = NULL;
|
||||
pr->hydraul.Xflow = NULL;
|
||||
pr->hydraul.FullDemand = NULL;
|
||||
pr->hydraul.DemandFlow = NULL;
|
||||
pr->hydraul.EmitterFlow = NULL;
|
||||
pr->hydraul.LeakageFlow = NULL;
|
||||
pr->hydraul.Leakage = NULL;
|
||||
|
||||
pr->quality.NodeQual = NULL;
|
||||
pr->quality.PipeRateCoeff = NULL;
|
||||
@@ -279,6 +358,8 @@ void initpointers(Project *pr)
|
||||
pr->hydraul.smatrix.NZSUB = NULL;
|
||||
pr->hydraul.smatrix.LNZ = NULL;
|
||||
|
||||
pr->report.reportCallback = NULL;
|
||||
|
||||
initrules(pr);
|
||||
}
|
||||
|
||||
@@ -313,10 +394,18 @@ int allocdata(Project *pr)
|
||||
pr->hydraul.NodeDemand = (double *)calloc(n, sizeof(double));
|
||||
pr->hydraul.NodeHead = (double *)calloc(n, sizeof(double));
|
||||
pr->quality.NodeQual = (double *)calloc(n, sizeof(double));
|
||||
pr->hydraul.FullDemand = (double *)calloc(n, sizeof(double));
|
||||
pr->hydraul.DemandFlow = (double *)calloc(n, sizeof(double));
|
||||
pr->hydraul.EmitterFlow = (double *)calloc(n, sizeof(double));
|
||||
pr->hydraul.LeakageFlow = (double *)calloc(n, sizeof(double));
|
||||
ERRCODE(MEMCHECK(pr->network.Node));
|
||||
ERRCODE(MEMCHECK(pr->hydraul.NodeDemand));
|
||||
ERRCODE(MEMCHECK(pr->hydraul.NodeHead));
|
||||
ERRCODE(MEMCHECK(pr->quality.NodeQual));
|
||||
ERRCODE(MEMCHECK(pr->hydraul.FullDemand));
|
||||
ERRCODE(MEMCHECK(pr->hydraul.DemandFlow));
|
||||
ERRCODE(MEMCHECK(pr->hydraul.EmitterFlow));
|
||||
ERRCODE(MEMCHECK(pr->hydraul.LeakageFlow));
|
||||
}
|
||||
|
||||
// Allocate memory for network links
|
||||
@@ -359,11 +448,13 @@ int allocdata(Project *pr)
|
||||
pr->network.Node[n].D = NULL; // node demand
|
||||
pr->network.Node[n].S = NULL; // node source
|
||||
pr->network.Node[n].Comment = NULL;
|
||||
pr->network.Node[n].Tag = NULL;
|
||||
}
|
||||
for (n = 0; n <= pr->parser.MaxLinks; n++)
|
||||
{
|
||||
pr->network.Link[n].Vertices = NULL;
|
||||
pr->network.Link[n].Comment = NULL;
|
||||
pr->network.Link[n].Tag = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,6 +479,10 @@ void freedata(Project *pr)
|
||||
free(pr->hydraul.LinkFlow);
|
||||
free(pr->hydraul.LinkSetting);
|
||||
free(pr->hydraul.LinkStatus);
|
||||
free(pr->hydraul.FullDemand);
|
||||
free(pr->hydraul.DemandFlow);
|
||||
free(pr->hydraul.EmitterFlow);
|
||||
free(pr->hydraul.LeakageFlow);
|
||||
free(pr->quality.NodeQual);
|
||||
|
||||
// Free memory used for nodal adjacency lists
|
||||
@@ -402,6 +497,7 @@ void freedata(Project *pr)
|
||||
freedemands(&(pr->network.Node[j]));
|
||||
free(pr->network.Node[j].S);
|
||||
free(pr->network.Node[j].Comment);
|
||||
free(pr->network.Node[j].Tag);
|
||||
}
|
||||
free(pr->network.Node);
|
||||
}
|
||||
@@ -413,6 +509,7 @@ void freedata(Project *pr)
|
||||
{
|
||||
freelinkvertices(&pr->network.Link[j]);
|
||||
free(pr->network.Link[j].Comment);
|
||||
free(pr->network.Link[j].Tag);
|
||||
}
|
||||
}
|
||||
free(pr->network.Link);
|
||||
@@ -482,7 +579,7 @@ Pdemand finddemand(Pdemand d, int index)
|
||||
return d;
|
||||
}
|
||||
|
||||
int adddemand(Snode *node, double dbase, int dpat, char *dname)
|
||||
int adddemand(Snode *node, double dbase, int dpat, const char *dname)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: node = a network junction node
|
||||
** dbase = base demand value
|
||||
@@ -550,31 +647,41 @@ int addlinkvertex(Slink *link, double x, double y)
|
||||
*/
|
||||
{
|
||||
static int CHUNKSIZE = 5;
|
||||
int n;
|
||||
int n, newCapacity;
|
||||
Pvertices vertices;
|
||||
if (link->Vertices == NULL)
|
||||
double *newX, *newY;
|
||||
|
||||
vertices = link->Vertices;
|
||||
if (vertices == NULL)
|
||||
{
|
||||
vertices = (struct Svertices *) malloc(sizeof(struct Svertices));
|
||||
if (vertices == NULL) return 101;
|
||||
vertices->Npts = 0;
|
||||
vertices->Capacity = CHUNKSIZE;
|
||||
vertices->X = (double *) calloc(vertices->Capacity, sizeof(double));
|
||||
vertices->Y = (double *) calloc(vertices->Capacity, sizeof(double));
|
||||
vertices->Capacity = 0;
|
||||
vertices->X = NULL;
|
||||
vertices->Y = NULL;
|
||||
link->Vertices = vertices;
|
||||
}
|
||||
vertices = link->Vertices;
|
||||
if (vertices->Npts >= vertices->Capacity)
|
||||
{
|
||||
vertices->Capacity += CHUNKSIZE;
|
||||
vertices->X = realloc(vertices->X, vertices->Capacity * sizeof(double));
|
||||
vertices->Y = realloc(vertices->Y, vertices->Capacity * sizeof(double));
|
||||
newCapacity = vertices->Capacity + CHUNKSIZE;
|
||||
newX = realloc(vertices->X, newCapacity * sizeof(double));
|
||||
newY = realloc(vertices->Y, newCapacity * sizeof(double));
|
||||
if (newX == NULL || newY == NULL)
|
||||
{
|
||||
free(newX);
|
||||
free(newY);
|
||||
return 101;
|
||||
}
|
||||
vertices->Capacity = newCapacity;
|
||||
vertices->X = newX;
|
||||
vertices->Y = newY;
|
||||
}
|
||||
if (vertices->X == NULL || vertices->Y == NULL) return 101;
|
||||
n = vertices->Npts;
|
||||
vertices->X[n] = x;
|
||||
vertices->Y[n] = y;
|
||||
vertices->Npts++;
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void freelinkvertices(Slink *link)
|
||||
@@ -647,7 +754,6 @@ int buildadjlists(Network *net)
|
||||
return errcode;
|
||||
}
|
||||
|
||||
|
||||
void freeadjlists(Network *net)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
@@ -734,6 +840,66 @@ int incontrols(Project *pr, int objType, int index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int changevalvetype(Project *pr, int index, int type)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: index = link index
|
||||
** type = new valve type
|
||||
** Output: returns an error code
|
||||
** Purpose: changes a valve's type
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Slink *link;
|
||||
int errcode;
|
||||
double setting;
|
||||
|
||||
// Check that new valve type has legal connections
|
||||
link = &net->Link[index];
|
||||
if (link->Type <= PUMP) return 264;
|
||||
errcode = valvecheck(pr, index, type, link->N1, link->N2);
|
||||
if (errcode) return errcode;
|
||||
|
||||
// Preserve new type's setting in solver units
|
||||
setting = link->InitSetting;
|
||||
switch (link->Type)
|
||||
{
|
||||
case FCV:
|
||||
setting *= pr->Ucf[FLOW];
|
||||
break;
|
||||
case PRV:
|
||||
case PSV:
|
||||
case PBV:
|
||||
setting *= pr->Ucf[PRESSURE];
|
||||
break;
|
||||
case GPV:
|
||||
setting = 0.0;
|
||||
break;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case FCV:
|
||||
setting /= pr->Ucf[FLOW];
|
||||
break;
|
||||
case PRV:
|
||||
case PSV:
|
||||
case PBV:
|
||||
setting /= pr->Ucf[PRESSURE];
|
||||
break;
|
||||
}
|
||||
|
||||
// Save setting
|
||||
if (type == GPV) setting = 0.0;
|
||||
if (type == PCV) setting = MIN(setting, 100.0);
|
||||
link->Kc = setting;
|
||||
link->InitSetting = setting;
|
||||
|
||||
// Change valve link's type
|
||||
link->Type = type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int valvecheck(Project *pr, int index, int type, int j1, int j2)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
@@ -795,7 +961,36 @@ int valvecheck(Project *pr, int index, int type, int j1, int j2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int findnode(Network *network, char *id)
|
||||
int unlinked(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code if any unlinked junctions found
|
||||
** Purpose: checks for unlinked junctions in network
|
||||
**
|
||||
** NOTE: unlinked tanks have no effect on computations.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
int i, count = 0;
|
||||
char errmsg[MAXMSG + 1] = "";
|
||||
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
if (pr->network.Adjlist[i] == NULL)
|
||||
{
|
||||
count++;
|
||||
sprintf(pr->Msg, "Error 234: %s %s", geterrmsg(234, errmsg), net->Node[i].ID);
|
||||
writeline(pr, pr->Msg);
|
||||
}
|
||||
if (count >= 10) break;
|
||||
}
|
||||
if (count > 0) return 233;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int findnode(Network *network, const char *id)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: id = node ID
|
||||
** Output: none
|
||||
@@ -807,7 +1002,7 @@ int findnode(Network *network, char *id)
|
||||
return (hashtable_find(network->NodeHashTable, id));
|
||||
}
|
||||
|
||||
int findlink(Network *network, char *id)
|
||||
int findlink(Network *network, const char *id)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: id = link ID
|
||||
** Output: none
|
||||
@@ -823,7 +1018,7 @@ int findtank(Network *network, int index)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: index = node index
|
||||
** Output: none
|
||||
** Returns: index of tank with given node id, or NOTFOUND if tank not found
|
||||
** Returns: index of tank with given node index, or NOTFOUND if tank not found
|
||||
** Purpose: for use in the deletenode function
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
@@ -840,7 +1035,7 @@ int findpump(Network *network, int index)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: index = link ID
|
||||
** Output: none
|
||||
** Returns: index of pump with given link id, or NOTFOUND if pump not found
|
||||
** Returns: index of pump with given link index, or NOTFOUND if pump not found
|
||||
** Purpose: for use in the deletelink function
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
@@ -857,7 +1052,7 @@ int findvalve(Network *network, int index)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: index = link ID
|
||||
** Output: none
|
||||
** Returns: index of valve with given link id, or NOTFOUND if valve not found
|
||||
** Returns: index of valve with given link index, or NOTFOUND if valve not found
|
||||
** Purpose: for use in the deletelink function
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
@@ -870,7 +1065,7 @@ int findvalve(Network *network, int index)
|
||||
return NOTFOUND;
|
||||
}
|
||||
|
||||
int findpattern(Network *network, char *id)
|
||||
int findpattern(Network *network, const char *id)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: id = time pattern ID
|
||||
** Output: none
|
||||
@@ -889,7 +1084,7 @@ int findpattern(Network *network, char *id)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int findcurve(Network *network, char *id)
|
||||
int findcurve(Network *network, const char *id)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: id = data curve ID
|
||||
** Output: none
|
||||
@@ -912,8 +1107,8 @@ void adjustpattern(int *pat, int index)
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
if (*pat == index) *pat = 0;
|
||||
else if (*pat > index) (*pat)--;
|
||||
if (*pat == index) *pat = 0;
|
||||
else if (*pat > index) (*pat)--;
|
||||
}
|
||||
|
||||
void adjustpatterns(Network *network, int index)
|
||||
@@ -973,7 +1168,7 @@ void adjustcurves(Network *network, int index)
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int j, k, setting;
|
||||
int j, k, curve;
|
||||
|
||||
// Adjust tank volume curves
|
||||
for (j = 1; j <= network->Ntanks; j++)
|
||||
@@ -988,60 +1183,29 @@ void adjustcurves(Network *network, int index)
|
||||
adjustcurve(&network->Pump[j].Ecurve, index);
|
||||
}
|
||||
|
||||
// Adjust GPV curves
|
||||
// Adjust PCV & GPV curves
|
||||
for (j = 1; j <= network->Nvalves; j++)
|
||||
{
|
||||
k = network->Valve[j].Link;
|
||||
if (network->Link[k].Type == PCV)
|
||||
{
|
||||
if ((curve = network->Valve[j].Curve) > 0)
|
||||
{
|
||||
adjustcurve(&curve, index);
|
||||
network->Valve[j].Curve = curve;
|
||||
if (curve == 0)
|
||||
network->Link[k].Kc = 0.0;
|
||||
}
|
||||
}
|
||||
if (network->Link[k].Type == GPV)
|
||||
{
|
||||
setting = INT(network->Link[k].Kc);
|
||||
adjustcurve(&setting, index);
|
||||
network->Link[k].Kc = setting;
|
||||
curve = INT(network->Link[k].Kc);
|
||||
adjustcurve(&curve, index);
|
||||
network->Link[k].Kc = curve;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int adjustpumpparams(Project *pr, int curveIndex)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: curveIndex = index of a data curve
|
||||
** Output: returns an error code
|
||||
** Purpose: updates head curve parameters for pumps using a
|
||||
** curve whose data have been modified.
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *network = &pr->network;
|
||||
|
||||
double *Ucf = pr->Ucf;
|
||||
int j, err = 0;
|
||||
Spump *pump;
|
||||
|
||||
// Check each pump
|
||||
for (j = 1; j <= network->Npumps; j++)
|
||||
{
|
||||
// Pump uses curve as head curve
|
||||
pump = &network->Pump[j];
|
||||
if ( curveIndex == pump->Hcurve)
|
||||
{
|
||||
// Update its head curve parameters
|
||||
pump->Ptype = NOCURVE;
|
||||
err = updatepumpparams(pr, curveIndex);
|
||||
if (err > 0) break;
|
||||
|
||||
// Convert parameters to internal units
|
||||
if (pump->Ptype == POWER_FUNC)
|
||||
{
|
||||
pump->H0 /= Ucf[HEAD];
|
||||
pump->R *= (pow(Ucf[FLOW], pump->N) / Ucf[HEAD]);
|
||||
}
|
||||
pump->Q0 /= Ucf[FLOW];
|
||||
pump->Qmax /= Ucf[FLOW];
|
||||
pump->Hmax /= Ucf[HEAD];
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int resizecurve(Scurve *curve, int size)
|
||||
/*----------------------------------------------------------------
|
||||
@@ -1072,6 +1236,112 @@ int resizecurve(Scurve *curve, int size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int setcontrol(EN_Project p, int type, int linkIndex, double setting,
|
||||
int nodeIndex, double level, Scontrol *control)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: type = type of control (see EN_ControlType)
|
||||
** linkIndex = index of link being controlled
|
||||
** setting = link control setting (e.g., pump speed)
|
||||
** nodeIndex = index of node controlling a link (for level controls)
|
||||
** level = control activation level (pressure for junction nodes,
|
||||
** water level for tank nodes or time value for time-based
|
||||
** control)
|
||||
** Output: control = control struct whose properties are being set
|
||||
** Returns: error code
|
||||
** Purpose: assigns properties to a control struct.
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &p->network;
|
||||
Parser *parser = &p->parser;
|
||||
|
||||
long t = 0;
|
||||
double lvl = 0.0, s = MISSING;
|
||||
double *Ucf = p->Ucf;
|
||||
LinkType linktype;
|
||||
StatusType status = ACTIVE;
|
||||
|
||||
// Cannot control check valve
|
||||
linktype = net->Link[linkIndex].Type;
|
||||
if (linktype == CVPIPE) return 207;
|
||||
|
||||
// Check for valid control type and node index
|
||||
if (type < 0 || type > TIMEOFDAY) return 251;
|
||||
if (type == LOWLEVEL || type == HILEVEL)
|
||||
{
|
||||
if (nodeIndex < 1 || nodeIndex > net->Nnodes) return 203;
|
||||
}
|
||||
else nodeIndex = 0;
|
||||
|
||||
// Check if control setting is a status level
|
||||
if (setting == SET_OPEN)
|
||||
{
|
||||
status = OPEN;
|
||||
if (linktype == PUMP) s = 1.0;
|
||||
if (linktype == GPV) s = net->Link[linkIndex].Kc;
|
||||
}
|
||||
else if (setting == SET_CLOSED)
|
||||
{
|
||||
status = CLOSED;
|
||||
if (linktype == PUMP) s = 0.0;
|
||||
if (linktype == GPV) s = net->Link[linkIndex].Kc;
|
||||
}
|
||||
|
||||
// Convert units of control setting
|
||||
else
|
||||
{
|
||||
s = setting;
|
||||
switch (linktype)
|
||||
{
|
||||
case PIPE:
|
||||
case PUMP:
|
||||
if (s < 0.0) return 202;
|
||||
else if (s == 0.0) status = CLOSED;
|
||||
else status = OPEN;
|
||||
break;
|
||||
case PRV:
|
||||
case PSV:
|
||||
case PBV:
|
||||
s /= Ucf[PRESSURE];
|
||||
break;
|
||||
case FCV:
|
||||
s /= Ucf[FLOW];
|
||||
break;
|
||||
case GPV:
|
||||
if (s == 0.0) status = CLOSED;
|
||||
else if (s == 1.0) status = OPEN;
|
||||
else return 202;
|
||||
s = net->Link[linkIndex].Kc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if control level is a pressure, tank level or time value
|
||||
if (type == LOWLEVEL || type == HILEVEL)
|
||||
{
|
||||
if (nodeIndex > net->Njuncs) lvl = net->Node[nodeIndex].El + level / Ucf[ELEV];
|
||||
else lvl = net->Node[nodeIndex].El + level / Ucf[PRESSURE];
|
||||
}
|
||||
else if (type == TIMER || type == TIMEOFDAY)
|
||||
{
|
||||
t = (long)level;
|
||||
if (t < 0) return 202;
|
||||
}
|
||||
|
||||
// Assign values to control struct
|
||||
control->Link = linkIndex;
|
||||
control->Node = nodeIndex;
|
||||
control->Type = type;
|
||||
control->Status = status;
|
||||
control->Setting = s;
|
||||
control->Time = t;
|
||||
control->Grade = lvl;
|
||||
control->isEnabled = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int getcomment(Network *network, int object, int index, char *comment)
|
||||
//----------------------------------------------------------------
|
||||
// Input: object = a type of network object
|
||||
@@ -1154,6 +1424,67 @@ int setcomment(Network *network, int object, int index, const char *newcomment)
|
||||
}
|
||||
}
|
||||
|
||||
int gettag(Network *network, int object, int index, char *tag)
|
||||
//----------------------------------------------------------------
|
||||
// Input: object = a type of network object
|
||||
// index = index of the specified object
|
||||
// tag = the object's tag string
|
||||
// Output: error code
|
||||
// Purpose: gets the tag string assigned to an object.
|
||||
//----------------------------------------------------------------
|
||||
{
|
||||
char *currenttag;
|
||||
|
||||
// Get pointer to specified object's tag
|
||||
switch (object)
|
||||
{
|
||||
case NODE:
|
||||
if (index < 1 || index > network->Nnodes) return 251;
|
||||
currenttag = network->Node[index].Tag;
|
||||
break;
|
||||
case LINK:
|
||||
if (index < 1 || index > network->Nlinks) return 251;
|
||||
currenttag = network->Link[index].Tag;
|
||||
break;
|
||||
default:
|
||||
strcpy(tag, "");
|
||||
return 251;
|
||||
}
|
||||
// Copy the object's tag to the returned string
|
||||
if (currenttag) strcpy(tag, currenttag);
|
||||
else tag[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
int settag(Network *network, int object, int index, const char *newtag)
|
||||
//----------------------------------------------------------------
|
||||
// Input: object = a type of network object
|
||||
// index = index of the specified object
|
||||
// newtag = new tag string
|
||||
// Output: error code
|
||||
// Purpose: sets the tag string of an object.
|
||||
//----------------------------------------------------------------
|
||||
{
|
||||
char *tag;
|
||||
|
||||
switch (object)
|
||||
{
|
||||
case NODE:
|
||||
if (index < 1 || index > network->Nnodes) return 251;
|
||||
tag = network->Node[index].Tag;
|
||||
network->Node[index].Tag = xstrcpy(&tag, newtag, MAXMSG);
|
||||
return 0;
|
||||
|
||||
case LINK:
|
||||
if (index < 1 || index > network->Nlinks) return 251;
|
||||
tag = network->Link[index].Tag;
|
||||
network->Link[index].Tag = xstrcpy(&tag, newtag, MAXMSG);
|
||||
return 0;
|
||||
|
||||
default: return 251;
|
||||
}
|
||||
}
|
||||
|
||||
int namevalid(const char *name)
|
||||
//----------------------------------------------------------------
|
||||
// Input: name = name used to ID an object
|
||||
@@ -1219,10 +1550,10 @@ char *xstrcpy(char **s1, const char *s2, const size_t n)
|
||||
// s1 points to a valid memory location or is NULL. E.g.,
|
||||
// the following code will likely cause a segment fault:
|
||||
// char *s;
|
||||
// s = xstrcpy(s, "Some text");
|
||||
// s = xstrcpy(&s, "Some text");
|
||||
// while this would work correctly:
|
||||
// char *s = NULL;
|
||||
// s = xstrcpy(s, "Some text");
|
||||
// s = xstrcpy(&s, "Some text");
|
||||
//----------------------------------------------------------------
|
||||
{
|
||||
size_t n1 = 0, n2 = 0;
|
||||
@@ -1244,7 +1575,7 @@ char *xstrcpy(char **s1, const char *s2, const size_t n)
|
||||
if (n2 > n1) *s1 = realloc(*s1, (n2 + 1) * sizeof(char));
|
||||
|
||||
// Copy the source string into the destination string
|
||||
strncpy(*s1, s2, n2+1);
|
||||
if (*s1) strncpy(*s1, s2, n2+1);
|
||||
return *s1;
|
||||
}
|
||||
|
||||
@@ -1283,6 +1614,7 @@ double interp(int n, double x[], double y[], double xx)
|
||||
int k, m;
|
||||
double dx, dy;
|
||||
|
||||
if (n == 0) return 0.0;
|
||||
m = n - 1; // Highest data index
|
||||
if (xx <= x[0]) return (y[0]); // xx off low end of curve
|
||||
for (k = 1; k <= m; k++) // Bracket xx on curve
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: quality.c
|
||||
Description: implements EPANET's water quality engine
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 05/15/2019
|
||||
Last Updated: 02/14/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -63,8 +63,16 @@ int openqual(Project *pr)
|
||||
// Build nodal adjacency lists if they don't already exist
|
||||
if (net->Adjlist == NULL)
|
||||
{
|
||||
// Check for too few nodes & no fixed grade nodes
|
||||
if (net->Nnodes < 2) return 223;
|
||||
if (net->Ntanks == 0) return 224;
|
||||
|
||||
// Build adjacency lists
|
||||
errcode = buildadjlists(net);
|
||||
if (errcode ) return errcode;
|
||||
|
||||
// Check for unconnected nodes
|
||||
if (errcode = unlinked(pr)) return errcode;
|
||||
}
|
||||
|
||||
// Create a memory pool for water quality segments
|
||||
@@ -175,6 +183,7 @@ int initqual(Project *pr)
|
||||
qual->MassBalance.reacted = 0.0;
|
||||
qual->MassBalance.final = 0.0;
|
||||
qual->MassBalance.ratio = 0.0;
|
||||
qual->MassBalance.segCount = 0;
|
||||
return errcode;
|
||||
}
|
||||
|
||||
@@ -402,6 +411,7 @@ int closequal(Project *pr)
|
||||
FREE(qual->FlowDir);
|
||||
FREE(qual->SortedNodes);
|
||||
}
|
||||
freeadjlists(&pr->network);
|
||||
return errcode;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: qualreact.c
|
||||
Description: computes water quality reactions within pipes and tanks
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 05/15/2019
|
||||
Last Updated: 12/16/2024
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -232,7 +232,7 @@ double piperate(Project *pr, int k)
|
||||
}
|
||||
|
||||
// Compute Reynolds No.
|
||||
// Flow rate made consistent with how its saved to hydraulics file
|
||||
// Flow rate made consistent with how it's saved to hydraulics file
|
||||
q = (hyd->LinkStatus[k] <= CLOSED) ? 0.0 : hyd->LinkFlow[k];
|
||||
a = PI * d * d / 4.0; // pipe area
|
||||
u = fabs(q) / a; // flow velocity
|
||||
@@ -492,6 +492,13 @@ void tankmix1(Project *pr, int i, double vin, double win, double vnet)
|
||||
seg->v += vnet;
|
||||
seg->v = MAX(0.0, seg->v);
|
||||
tank->C = seg->c;
|
||||
|
||||
// Account for mass lost in tank overflow
|
||||
if (seg->v > tank->Vmax)
|
||||
{
|
||||
qual->MassBalance.outflow += ((seg->v) - tank->Vmax) * tank->C;
|
||||
seg->v = tank->Vmax;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,7 +520,8 @@ void tankmix2(Project *pr, int i, double vin, double win, double vnet)
|
||||
|
||||
int k;
|
||||
double vt, // Transferred volume
|
||||
vmz; // Full mixing zone volume
|
||||
vmz, // Full mixing zone volume
|
||||
vsz; // Full stagnant zone volume
|
||||
Pseg mixzone, // Mixing zone segment
|
||||
stagzone; // Stagnant zone segment
|
||||
Stank *tank = &pr->network.Tank[i];
|
||||
@@ -525,7 +533,7 @@ void tankmix2(Project *pr, int i, double vin, double win, double vnet)
|
||||
if (mixzone == NULL || stagzone == NULL) return;
|
||||
|
||||
// Full mixing zone volume
|
||||
vmz = tank->V1max;
|
||||
vmz = tank->V1frac * tank->Vmax;
|
||||
|
||||
// Tank is filling
|
||||
vt = 0.0;
|
||||
@@ -558,16 +566,31 @@ void tankmix2(Project *pr, int i, double vin, double win, double vnet)
|
||||
// Update segment volumes
|
||||
if (vt > 0.0)
|
||||
{
|
||||
mixzone->v = vmz;
|
||||
if (vnet > 0.0) stagzone->v += vt;
|
||||
else stagzone->v = MAX(0.0, ((stagzone->v) - vt));
|
||||
if (vnet > 0.0)
|
||||
{
|
||||
mixzone->v = vmz;
|
||||
stagzone->v += vt;
|
||||
|
||||
// Account for mass lost in overflow from stagnant zone
|
||||
vsz = (tank->Vmax) - vmz;
|
||||
if (stagzone->v > vsz)
|
||||
{
|
||||
qual->MassBalance.outflow += ((stagzone->v) - vsz) * stagzone->c;
|
||||
stagzone->v = vsz;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stagzone->v = MAX(0.0, ((stagzone->v) - vt));
|
||||
mixzone->v = vmz + vt + vnet;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mixzone->v += vnet;
|
||||
mixzone->v = MIN(mixzone->v, vmz);
|
||||
mixzone->v = MAX(0.0, mixzone->v);
|
||||
stagzone->v = 0.0;
|
||||
if (vmz - mixzone->v > 0.0) stagzone->v = 0.0;
|
||||
}
|
||||
|
||||
// Use quality of mixing zone to represent quality of
|
||||
@@ -612,10 +635,13 @@ void tankmix3(Project *pr, int i, double vin, double win, double vnet)
|
||||
else addseg(pr, k, vin, cin);
|
||||
}
|
||||
|
||||
// Withdraw flow from first segment
|
||||
// Find volume leaving tank, adjusted so its volume doesn't exceed Vmax
|
||||
vout = vin - vnet;
|
||||
if (tank->V >= tank->Vmax && vnet > 0.0) vout = vin;
|
||||
|
||||
// Withdraw outflow from first segment
|
||||
vsum = 0.0;
|
||||
wsum = 0.0;
|
||||
vout = vin - vnet;
|
||||
while (vout > 0.0)
|
||||
{
|
||||
seg = qual->FirstSeg[k];
|
||||
@@ -643,6 +669,10 @@ void tankmix3(Project *pr, int i, double vin, double win, double vnet)
|
||||
if (vsum > 0.0) tank->C = wsum / vsum;
|
||||
else if (qual->FirstSeg[k] == NULL) tank->C = 0.0;
|
||||
else tank->C = qual->FirstSeg[k]->c;
|
||||
|
||||
// Account for mass lost in overflow from 1st segment
|
||||
if (tank->V >= tank->Vmax && vnet > 0.0)
|
||||
qual->MassBalance.outflow += vnet * tank->C;
|
||||
}
|
||||
|
||||
|
||||
@@ -669,7 +699,7 @@ void tankmix4(Project *pr, int i, double vin, double win, double vnet)
|
||||
k = net->Nlinks + i;
|
||||
if (qual->LastSeg[k] == NULL || qual->FirstSeg[k] == NULL) return;
|
||||
|
||||
// Find inflows & outflows
|
||||
// Find inflow concentration
|
||||
if (vin > 0.0) cin = win / vin;
|
||||
else cin = 0.0;
|
||||
|
||||
@@ -687,6 +717,33 @@ void tankmix4(Project *pr, int i, double vin, double win, double vnet)
|
||||
|
||||
// Update reported tank quality
|
||||
tank->C = qual->LastSeg[k]->c;
|
||||
|
||||
// If tank full then remove vnet from leading segments
|
||||
if (tank->V >= tank->Vmax)
|
||||
{
|
||||
wsum = 0.0;
|
||||
while (vnet > 0.0)
|
||||
{
|
||||
seg = qual->FirstSeg[k];
|
||||
if (seg == NULL) break;
|
||||
vseg = seg->v; // Flow volume from leading seg
|
||||
vseg = MIN(vseg, vnet);
|
||||
if (seg == qual->LastSeg[k]) vseg = vnet;
|
||||
wsum += (seg->c) * vseg;
|
||||
vnet -= vseg; // Remaining flow volume
|
||||
if (vnet >= 0.0 && vseg >= seg->v) // Seg used up
|
||||
{
|
||||
if (seg->prev)
|
||||
{
|
||||
qual->FirstSeg[k] = seg->prev;
|
||||
seg->prev = qual->FreeSeg;
|
||||
qual->FreeSeg = seg;
|
||||
}
|
||||
}
|
||||
else seg->v -= vseg; // Remaining volume in segment
|
||||
}
|
||||
qual->MassBalance.outflow += wsum;
|
||||
}
|
||||
}
|
||||
|
||||
// If tank emptying then remove last segments until vnet consumed
|
||||
@@ -715,7 +772,7 @@ void tankmix4(Project *pr, int i, double vin, double win, double vnet)
|
||||
vsum += vseg;
|
||||
wsum += (seg->c) * vseg;
|
||||
|
||||
// ... update remiaing volume to remove
|
||||
// ... update remaining volume to remove
|
||||
vnet -= vseg;
|
||||
|
||||
// ... if no more volume left in current segment
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: qualroute.c
|
||||
Description: computes water quality transport over a single time step
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 05/15/2019
|
||||
Last Updated: 02/14/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -183,6 +183,7 @@ void evalnodeinflow(Project *pr, int k, long tstep, double *volin,
|
||||
// ... recycle the used up segment
|
||||
seg->prev = qual->FreeSeg;
|
||||
qual->FreeSeg = seg;
|
||||
qual->MassBalance.segCount--;
|
||||
}
|
||||
|
||||
// ... otherwise just reduce this segment's volume
|
||||
@@ -246,7 +247,7 @@ double findnodequal(Project *pr, int n, double volin,
|
||||
return qual->NodeQual[n];
|
||||
}
|
||||
|
||||
// Find quality contribued by any external chemical source
|
||||
// Find quality contributed by any external chemical source
|
||||
else qual->SourceQual = findsourcequal(pr, n, volout, tstep);
|
||||
if (qual->SourceQual == 0.0) return qual->NodeQual[n];
|
||||
|
||||
@@ -609,10 +610,10 @@ void initsegs(Project *pr)
|
||||
addseg(pr, k, v, c);
|
||||
|
||||
// Create a 2nd segment for the 2-compartment tank model
|
||||
if (net->Tank[j].MixModel == MIX2)
|
||||
if (!qual->OutOfMemory && net->Tank[j].MixModel == MIX2)
|
||||
{
|
||||
// ... mixing zone segment
|
||||
v1 = MAX(0, v - net->Tank[j].V1max);
|
||||
v1 = MAX(0, v - net->Tank[j].V1frac * net->Tank[j].Vmax);
|
||||
qual->FirstSeg[k]->v = v1;
|
||||
|
||||
// ... stagnant zone segment
|
||||
@@ -691,4 +692,5 @@ void addseg(Project *pr, int k, double v, double c)
|
||||
if (qual->FirstSeg[k] == NULL) qual->FirstSeg[k] = seg;
|
||||
if (qual->LastSeg[k] != NULL) qual->LastSeg[k]->prev = seg;
|
||||
qual->LastSeg[k] = seg;
|
||||
qual->MassBalance.segCount++;
|
||||
}
|
||||
|
||||
108
src/report.c
108
src/report.c
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: report.c
|
||||
Description: procedures for writing formatted text to a report file
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 07/22/2019
|
||||
Last Updated: 02/14/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -45,7 +45,7 @@ static void writeenergy(Project *);
|
||||
static int writeresults(Project *);
|
||||
static int disconnected(Project *);
|
||||
static void marknodes(Project *, int, int *, char *);
|
||||
static void getclosedlink(Project *, int, char *);
|
||||
static void getclosedlink(Project *, int, char *, int *);
|
||||
static void writelimits(Project *, int, int);
|
||||
static int checklimits(Report *, double *, int, int);
|
||||
static char *fillstr(char *, char, int);
|
||||
@@ -67,7 +67,7 @@ int clearreport(Project *pr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copyreport(Project* pr, char *filename)
|
||||
int copyreport(Project* pr, const char *filename)
|
||||
/*
|
||||
**------------------------------------------------------
|
||||
** Input: filename = name of file to copy to
|
||||
@@ -291,7 +291,7 @@ void writesummary(Project *pr)
|
||||
if (qual->Qualflag == NONE || time->Dur == 0.0) sprintf(s, FMT29);
|
||||
else if (qual->Qualflag == CHEM) sprintf(s, FMT30, qual->ChemName);
|
||||
else if (qual->Qualflag == TRACE) sprintf(s, FMT31, net->Node[qual->TraceNode].ID);
|
||||
else if (qual->Qualflag == AGE) printf(s, FMT32);
|
||||
else if (qual->Qualflag == AGE) sprintf(s, FMT32);
|
||||
writeline(pr, s);
|
||||
if (qual->Qualflag != NONE && time->Dur > 0)
|
||||
{
|
||||
@@ -422,13 +422,51 @@ void writehydstat(Project *pr, int iter, double relerr)
|
||||
writeline(pr, " ");
|
||||
}
|
||||
|
||||
void writeflowbalance(Project *pr)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: writes hydraulic flow balance ratio to report file.
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Report *rpt = &pr->report;
|
||||
char s1[MAXMSG+1];
|
||||
double ucf = pr->Ucf[FLOW];
|
||||
|
||||
snprintf(s1, MAXMSG, "Hydraulic Flow Balance (%s)", rpt->Field[DEMAND].Units);
|
||||
writeline(pr, s1);
|
||||
snprintf(s1, MAXMSG, "================================");
|
||||
writeline(pr, s1);
|
||||
snprintf(s1, MAXMSG, "Total Inflow: %12.3f", hyd->FlowBalance.totalInflow*ucf);
|
||||
writeline(pr, s1);
|
||||
snprintf(s1, MAXMSG, "Consumer Demand: %12.3f", hyd->FlowBalance.consumerDemand*ucf);
|
||||
writeline(pr, s1);
|
||||
snprintf(s1, MAXMSG, "Demand Deficit: %12.3f", hyd->FlowBalance.deficitDemand*ucf);
|
||||
writeline(pr, s1);
|
||||
snprintf(s1, MAXMSG, "Emitter Flow: %12.3f", hyd->FlowBalance.emitterDemand*ucf);
|
||||
writeline(pr, s1);
|
||||
snprintf(s1, MAXMSG, "Leakage Flow: %12.3f", hyd->FlowBalance.leakageDemand*ucf);
|
||||
writeline(pr, s1);
|
||||
snprintf(s1, MAXMSG, "Total Outflow: %12.3f", hyd->FlowBalance.totalOutflow*ucf);
|
||||
writeline(pr, s1);
|
||||
snprintf(s1, MAXMSG, "Storage Flow: %12.3f", hyd->FlowBalance.storageDemand*ucf);
|
||||
writeline(pr, s1);
|
||||
snprintf(s1, MAXMSG, "Flow Ratio: %12.3f", hyd->FlowBalance.ratio);
|
||||
writeline(pr, s1);
|
||||
snprintf(s1, MAXMSG, "================================\n");
|
||||
writeline(pr, s1);
|
||||
}
|
||||
|
||||
void writemassbalance(Project *pr)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: writes water quality mass balance ratio
|
||||
** (Outflow + Final Storage) / Inflow + Initial Storage)
|
||||
** (Outflow + Final Storage) / Inflow + Initial Storage
|
||||
** to report file.
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
@@ -463,6 +501,8 @@ void writemassbalance(Project *pr)
|
||||
writeline(pr, s1);
|
||||
snprintf(s1, MAXMSG, "Mass Ratio: %-.5f", qual->MassBalance.ratio);
|
||||
writeline(pr, s1);
|
||||
snprintf(s1, MAXMSG, "Total Segments: %d", qual->MassBalance.segCount);
|
||||
writeline(pr, s1);
|
||||
snprintf(s1, MAXMSG, "================================\n");
|
||||
writeline(pr, s1);
|
||||
}
|
||||
@@ -876,7 +916,7 @@ void writeheader(Project *pr, int type, int contin)
|
||||
}
|
||||
}
|
||||
|
||||
void writeline(Project *pr, char *s)
|
||||
void writeline(Project *pr, const char *s)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: *s = text string
|
||||
@@ -886,6 +926,12 @@ void writeline(Project *pr, char *s)
|
||||
*/
|
||||
{
|
||||
Report *rpt = &pr->report;
|
||||
|
||||
if (pr->report.reportCallback != NULL)
|
||||
{
|
||||
pr->report.reportCallback(pr->report.reportCallbackUserData, pr, s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rpt->RptFile == NULL) return;
|
||||
if (rpt->Rptflag)
|
||||
@@ -1281,7 +1327,7 @@ int disconnected(Project *pr)
|
||||
clocktime(rpt->Atime, time->Htime));
|
||||
writeline(pr, pr->Msg);
|
||||
}
|
||||
getclosedlink(pr, j, marked);
|
||||
getclosedlink(pr, j, marked, nodelist);
|
||||
}
|
||||
|
||||
// Free allocated memory
|
||||
@@ -1344,11 +1390,12 @@ void marknodes(Project *pr, int m, int *nodelist, char *marked)
|
||||
}
|
||||
}
|
||||
|
||||
void getclosedlink(Project *pr, int i, char *marked)
|
||||
void getclosedlink(Project *pr, int i, char *marked, int *stack)
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
** Input: i = junction index
|
||||
** marked[] = marks nodes already examined
|
||||
** stack[] = stack to hold nodes to examine
|
||||
** Output: None.
|
||||
** Purpose: Determines if a closed link connects to junction i.
|
||||
**----------------------------------------------------------------
|
||||
@@ -1359,20 +1406,41 @@ void getclosedlink(Project *pr, int i, char *marked)
|
||||
int j, k;
|
||||
Padjlist alink;
|
||||
|
||||
int top = 0;
|
||||
|
||||
// Mark the current junction as examined and push onto stack
|
||||
marked[i] = 2;
|
||||
for (alink = net->Adjlist[i]; alink != NULL; alink = alink->next)
|
||||
{
|
||||
k = alink->link;
|
||||
j = alink->node;
|
||||
if (marked[j] == 2) continue;
|
||||
if (marked[j] == 1)
|
||||
{
|
||||
sprintf(pr->Msg, WARN03c, net->Link[k].ID);
|
||||
writeline(pr, pr->Msg);
|
||||
return;
|
||||
stack[top] = i;
|
||||
|
||||
while (top >= 0) {
|
||||
i = stack[top--];
|
||||
alink = net->Adjlist[i];
|
||||
|
||||
// Iterate through each link adjacent to the current node
|
||||
while (alink != NULL) {
|
||||
k = alink->link;
|
||||
j = alink->node;
|
||||
|
||||
// Skip nodes that have already been examined
|
||||
if (marked[j] == 2) {
|
||||
alink = alink->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If a closed link is found, return and display a warning message
|
||||
if (marked[j] == 1) {
|
||||
sprintf(pr->Msg, WARN03c, net->Link[k].ID);
|
||||
writeline(pr, pr->Msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark the node as examined and push it onto the stack
|
||||
marked[j] = 2;
|
||||
stack[++top] = j;
|
||||
alink = alink->next;
|
||||
}
|
||||
else getclosedlink(pr, j, marked);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void writelimits(Project *pr, int j1, int j2)
|
||||
|
||||
150
src/rules.c
150
src/rules.c
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: rules.c
|
||||
Description: implements rule-based controls
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 05/15/2019
|
||||
Last Updated: 02/11/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -32,10 +32,11 @@ enum Rulewords {
|
||||
r_THEN,
|
||||
r_ELSE,
|
||||
r_PRIORITY,
|
||||
r_DISABLED,
|
||||
r_ERROR
|
||||
};
|
||||
char *Ruleword[] = {w_RULE, w_IF, w_AND, w_OR,
|
||||
w_THEN, w_ELSE, w_PRIORITY, NULL};
|
||||
w_THEN, w_ELSE, w_PRIORITY, w_DISABLED, NULL};
|
||||
|
||||
enum Varwords {
|
||||
r_DEMAND,
|
||||
@@ -273,6 +274,16 @@ int ruledata(Project *pr)
|
||||
err = newpriority(pr);
|
||||
break;
|
||||
|
||||
case r_DISABLED:
|
||||
if (rules->RuleState != r_THEN && rules->RuleState != r_ELSE &&
|
||||
rules->RuleState != r_PRIORITY)
|
||||
{
|
||||
err = 221;
|
||||
break;
|
||||
}
|
||||
net->Rule[net->Nrules].isEnabled = FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
err = 201;
|
||||
}
|
||||
@@ -404,7 +415,7 @@ void adjustrules(Project *pr, int objtype, int index)
|
||||
}
|
||||
}
|
||||
|
||||
void adjusttankrules(Project *pr)
|
||||
void adjusttankrules(Project *pr, int ndiff)
|
||||
//-----------------------------------------------------------
|
||||
// Adjusts tank indices in rule premises.
|
||||
//-----------------------------------------------------------
|
||||
@@ -420,7 +431,8 @@ void adjusttankrules(Project *pr)
|
||||
p = net->Rule[i].Premises;
|
||||
while (p != NULL)
|
||||
{
|
||||
if (p->object == r_NODE && p->index > njuncs) p->index++;
|
||||
if (p->object == r_NODE && p->index > njuncs)
|
||||
p->index += ndiff;
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
@@ -472,7 +484,7 @@ int writerule(Project *pr, FILE *f, int ruleIndex)
|
||||
Srule *rule = &net->Rule[ruleIndex];
|
||||
Spremise *p;
|
||||
Saction *a;
|
||||
|
||||
|
||||
// Write each premise clause to the file
|
||||
p = rule->Premises;
|
||||
fprintf(f, "\nIF ");
|
||||
@@ -527,6 +539,11 @@ int checkrules(Project *pr, long dt)
|
||||
rules->ActionList = NULL;
|
||||
for (i = 1; i <= net->Nrules; i++)
|
||||
{
|
||||
// skip if the rule is disabled
|
||||
if (!net->Rule[i].isEnabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// If premises true, add THEN clauses to action list
|
||||
if (evalpremises(pr, i) == TRUE)
|
||||
{
|
||||
@@ -549,6 +566,126 @@ int checkrules(Project *pr, long dt)
|
||||
return actionCount;
|
||||
}
|
||||
|
||||
void updateruleunits(Project *pr, double dcf, double pcf, double hcf, double qcf)
|
||||
//-----------------------------------------------------------
|
||||
// Updates the units of a rule's premises and actions.
|
||||
//-----------------------------------------------------------
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Slink *Link = net->Link;
|
||||
|
||||
int i, k;
|
||||
double x;
|
||||
Spremise *p;
|
||||
Saction *a;
|
||||
|
||||
for (i = 1; i <= net->Nrules; i++)
|
||||
{
|
||||
p = net->Rule[i].Premises;
|
||||
while (p != NULL)
|
||||
{
|
||||
|
||||
switch (p->variable)
|
||||
{
|
||||
case r_DEMAND:
|
||||
p->value *= dcf;
|
||||
break;
|
||||
|
||||
case r_HEAD:
|
||||
case r_GRADE:
|
||||
p->value *= hcf;
|
||||
break;
|
||||
|
||||
case r_PRESSURE:
|
||||
p->value *= pcf;
|
||||
break;
|
||||
|
||||
case r_LEVEL:
|
||||
p->value *= hcf;
|
||||
break;
|
||||
|
||||
case r_FLOW:
|
||||
p->value *= qcf;
|
||||
break;
|
||||
|
||||
case r_SETTING:
|
||||
|
||||
switch (Link[p->index].Type)
|
||||
{
|
||||
case PRV:
|
||||
case PSV:
|
||||
case PBV:
|
||||
p->value *= pcf;
|
||||
break;
|
||||
case FCV:
|
||||
p->value *= qcf;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
a = net->Rule[i].ThenActions;
|
||||
while (a != NULL)
|
||||
{
|
||||
k = a->link;
|
||||
x = a->setting;
|
||||
|
||||
// Change link's setting
|
||||
if (x != MISSING)
|
||||
{
|
||||
switch (net->Link[k].Type)
|
||||
{
|
||||
case PRV:
|
||||
case PSV:
|
||||
case PBV:
|
||||
a->setting *= pcf;
|
||||
break;
|
||||
case FCV:
|
||||
a->setting *= qcf;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
a = net->Rule[i].ElseActions;
|
||||
while (a != NULL)
|
||||
{
|
||||
k = a->link;
|
||||
x = a->setting;
|
||||
|
||||
// Change link's setting
|
||||
if (x != MISSING)
|
||||
{
|
||||
switch (net->Link[k].Type)
|
||||
{
|
||||
case PRV:
|
||||
case PSV:
|
||||
case PBV:
|
||||
a->setting *= pcf;
|
||||
break;
|
||||
case FCV:
|
||||
a->setting *= qcf;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void newrule(Project *pr)
|
||||
//----------------------------------------------------------
|
||||
// Adds a new rule to the project
|
||||
@@ -564,6 +701,7 @@ void newrule(Project *pr)
|
||||
rule->ThenActions = NULL;
|
||||
rule->ElseActions = NULL;
|
||||
rule->priority = 0.0;
|
||||
rule->isEnabled = TRUE;
|
||||
pr->rules.LastPremise = NULL;
|
||||
pr->rules.LastThenAction = NULL;
|
||||
pr->rules.LastElseAction = NULL;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: smatrix.c
|
||||
Description: solves a sparse set of linear equations
|
||||
Authors: see AUTHORS
|
||||
@@ -48,8 +48,8 @@ static int paralink(Network *, Smatrix *, int, int, int k);
|
||||
static void xparalinks(Network *);
|
||||
static int reordernodes(Project *);
|
||||
static int factorize(Project *);
|
||||
static int growlist(Project *, int);
|
||||
static int newlink(Project *, Padjlist);
|
||||
static int growlist(Project *, int, int *);
|
||||
static int newlink(Project *, Padjlist, int *);
|
||||
static int linked(Network *, int, int);
|
||||
static int addlink(Network *, int, int, int);
|
||||
static int storesparse(Project *, int);
|
||||
@@ -443,8 +443,8 @@ int factorize(Project *pr)
|
||||
Padjlist alink;
|
||||
|
||||
// Find degree of each junction node
|
||||
sm->Degree = (int *)calloc(net->Nnodes + 1, sizeof(int));
|
||||
if (sm->Degree == NULL) return 101;
|
||||
int *degree = (int *)calloc(net->Nnodes + 1, sizeof(int));
|
||||
if (degree == NULL) return 101;
|
||||
|
||||
// NOTE: For purposes of node re-ordering, Tanks (nodes with
|
||||
// indexes above Njuncs) have zero degree of adjacency.
|
||||
@@ -453,7 +453,7 @@ int factorize(Project *pr)
|
||||
{
|
||||
for (alink = net->Adjlist[k]; alink != NULL; alink = alink->next)
|
||||
{
|
||||
if (alink->node > 0) sm->Degree[k]++;
|
||||
if (alink->node > 0) degree[k]++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,19 +463,19 @@ int factorize(Project *pr)
|
||||
for (k = 1; k <= net->Njuncs; k++) // Examine each junction
|
||||
{
|
||||
knode = sm->Order[k]; // Re-ordered index
|
||||
if (!growlist(pr, knode)) // Augment adjacency list
|
||||
if (!growlist(pr, knode, degree)) // Augment adjacency list
|
||||
{
|
||||
errcode = 101;
|
||||
break;
|
||||
}
|
||||
sm->Degree[knode] = 0; // In-activate node
|
||||
degree[knode] = 0; // In-activate node
|
||||
}
|
||||
free(sm->Degree);
|
||||
free(degree);
|
||||
return errcode;
|
||||
}
|
||||
|
||||
|
||||
int growlist(Project *pr, int knode)
|
||||
int growlist(Project *pr, int knode, int *degree)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: knode = node index
|
||||
@@ -496,10 +496,10 @@ int growlist(Project *pr, int knode)
|
||||
for (alink = net->Adjlist[knode]; alink != NULL; alink = alink -> next)
|
||||
{
|
||||
node = alink->node; // End node of connecting link
|
||||
if (node > 0 && sm->Degree[node] > 0) // End node is active
|
||||
if (node > 0 && degree[node] > 0) // End node is active
|
||||
{
|
||||
sm->Degree[node]--; // Reduce degree of adjacency
|
||||
if (!newlink(pr, alink)) // Add to adjacency list
|
||||
degree[node]--; // Reduce degree of adjacency
|
||||
if (!newlink(pr, alink, degree)) // Add to adjacency list
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -509,7 +509,7 @@ int growlist(Project *pr, int knode)
|
||||
}
|
||||
|
||||
|
||||
int newlink(Project *pr, Padjlist alink)
|
||||
int newlink(Project *pr, Padjlist alink, int *degree)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: alink = element of node's adjacency list
|
||||
@@ -533,7 +533,7 @@ int newlink(Project *pr, Padjlist alink)
|
||||
|
||||
// If jnode still active, and inode not connected to jnode,
|
||||
// then add a new connection between inode and jnode.
|
||||
if (jnode > 0 && sm->Degree[jnode] > 0) // jnode still active
|
||||
if (jnode > 0 && degree[jnode] > 0) // jnode still active
|
||||
{
|
||||
if (!linked(net, inode, jnode)) // inode not linked to jnode
|
||||
{
|
||||
@@ -545,8 +545,8 @@ int newlink(Project *pr, Padjlist alink)
|
||||
// reflect the new connection.
|
||||
if (!addlink(net, inode, jnode, sm->Ncoeffs)) return 0;
|
||||
if (!addlink(net, jnode, inode, sm->Ncoeffs)) return 0;
|
||||
sm->Degree[inode]++;
|
||||
sm->Degree[jnode]++;
|
||||
degree[inode]++;
|
||||
degree[jnode]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -651,7 +651,7 @@ int sortsparse(Smatrix *sm, int n)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: n = number of rows in solution matrix
|
||||
** Output: returns eror code
|
||||
** Output: returns error code
|
||||
** Purpose: puts row indexes in ascending order in NZSUB
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
@@ -834,7 +834,7 @@ int linsolve(Smatrix *sm, int n)
|
||||
}
|
||||
} // next j
|
||||
|
||||
// Foward substitution
|
||||
// Forward substitution
|
||||
for (j = 1; j <= n; j++)
|
||||
{
|
||||
bj = B[j]/Aii[j];
|
||||
|
||||
21
src/text.h
21
src/text.h
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: text.h
|
||||
Description: string constants used throughout EPANET
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 07/15/2019
|
||||
Last Updated: 03/10/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#define w_FCV "FCV"
|
||||
#define w_TCV "TCV"
|
||||
#define w_GPV "GPV"
|
||||
#define w_PCV "PCV"
|
||||
|
||||
#define w_OPEN "OPEN"
|
||||
#define w_CLOSED "CLOSED"
|
||||
@@ -51,9 +52,6 @@
|
||||
#define w_IS "IS"
|
||||
#define w_NOT "NOT"
|
||||
|
||||
#define w_ADD "ADD"
|
||||
#define w_MULTIPLY "MULT"
|
||||
|
||||
#define w_LIMITING "LIMIT"
|
||||
#define w_ORDER "ORDER"
|
||||
#define w_GLOBAL "GLOB"
|
||||
@@ -86,11 +84,14 @@
|
||||
#define w_MLD "MLD"
|
||||
#define w_CMH "CMH"
|
||||
#define w_CMD "CMD"
|
||||
#define w_CMS "CMS"
|
||||
#define w_SI "SI"
|
||||
|
||||
#define w_PSI "PSI"
|
||||
#define w_KPA "KPA"
|
||||
#define w_METERS "METERS"
|
||||
#define w_BAR "BAR"
|
||||
#define w_FEET "FEET"
|
||||
|
||||
#define w_ELEV "ELEV"
|
||||
#define w_DEMAND "DEMAND"
|
||||
@@ -130,6 +131,8 @@
|
||||
#define w_SEGMENTS "SEGM"
|
||||
#define w_TOLERANCE "TOLER"
|
||||
#define w_EMITTER "EMIT"
|
||||
#define w_BACKFLOW "BACK"
|
||||
#define w_ALLOWED "ALLOW"
|
||||
|
||||
#define w_PRICE "PRICE"
|
||||
#define w_DMNDCHARGE "DEMAN"
|
||||
@@ -150,6 +153,9 @@
|
||||
#define w_REQUIRED "REQ"
|
||||
#define w_EXPONENT "EXP"
|
||||
|
||||
#define w_AREA "AREA"
|
||||
#define w_EXPAN "EXPAN"
|
||||
|
||||
#define w_SECONDS "SEC"
|
||||
#define w_MINUTES "MIN"
|
||||
#define w_HOURS "HOU"
|
||||
@@ -192,6 +198,7 @@
|
||||
#define w_THEN "THEN"
|
||||
#define w_ELSE "ELSE"
|
||||
#define w_PRIORITY "PRIO"
|
||||
#define w_DISABLED "DISABLED"
|
||||
|
||||
// ------ Input File Section Names ------------------------
|
||||
|
||||
@@ -207,6 +214,7 @@
|
||||
#define s_DEMANDS "[DEMANDS]"
|
||||
#define s_SOURCES "[SOURCES]"
|
||||
#define s_EMITTERS "[EMITTERS]"
|
||||
#define s_LEAKAGE "[LEAKAGE]"
|
||||
#define s_PATTERNS "[PATTERNS]"
|
||||
#define s_CURVES "[CURVES]"
|
||||
#define s_QUALITY "[QUALITY]"
|
||||
@@ -234,6 +242,7 @@
|
||||
#define u_IMGD "Imgd"
|
||||
#define u_LPS "L/s"
|
||||
#define u_LPM "Lpm"
|
||||
#define u_CMS "m3/s"
|
||||
#define u_CMH "m3/h"
|
||||
#define u_CMD "m3/d"
|
||||
#define u_MLD "ML/d"
|
||||
@@ -263,6 +272,8 @@
|
||||
#define c_PUMP "PUMP"
|
||||
#define c_EFFIC "EFFIC"
|
||||
#define c_VOLUME "VOLUME"
|
||||
#define c_VALVE "VALVE"
|
||||
#define c_GENERIC "GENERIC"
|
||||
|
||||
//------- Text Phrases ------------------------------------
|
||||
|
||||
|
||||
92
src/types.h
92
src/types.h
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: types.h
|
||||
Description: symbolic constants and data types used throughout EPANET
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 10/29/2019
|
||||
Last Updated: 04/19/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -31,7 +31,7 @@ typedef int INT4;
|
||||
Various constants
|
||||
----------------------------------------------
|
||||
*/
|
||||
#define CODEVERSION 20200
|
||||
#define CODEVERSION 20300
|
||||
#define MAGICNUMBER 516114521
|
||||
#define ENGINE_VERSION 201 // Used for binary hydraulics file
|
||||
#define EOFMARK 0x1A // Use 0x04 for UNIX systems
|
||||
@@ -48,6 +48,9 @@ typedef int INT4;
|
||||
#define BIG 1.E10
|
||||
#define TINY 1.E-6
|
||||
#define MISSING -1.E10 // Missing value indicator
|
||||
#define SET_CLOSED -1.E10 // Link set closed indicator
|
||||
#define SET_OPEN 1.E10 // Link set open indicator
|
||||
|
||||
#define DIFFUS 1.3E-8 // Diffusivity of chlorine
|
||||
// @ 20 deg C (sq ft/sec)
|
||||
#define VISCOS 1.1E-5 // Kinematic viscosity of water
|
||||
@@ -71,6 +74,7 @@ typedef int INT4;
|
||||
#define IMGDperCFS 0.5382
|
||||
#define LPSperCFS 28.317
|
||||
#define LPMperCFS 1699.0
|
||||
#define CMSperCFS 0.028317
|
||||
#define CMHperCFS 101.94
|
||||
#define CMDperCFS 2446.6
|
||||
#define MLDperCFS 2.4466
|
||||
@@ -79,6 +83,7 @@ typedef int INT4;
|
||||
#define MperFT 0.3048
|
||||
#define PSIperFT 0.4333
|
||||
#define KPAperPSI 6.895
|
||||
#define BARperPSI 0.068948
|
||||
#define KWperHP 0.7457
|
||||
#define SECperDAY 86400
|
||||
|
||||
@@ -145,7 +150,8 @@ typedef enum {
|
||||
PBV, // pressure breaker valve
|
||||
FCV, // flow control valve
|
||||
TCV, // throttle control valve
|
||||
GPV // general purpose valve
|
||||
GPV, // general purpose valve
|
||||
PCV // positional control valve
|
||||
} LinkType;
|
||||
|
||||
typedef enum {
|
||||
@@ -166,7 +172,8 @@ typedef enum {
|
||||
PUMP_CURVE, // pump curve
|
||||
EFFIC_CURVE, // efficiency curve
|
||||
HLOSS_CURVE, // head loss curve
|
||||
GENERIC_CURVE // generic curve
|
||||
GENERIC_CURVE, // generic curve
|
||||
VALVE_CURVE // positional valve loss curve
|
||||
} CurveType;
|
||||
|
||||
typedef enum {
|
||||
@@ -225,13 +232,17 @@ typedef enum {
|
||||
LPM, // liters per minute
|
||||
MLD, // megaliters per day
|
||||
CMH, // cubic meters per hour
|
||||
CMD // cubic meters per day
|
||||
CMD, // cubic meters per day
|
||||
CMS // cubic meters per second
|
||||
} FlowUnitsType;
|
||||
|
||||
typedef enum {
|
||||
PSI, // pounds per square inch
|
||||
KPA, // kiloPascals
|
||||
METERS // meters
|
||||
METERS, // meters
|
||||
BAR, // bar
|
||||
FEET, // feet
|
||||
DEFAULTUNIT // default based on unit system (SI or US)
|
||||
} PressureUnitsType;
|
||||
|
||||
typedef enum {
|
||||
@@ -287,7 +298,7 @@ typedef enum {
|
||||
_VALVES, _CONTROLS, _RULES, _DEMANDS, _SOURCES, _EMITTERS,
|
||||
_PATTERNS, _CURVES, _QUALITY, _STATUS, _ROUGHNESS, _ENERGY,
|
||||
_REACTIONS, _MIXING, _REPORT, _TIMES, _OPTIONS,
|
||||
_COORDS, _VERTICES, _LABELS, _BACKDROP, _TAGS, _END
|
||||
_COORDS, _VERTICES, _LABELS, _BACKDROP, _TAGS, _LEAKAGE, _END
|
||||
} SectionType;
|
||||
|
||||
typedef enum {
|
||||
@@ -355,6 +366,8 @@ typedef struct // Energy Usage Object
|
||||
double KwHrs; // total kw-hrs consumed
|
||||
double MaxKwatts; // max. kw consumed
|
||||
double TotalCost; // total pumping cost
|
||||
double CurrentPower; // current pump power (kw)
|
||||
double CurrentEffic; // current pump efficiency
|
||||
} Senergy;
|
||||
|
||||
struct Ssource // Water Quality Source Object
|
||||
@@ -389,6 +402,7 @@ typedef struct // Node Object
|
||||
int ResultIndex; // saved result index
|
||||
NodeType Type; // node type
|
||||
char *Comment; // node comment
|
||||
char *Tag; // optional category tag
|
||||
} Snode;
|
||||
|
||||
typedef struct // Link Object
|
||||
@@ -398,18 +412,22 @@ typedef struct // Link Object
|
||||
int N2; // end node index
|
||||
double Diam; // diameter
|
||||
double Len; // length
|
||||
double Kc; // roughness
|
||||
double Kc; // pipe roughness, pump speed, valve setting
|
||||
double Km; // minor loss coeff.
|
||||
double Kb; // bulk react. coeff.
|
||||
double Kw; // wall react. coef.
|
||||
double R; // flow resistance
|
||||
double Rc; // reaction coeff.
|
||||
double LeakArea; // leak area (sq mm per 100 pipe length units
|
||||
double LeakExpan; // leak expansion (sq mm per unit of head)
|
||||
LinkType Type; // link type
|
||||
StatusType Status; // initial status
|
||||
StatusType InitStatus; // initial status
|
||||
double InitSetting; // initial setting
|
||||
Pvertices Vertices; // internal vertex coordinates
|
||||
int Rpt; // reporting flag
|
||||
int ResultIndex; // saved result index
|
||||
char *Comment; // link comment
|
||||
char *Tag; // optional category tag
|
||||
} Slink;
|
||||
|
||||
typedef struct // Tank Object
|
||||
@@ -428,7 +446,7 @@ typedef struct // Tank Object
|
||||
int Pat; // fixed grade time pattern
|
||||
int Vcurve; // volume v. elev. curve index
|
||||
MixType MixModel; // type of mixing model
|
||||
double V1max; // mixing compartment size
|
||||
double V1frac; // mixing compartment fraction
|
||||
int CanOverflow; // tank can overflow or not
|
||||
} Stank;
|
||||
|
||||
@@ -453,6 +471,7 @@ typedef struct // Pump Object
|
||||
typedef struct // Valve Object
|
||||
{
|
||||
int Link; // link index of valve
|
||||
int Curve; // positional loss coeff. curve
|
||||
} Svalve;
|
||||
|
||||
typedef struct // Control Statement
|
||||
@@ -464,6 +483,7 @@ typedef struct // Control Statement
|
||||
double Setting; // new link setting
|
||||
StatusType Status; // new link status
|
||||
ControlType Type; // control type
|
||||
int isEnabled; // control enabled?
|
||||
} Scontrol;
|
||||
|
||||
typedef struct // Field Object of Report Table
|
||||
@@ -515,6 +535,7 @@ typedef struct // Control Rule Structure
|
||||
{
|
||||
char label[MAXID+1]; // rule label
|
||||
double priority; // priority level
|
||||
int isEnabled; // is the rule enabled?
|
||||
Spremise *Premises; // list of premises
|
||||
Saction *ThenActions; // list of THEN actions
|
||||
Saction *ElseActions; // list of ELSE actions
|
||||
@@ -535,8 +556,29 @@ typedef struct // Mass Balance Components
|
||||
double reacted; // mass reacted in system
|
||||
double final; // final mass in system
|
||||
double ratio; // ratio of mass added to mass lost
|
||||
int segCount; // total number of pipe segments used
|
||||
} SmassBalance;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double totalInflow;
|
||||
double totalOutflow;
|
||||
double consumerDemand;
|
||||
double emitterDemand;
|
||||
double leakageDemand;
|
||||
double deficitDemand;
|
||||
double storageDemand;
|
||||
double ratio;
|
||||
} SflowBalance;
|
||||
|
||||
typedef struct // Node Leakage Object
|
||||
{
|
||||
double qfa; // fixed area leakage flow
|
||||
double qva; // variable area leakage flow
|
||||
double cfa; // fixed area leakage coeff.
|
||||
double cva; // variable area leakage coeff.
|
||||
} Sleakage;
|
||||
|
||||
/*
|
||||
------------------------------------------------------
|
||||
Wrapper Data Structures
|
||||
@@ -571,8 +613,7 @@ typedef struct {
|
||||
ErrTok, // Index of error-producing token
|
||||
Unitsflag, // Unit system flag
|
||||
Flowflag, // Flow units flag
|
||||
Pressflag, // Pressure units flag
|
||||
DefPat; // Default demand pattern
|
||||
Pressflag; // Pressure units flag
|
||||
|
||||
Spattern *PrevPat; // Previous pattern processed
|
||||
Scurve *PrevCurve; // Previous curve processed
|
||||
@@ -628,7 +669,10 @@ typedef struct {
|
||||
Rpt2Fname[MAXFNAME+1], // Secondary report file name
|
||||
DateStamp[26]; // Current date & time
|
||||
|
||||
SField Field[MAXVAR]; // Output reporting fields
|
||||
SField Field[MAXVAR]; // Output reporting fields
|
||||
|
||||
void (*reportCallback)(void*,void*,const char*); // user-supplied reporting callback
|
||||
void *reportCallbackUserData; // user-supplied reporting context
|
||||
|
||||
} Report;
|
||||
|
||||
@@ -688,7 +732,6 @@ typedef struct {
|
||||
*XLNZ, // Start position of each column in NZSUB
|
||||
*NZSUB, // Row index of each coeff. in each column
|
||||
*LNZ, // Position of each coeff. in Aij array
|
||||
*Degree, // Number of links adjacent to each node
|
||||
*link, // Array used by linear eqn. solver
|
||||
*first; // Array used by linear eqn. solver
|
||||
|
||||
@@ -699,9 +742,11 @@ typedef struct {
|
||||
|
||||
double
|
||||
*NodeHead, // Node hydraulic heads
|
||||
*NodeDemand, // Node demand + emitter flows
|
||||
*DemandFlow, // Work array of demand flows
|
||||
*EmitterFlow, // Emitter outflows
|
||||
*NodeDemand, // Node total demand (consumer + emitter + leakage)
|
||||
*FullDemand, // Required consumer demand
|
||||
*DemandFlow, // Demand flow from nodes
|
||||
*EmitterFlow, // Emitter flow from nodes
|
||||
*LeakageFlow, // Leakage flow from nodes
|
||||
*LinkFlow, // Link flows
|
||||
*LinkSetting, // Link settings
|
||||
Htol, // Hydraulic head tolerance
|
||||
@@ -728,15 +773,18 @@ typedef struct {
|
||||
MaxHeadError, // Max. error for link head loss
|
||||
MaxFlowChange, // Max. change in link flow
|
||||
DemandReduction, // % demand reduction at pressure deficient nodes
|
||||
LeakageLoss, // % system leakage loss
|
||||
RelaxFactor, // Relaxation factor for flow updating
|
||||
*P, // Inverse of head loss derivatives
|
||||
*Y, // Flow correction factors
|
||||
*Xflow; // Inflow - outflow at each node
|
||||
|
||||
int
|
||||
DefPat, // Default demand pattern
|
||||
Epat, // Energy cost time pattern
|
||||
DemandModel, // Fixed or pressure dependent
|
||||
Formflag, // Head loss formula flag
|
||||
EmitBackFlag, // Emitter backflow flag
|
||||
Iterations, // Number of hydraulic trials taken
|
||||
MaxIter, // Max. hydraulic trials allowed
|
||||
ExtraIter, // Extra hydraulic trials
|
||||
@@ -744,12 +792,18 @@ typedef struct {
|
||||
MaxCheck, // Hydraulic trials limit on status checks
|
||||
OpenHflag, // Hydraulic system opened flag
|
||||
Haltflag, // Flag to halt simulation
|
||||
DeficientNodes; // Number of pressure deficient nodes
|
||||
DeficientNodes, // Number of pressure deficient nodes
|
||||
HasLeakage; // TRUE if project has non-zero leakage parameters
|
||||
|
||||
Sleakage *Leakage; // Array of node leakage parameters
|
||||
|
||||
StatusType
|
||||
*LinkStatus, // Link status
|
||||
*OldStatus; // Previous link/tank status
|
||||
|
||||
SflowBalance
|
||||
FlowBalance; // Flow balance components
|
||||
|
||||
Smatrix smatrix; // Sparse matrix storage
|
||||
|
||||
} Hydraul;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: util/cstr_helper.c
|
||||
Description: Provides C string helper functions
|
||||
Authors: see AUTHORS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: util/cstr_helper.h
|
||||
Description: Provides C string helper functions
|
||||
Authors: see AUTHORS
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: util/errormanager.c
|
||||
Description: Provides a simple interface for managing errors
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 04/02/2019
|
||||
Last Updated: 08/02/2023
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -36,6 +36,7 @@ error_handle_t *create_error_manager(void (*p_error_message)(int, char*, int))
|
||||
{
|
||||
error_handle_t *error_handle;
|
||||
error_handle = (error_handle_t*)calloc(1, sizeof(error_handle_t));
|
||||
if (error_handle == NULL) return NULL;
|
||||
|
||||
error_handle->p_msg_lookup = p_error_message;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: util/errormanager.h
|
||||
Description: Provides a simple interface for managing errors
|
||||
Authors: see AUTHORS
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: util/filemanager.c
|
||||
Description: Provides a simple interface for managing files
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 04/01/2019
|
||||
Last Updated: 08/02/2023
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -41,6 +41,7 @@ file_handle_t *create_file_manager() {
|
||||
|
||||
file_handle_t *file_handle;
|
||||
file_handle = (file_handle_t *)calloc(1, sizeof(file_handle_t));
|
||||
if (file_handle == NULL) return NULL;
|
||||
|
||||
file_handle->filename = NULL;
|
||||
file_handle->file = NULL;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: util/filemanager.h
|
||||
Description: Provides a simple interface for managing files
|
||||
Authors: see AUTHORS
|
||||
|
||||
408
src/validate.c
Normal file
408
src/validate.c
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.3
|
||||
Module: validate.c
|
||||
Description: validates project data
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 03/18/2024
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "funcs.h"
|
||||
#include "text.h"
|
||||
|
||||
// Exported functions
|
||||
int validateproject(Project *);
|
||||
void reindextanks(Project *);
|
||||
|
||||
int validatetanks(Project *pr)
|
||||
/*
|
||||
**-------------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns 1 if successful, 0 if not
|
||||
** Purpose: checks for valid tank levels.
|
||||
**-------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
int i, j, n, result = 1, levelerr;
|
||||
char errmsg[MAXMSG+1] = "";
|
||||
Stank *tank;
|
||||
Scurve *curve;
|
||||
double elev;
|
||||
|
||||
for (j = 1; j <= net->Ntanks; j++)
|
||||
{
|
||||
tank = &net->Tank[j];
|
||||
if (tank->A == 0.0) continue; // Skip reservoirs
|
||||
|
||||
// Check for valid lower/upper tank levels
|
||||
levelerr = 0;
|
||||
if (tank->H0 > tank->Hmax ||
|
||||
tank->Hmin > tank->Hmax ||
|
||||
tank->H0 < tank->Hmin
|
||||
) levelerr = 1;
|
||||
|
||||
// Check that tank heights are within volume curve
|
||||
elev = net->Node[tank->Node].El;
|
||||
i = tank->Vcurve;
|
||||
if (i > 0)
|
||||
{
|
||||
curve = &net->Curve[i];
|
||||
n = curve->Npts - 1;
|
||||
if ((tank->Hmin - elev) * pr->Ucf[ELEV] < curve->X[0] - TINY ||
|
||||
(tank->Hmax - elev) * pr->Ucf[ELEV] > curve->X[n] + TINY)
|
||||
{
|
||||
levelerr = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Report error in levels if found
|
||||
if (levelerr)
|
||||
{
|
||||
sprintf(pr->Msg, "Error 225: %s node %s", geterrmsg(225, errmsg),
|
||||
net->Node[tank->Node].ID);
|
||||
writeline(pr, pr->Msg);
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int validatepatterns(Project *pr)
|
||||
/*
|
||||
**-------------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns 1 if successful, 0 if not
|
||||
** Purpose: checks if time patterns have data.
|
||||
**-------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
int j, result = 1;
|
||||
char errmsg[MAXMSG+1] = "";
|
||||
|
||||
if (pr->network.Pattern != NULL)
|
||||
{
|
||||
for (j = 0; j <= pr->network.Npats; j++)
|
||||
{
|
||||
if (pr->network.Pattern[j].Length == 0)
|
||||
{
|
||||
sprintf(pr->Msg, "Error 232: %s %s", geterrmsg(232, errmsg),
|
||||
pr->network.Pattern[j].ID);
|
||||
writeline(pr, pr->Msg);
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int validatecurves(Project *pr)
|
||||
/*
|
||||
**-------------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns 1 if successful, 0 if not
|
||||
** Purpose: checks if data curves have data.
|
||||
**-------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i, j, npts, result = 1;
|
||||
char errmsg[MAXMSG+1] = "";
|
||||
Scurve *curve;
|
||||
|
||||
if (pr->network.Curve != NULL)
|
||||
{
|
||||
for (j = 1; j <= pr->network.Ncurves; j++)
|
||||
{
|
||||
// Check that curve has data
|
||||
curve = &pr->network.Curve[j];
|
||||
npts = curve->Npts;
|
||||
if (npts == 0)
|
||||
{
|
||||
sprintf(pr->Msg, "Error 231: %s %s", geterrmsg(231, errmsg),
|
||||
curve->ID);
|
||||
writeline(pr, pr->Msg);
|
||||
result = 0;
|
||||
}
|
||||
|
||||
// Check that x values are increasing
|
||||
for (i = 1; i < npts; i++)
|
||||
{
|
||||
if (curve->X[i-1] >= curve->X[i])
|
||||
{
|
||||
sprintf(pr->Msg, "Error 230: %s %s", geterrmsg(230, errmsg),
|
||||
curve->ID);
|
||||
writeline(pr, pr->Msg);
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int powerfuncpump(double h0, double h1, double h2, double q1, double q2,
|
||||
double *a, double *b, double *c)
|
||||
/*
|
||||
**---------------------------------------------------------
|
||||
** Input: h0 = shutoff head
|
||||
** h1 = design head
|
||||
** h2 = head at max. flow
|
||||
** q1 = design flow
|
||||
** q2 = max. flow
|
||||
** Output: *a, *b, *c = pump curve coeffs. (H = a-bQ^c),
|
||||
** Returns 1 if successful, 0 otherwise.
|
||||
** Purpose: computes coeffs. for a power function pump curve
|
||||
**----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
double h4, h5;
|
||||
|
||||
if (h0 < TINY || h0 - h1 < TINY || h1 - h2 < TINY ||
|
||||
q1 < TINY || q2 - q1 < TINY
|
||||
) return 0;
|
||||
*a = h0;
|
||||
h4 = h0 - h1;
|
||||
h5 = h0 - h2;
|
||||
*c = log(h5 / h4) / log(q2 / q1);
|
||||
if (*c <= 0.0 || *c > 20.0) return 0;
|
||||
*b = -h4 / pow(q1, *c);
|
||||
if (*b >= 0.0) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int customcurvepump(Project *pr, Spump *pump, Scurve *curve)
|
||||
/*
|
||||
**-------------------------------------------------------------------
|
||||
** Input: pump = a pump object
|
||||
** curve = a data curve object
|
||||
** Output: returns an error code
|
||||
** Purpose: computes properties for a pump with a custom pump curve.
|
||||
**-------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int m, npts = curve->Npts;
|
||||
pump->Ptype = CUSTOM;
|
||||
for (m = 1; m < npts; m++)
|
||||
{
|
||||
// Curve must have continuously decreasing head (the Y value)
|
||||
if (curve->Y[m] >= curve->Y[m - 1])
|
||||
{
|
||||
pump->Ptype = NOCURVE;
|
||||
return 227;
|
||||
}
|
||||
}
|
||||
pump->Qmax = curve->X[npts - 1];
|
||||
pump->Q0 = (curve->X[0] + pump->Qmax) / 2.0 / pr->Ucf[FLOW];
|
||||
pump->Qmax /= pr->Ucf[FLOW];
|
||||
pump->Hmax = curve->Y[0] / pr->Ucf[HEAD];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pumpcurvepump(Project *pr, Spump *pump, Scurve *curve)
|
||||
/*
|
||||
**-------------------------------------------------------------------
|
||||
** Input: pump = a pump object
|
||||
** curve = a data curve object
|
||||
** Output: returns an error code
|
||||
** Purpose: computes properties for a pump assigned a pump curve.
|
||||
**-------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
double a, b, c, h0 = 0.0, h1 = 0.0, h2 = 0.0, q1 = 0.0, q2 = 0.0;
|
||||
int npts = curve->Npts;
|
||||
|
||||
curve->Type = PUMP_CURVE;
|
||||
|
||||
// Generic power function curve
|
||||
if (npts == 1)
|
||||
{
|
||||
pump->Ptype = POWER_FUNC;
|
||||
q1 = curve->X[0];
|
||||
h1 = curve->Y[0];
|
||||
h0 = 1.33334 * h1;
|
||||
q2 = 2.0 * q1;
|
||||
h2 = 0.0;
|
||||
}
|
||||
|
||||
// 3 point curve with shutoff head
|
||||
else if (npts == 3 && curve->X[0] == 0.0)
|
||||
{
|
||||
pump->Ptype = POWER_FUNC;
|
||||
h0 = curve->Y[0];
|
||||
q1 = curve->X[1];
|
||||
h1 = curve->Y[1];
|
||||
q2 = curve->X[2];
|
||||
h2 = curve->Y[2];
|
||||
}
|
||||
else return customcurvepump(pr, pump, curve);
|
||||
|
||||
// Compute shape factors & limits of power function curves
|
||||
if (!powerfuncpump(h0, h1, h2, q1, q2, &a, &b, &c))
|
||||
{
|
||||
pump->Ptype = NOCURVE;
|
||||
return 227;
|
||||
}
|
||||
else
|
||||
{
|
||||
pump->H0 = -a / pr->Ucf[HEAD];
|
||||
pump->R = -b * (pow(pr->Ucf[FLOW], c) / pr->Ucf[HEAD]);
|
||||
pump->N = c;
|
||||
pump->Q0 = q1 / pr->Ucf[FLOW];
|
||||
pump->Qmax = pow((-a / b), (1.0 / c)) / pr->Ucf[FLOW];
|
||||
pump->Hmax = h0 / pr->Ucf[HEAD];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int constpowerpump(Project *pr, Spump *pump)
|
||||
/*
|
||||
**-------------------------------------------------------------------
|
||||
** Input: pump = a pump object
|
||||
** Output: returns an error code
|
||||
** Purpose: computes properties for a constant power pump.
|
||||
**-------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
pump->Ptype = CONST_HP;
|
||||
pump->H0 = 0.0;
|
||||
pump->R = -8.814 * pr->network.Link[pump->Link].Km / pr->Ucf[POWER];
|
||||
pump->N = -1.0;
|
||||
pump->Hmax = BIG; // No head limit
|
||||
pump->Qmax = BIG; // No flow limit
|
||||
pump->Q0 = 1.0; // Init. flow = 1 cfs
|
||||
return 0;
|
||||
}
|
||||
|
||||
int validatepumps(Project *pr)
|
||||
/*
|
||||
**-------------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns 1 if successful, 0 if not
|
||||
** Purpose: checks if pumps are assigned valid pump curve data.
|
||||
**-------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
int i, errcode, result = 1;
|
||||
char errmsg[MAXMSG+1] = "";
|
||||
Spump *pump;
|
||||
|
||||
for (i = 1; i <= net->Npumps; i++)
|
||||
{
|
||||
// Pump has a designated pump curve
|
||||
pump = &net->Pump[i];
|
||||
if (pump->Hcurve > 0)
|
||||
errcode = pumpcurvepump(pr, pump, &net->Curve[pump->Hcurve]);
|
||||
|
||||
// Pump has a constant power setting
|
||||
else if (net->Link[pump->Link].Km > 0.0)
|
||||
errcode = constpowerpump(pr, pump);
|
||||
|
||||
// Pump has no pump curve info assigned
|
||||
else
|
||||
{
|
||||
pump->Ptype = NOCURVE;
|
||||
errcode = 226;
|
||||
}
|
||||
|
||||
if (errcode)
|
||||
{
|
||||
sprintf(pr->Msg, "Error %d: %s %s",
|
||||
errcode, geterrmsg(errcode, errmsg), net->Link[pump->Link].ID);
|
||||
writeline(pr, pr->Msg);
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int validateproject(Project *pr)
|
||||
/*
|
||||
*--------------------------------------------------------------
|
||||
* Input: none
|
||||
* Output: returns error code
|
||||
* Purpose: checks for valid network data.
|
||||
*--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int errcode = 0;
|
||||
if (pr->network.Nnodes < 2) return 223;
|
||||
if (pr->network.Ntanks == 0) return 224;
|
||||
if (!validatetanks(pr)) errcode = 110;
|
||||
if (!validatepumps(pr)) errcode = 110;
|
||||
if (!validatepatterns(pr)) errcode = 110;
|
||||
if (!validatecurves(pr)) errcode = 110;
|
||||
return errcode;
|
||||
}
|
||||
|
||||
void reindextanks(Project *pr)
|
||||
/*
|
||||
*--------------------------------------------------------------
|
||||
* Input: none
|
||||
* Output: none
|
||||
* Purpose: adjusts tank node indexes when the number of
|
||||
* junctions created from an input file is less than
|
||||
* the total number of junction lines in the file.
|
||||
*--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Parser *parser = &pr->parser;
|
||||
Quality *qual = &pr->quality;
|
||||
Scontrol *control;
|
||||
int i, j, ndiff, n1, n2, size;
|
||||
|
||||
// ndiff = # unused entries in Node array before first tank node
|
||||
ndiff = parser->MaxJuncs - net->Njuncs;
|
||||
if (ndiff > 0)
|
||||
{
|
||||
for (i = 1; i <= net->Ntanks; ++i)
|
||||
{
|
||||
// n1 is current tank index in Node array, n2 is adjusted index
|
||||
n1 = net->Tank[i].Node;
|
||||
n2 = n1 - ndiff;
|
||||
|
||||
// Update the tank node's hash table entry
|
||||
hashtable_update(net->NodeHashTable, net->Node[n1].ID, n2);
|
||||
|
||||
// Update the tank's node index
|
||||
net->Tank[i].Node = n2;
|
||||
|
||||
// Re-position tank node in Node array
|
||||
net->Node[n2] = net->Node[n1];
|
||||
|
||||
// Replace all references to old tank node index with new one
|
||||
for (j = 1; j <= net->Nlinks; ++j)
|
||||
{
|
||||
if (net->Link[j].N1 == n1) net->Link[j].N1 = n2;
|
||||
if (net->Link[j].N2 == n1) net->Link[j].N2 = n2;
|
||||
}
|
||||
for (j = 1; j <= net->Ncontrols; ++j)
|
||||
{
|
||||
control = &net->Control[j];
|
||||
if (control->Node == n1) control->Node = n2;
|
||||
}
|
||||
adjusttankrules(pr, -ndiff);
|
||||
if (qual->TraceNode == n1) qual->TraceNode = n2;
|
||||
}
|
||||
|
||||
// Reallocate the Node array (shouldn't fail as new size < old size)
|
||||
parser->MaxJuncs = net->Njuncs;
|
||||
parser->MaxNodes = net->Njuncs + net->Ntanks;
|
||||
size = (net->Nnodes + 2) * sizeof(Snode);
|
||||
net->Node = (Snode *)realloc(net->Node, size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,9 @@ set(toolkit_test_srcs
|
||||
test_control.cpp
|
||||
test_overflow.cpp
|
||||
test_pda.cpp
|
||||
test_valve.cpp
|
||||
test_units.cpp
|
||||
test_leakage.cpp
|
||||
)
|
||||
|
||||
add_executable(test_toolkit ${toolkit_test_srcs})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_analysis.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
@@ -23,11 +23,11 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose)
|
||||
{
|
||||
int i;
|
||||
|
||||
std::vector<double> test(23);
|
||||
std::vector<double> test(26);
|
||||
double *array = test.data();
|
||||
|
||||
std::vector<double> ref = {40.0, 0.001, 0.01, 0.5, 1.0, 0.0, 0.0, 0.0, 75.0, 0.0, 0.0, 0.0,
|
||||
1.0, 1.0, 10.0, 2.0, 10.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0};
|
||||
1.0, 1.0, 10.0, 2.0, 10.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0};
|
||||
|
||||
error = EN_solveH(ph);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
@@ -36,7 +36,7 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose)
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
|
||||
for (i=EN_TRIALS; i<=EN_CONCENLIMIT; i++) {
|
||||
for (i=EN_TRIALS; i<=EN_PRESS_UNITS; i++) {
|
||||
error = EN_getoption(ph, i, array++);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
}
|
||||
@@ -44,7 +44,7 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose)
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(ref.begin(), ref.end(), test.begin(), test.end());
|
||||
|
||||
double temp;
|
||||
error = EN_getoption(ph, 25, &temp);
|
||||
error = EN_getoption(ph, 27, &temp);
|
||||
BOOST_CHECK(error == 251);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_control.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_curve.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_demand.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 03/21/2019
|
||||
Last Updated: 08/02/2023
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,9 @@ BOOST_AUTO_TEST_CASE(test_categories_save)
|
||||
EN_Project ph = NULL;
|
||||
|
||||
error = EN_createproject(&ph);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_getnodeindex(ph, (char *)"12", &Nindex);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
@@ -122,5 +124,31 @@ BOOST_FIXTURE_TEST_CASE(test_adddemand, FixtureSingleNode)
|
||||
BOOST_CHECK(nD1 - nD2 == 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_cms_unit)
|
||||
{
|
||||
int flowType;
|
||||
|
||||
EN_Project ph = NULL;
|
||||
EN_createproject(&ph);
|
||||
|
||||
int error = EN_init(ph, DATA_PATH_RPT, DATA_PATH_OUT, EN_CMS, EN_HW);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_setflowunits(ph, EN_CMS);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_getflowunits(ph, &flowType );
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_REQUIRE(flowType == EN_CMS);
|
||||
|
||||
error = EN_close(ph);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_init(ph, DATA_PATH_RPT, DATA_PATH_OUT, EN_CMS+1, EN_HW);
|
||||
BOOST_REQUIRE(error == 251);
|
||||
|
||||
EN_deleteproject(ph);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_hydraulics.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
|
||||
93
tests/test_leakage.cpp
Normal file
93
tests/test_leakage.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.3
|
||||
Module: test_leakage.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 06/26/2024
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
Tests Pipe Leakage Feature
|
||||
*/
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "test_toolkit.hpp"
|
||||
|
||||
BOOST_AUTO_TEST_SUITE (test_leakage)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_leakage_model)
|
||||
|
||||
//#include <stdio.h>
|
||||
//#include <math.h>
|
||||
//#include "epanet2_2.h"
|
||||
|
||||
//int main()
|
||||
{
|
||||
int error = 0;
|
||||
int Pipe21, Junc21, Junc22;
|
||||
double pipe21Leak, junc21Leak, junc22Leak;
|
||||
EN_Project ph = NULL;
|
||||
|
||||
error = EN_createproject(&ph);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, "");
|
||||
// error = EN_open(ph, "Net1.inp", "Net1.rpt", "");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// single period analysis
|
||||
error = EN_settimeparam(ph, EN_DURATION, 0);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Get index of Pipe 21
|
||||
error = EN_getlinkindex(ph, "21", &Pipe21);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Set Pipe21 leak area to 1.0 sq mm per 100 ft of pipe
|
||||
// and its expansion rate to 0.1 sq mm per ft of head
|
||||
error = EN_setlinkvalue(ph, Pipe21, EN_LEAK_AREA, 1.0);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_setlinkvalue(ph, Pipe21, EN_LEAK_EXPAN, 0.1);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Solve for hydraulics
|
||||
error = EN_solveH(ph);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Compute Pipe 21 leakage flow using the FAVAD formula
|
||||
// Note: we can't just sum the leak rates at both end nodes
|
||||
// together since in general the nodes can have leakage
|
||||
// contributed by other connecting pipes.
|
||||
error = EN_getlinkvalue(ph, Pipe21, EN_LINK_LEAKAGE, &pipe21Leak);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
// printf("\n Pipe leakage flow: %.4f", pipe21Leak);
|
||||
|
||||
// Retrieve leakage flow at end nodes
|
||||
// Note: In this case all of the leakage at these nodes is from Pipe 21.
|
||||
error = EN_getnodeindex(ph, "21", &Junc21);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getnodeindex(ph, "22", &Junc22);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getnodevalue(ph, Junc21, EN_LEAKAGEFLOW, &junc21Leak);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getnodevalue(ph, Junc22, EN_LEAKAGEFLOW, &junc22Leak);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Check that the sum of the node leakages equals the pipe leakage
|
||||
//printf("\n Node leakage flow: %.4f\n", junc21Leak + junc22Leak);
|
||||
BOOST_REQUIRE(abs(pipe21Leak - (junc21Leak+junc22Leak)) < 0.01);
|
||||
|
||||
// Clean up
|
||||
error = EN_close(ph);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_deleteproject(ph);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
// return 0;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_link.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_net_builder.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_node.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 03/21/2019
|
||||
Last Updated: 02/14/2025
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -89,7 +89,7 @@ BOOST_FIXTURE_TEST_CASE(test_junc_props, FixtureOpenClose)
|
||||
double *value = test.data();
|
||||
|
||||
error = EN_getnodeindex(ph, (char *)"11", &index);
|
||||
std::vector<double> ref = {710.0, 150.0, 1.0, 0.0, 0.5};
|
||||
std::vector<double> ref = {710.0, 150.0, 0.0, 0.0, 0.5};
|
||||
|
||||
|
||||
// Ranged for loop iterates over property set
|
||||
@@ -255,17 +255,22 @@ BOOST_FIXTURE_TEST_CASE(test_node_comments, FixtureOpenClose)
|
||||
{
|
||||
int index;
|
||||
char comment[EN_MAXMSG + 1];
|
||||
char tag[EN_MAXMSG + 1];
|
||||
|
||||
// Add comments to selected objects
|
||||
error = EN_getnodeindex(ph, (char *)"11", &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_setcomment(ph, EN_NODE, index, (char *)"J11");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_settag(ph, EN_NODE, index, (char *)"J11_Tag");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_getnodeindex(ph, (char *)"23", &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_setcomment(ph, EN_NODE, index, (char *)"Junc23");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_settag(ph, EN_NODE, index, (char *)"Junc23_Tag");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Check comments
|
||||
error = EN_getnodeindex(ph, (char *)"11", &index);
|
||||
@@ -273,18 +278,25 @@ BOOST_FIXTURE_TEST_CASE(test_node_comments, FixtureOpenClose)
|
||||
error = EN_getcomment(ph, EN_NODE, index, comment);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(check_string(comment, (char *)"J11"));
|
||||
error = EN_gettag(ph, EN_NODE, index, tag);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(check_string(tag, (char *)"J11_Tag"));
|
||||
|
||||
error = EN_getnodeindex(ph, (char *)"23", &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getcomment(ph, EN_NODE, index, comment);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(check_string(comment, (char *)"Junc23"));
|
||||
error = EN_gettag(ph, EN_NODE, index, tag);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(check_string(tag, (char *)"Junc23_Tag"));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(test_replace_comment, FixtureOpenClose)
|
||||
{
|
||||
int index;
|
||||
char comment[EN_MAXMSG + 1];
|
||||
char tag[EN_MAXMSG + 1];
|
||||
|
||||
// Replace short comment with longer one and vice versa
|
||||
error = EN_getnodeindex(ph, (char *)"11", &index);
|
||||
@@ -295,11 +307,23 @@ BOOST_FIXTURE_TEST_CASE(test_replace_comment, FixtureOpenClose)
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(check_string(comment, (char *)"Junction11"));
|
||||
|
||||
error = EN_settag(ph, EN_NODE, index, (char *)"Junction11_Tag");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_gettag(ph, EN_NODE, index, tag);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(check_string(tag, (char *)"Junction11_Tag"));
|
||||
|
||||
error = EN_setcomment(ph, EN_NODE, index, (char *)"J11");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getcomment(ph, EN_NODE, index, comment);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(check_string(comment, (char *)"J11"));
|
||||
|
||||
error = EN_settag(ph, EN_NODE, index, (char *)"J11_Tag");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_gettag(ph, EN_NODE, index, tag);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(check_string(tag, (char *)"J11_Tag"));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(test_save_comment, FixtureOpenClose)
|
||||
@@ -311,11 +335,15 @@ BOOST_FIXTURE_TEST_CASE(test_save_comment, FixtureOpenClose)
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_setcomment(ph, EN_NODE, index, (char *)"J11");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_settag(ph, EN_NODE, index, (char *)"J11_Tag");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_getnodeindex(ph, (char *)"23", &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_setcomment(ph, EN_NODE, index, (char *)"Junc23");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_settag(ph, EN_NODE, index, (char *)"Junc23_Tag");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_saveinpfile(ph, DATA_PATH_TMP);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
@@ -325,6 +353,7 @@ BOOST_AUTO_TEST_CASE(test_reopen_comment, * boost::unit_test::depends_on("node_c
|
||||
{
|
||||
int error, index;
|
||||
char comment[EN_MAXMSG + 1];
|
||||
char tag[EN_MAXMSG + 1];
|
||||
|
||||
// Create & load a project
|
||||
EN_Project ph = NULL;
|
||||
@@ -340,12 +369,18 @@ BOOST_AUTO_TEST_CASE(test_reopen_comment, * boost::unit_test::depends_on("node_c
|
||||
error = EN_getcomment(ph, EN_NODE, index, comment);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(check_string(comment, (char *)"J11"));
|
||||
error = EN_gettag(ph, EN_NODE, index, tag);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(check_string(tag, (char *)"J11_Tag"));
|
||||
|
||||
error = EN_getnodeindex(ph, (char *)"23", &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getcomment(ph, EN_NODE, index, comment);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(check_string(comment, (char *)"Junc23"));
|
||||
error = EN_gettag(ph, EN_NODE, index, tag);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(check_string(tag, (char *)"Junc23_Tag"));
|
||||
|
||||
// Close project
|
||||
EN_close(ph);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_overflow.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 06/16/2019
|
||||
Last Updated: 08/02/2023
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -32,7 +32,9 @@ BOOST_AUTO_TEST_CASE(test_tank_overflow)
|
||||
EN_Project ph = NULL;
|
||||
|
||||
error = EN_createproject(&ph);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, "");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Get index of the tank and its inlet/outlet pipe
|
||||
error = EN_getnodeindex(ph, (char *)"2", &Nindex);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_pattern.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_pda.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 07/20/2019
|
||||
Last Updated: 08/02/2023
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -30,7 +30,9 @@ BOOST_AUTO_TEST_CASE(test_pda_model)
|
||||
|
||||
EN_Project ph = NULL;
|
||||
error = EN_createproject(&ph);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, "");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Set Demand Multiplier to 10 to cause negative pressures
|
||||
error = EN_setoption(ph, EN_DEMANDMULT, 10);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_project.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
@@ -118,7 +118,6 @@ BOOST_AUTO_TEST_CASE(test_run)
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(test_proj_fixture)
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(test_title, FixtureOpenClose)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_quality.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_reent.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_report.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_toolkit.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Version: 2.3
|
||||
Module: test_toolkit.hpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
|
||||
460
tests/test_units.cpp
Normal file
460
tests/test_units.cpp
Normal file
@@ -0,0 +1,460 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.3
|
||||
Module: test_units.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 03/30/2023
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
This is a test for the API functions that change the units of a project.
|
||||
*/
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "test_toolkit.hpp"
|
||||
|
||||
/*
|
||||
----------------------------------------------
|
||||
Flow units conversion factors
|
||||
----------------------------------------------
|
||||
*/
|
||||
double GPMperCFS = 448.831;
|
||||
double LPSperCFS = 28.317;
|
||||
double MperFT = 0.3048;
|
||||
double PSIperFT = 0.4333;
|
||||
double KPAperPSI = 6.895;
|
||||
|
||||
char unitrules[] = "RULE 1\n IF NODE 10 DEMAND > 10 \n"
|
||||
"AND NODE 10 HEAD > 20 \n"
|
||||
"AND NODE 10 PRESSURE > 30 \n"
|
||||
"AND NODE 10 LEVEL > 40 \n"
|
||||
"AND LINK 10 FLOW > 50 \n"
|
||||
"AND LINK PRV1 SETTING > 60 \n"
|
||||
"AND LINK FCV1 SETTING > 70 \n"
|
||||
"THEN LINK PRV1 SETTING = 80\n ELSE LINK FCV1 SETTING = 90";
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE (test_units)
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(test_pressure_units, FixtureInitClose)
|
||||
{
|
||||
int index;
|
||||
long t;
|
||||
double p, units;
|
||||
|
||||
// Create basic network
|
||||
error = EN_addnode(ph, "R1", EN_RESERVOIR, &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_setnodevalue(ph, index, EN_ELEVATION, 100);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_addnode(ph, "J1", EN_JUNCTION, &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_addlink(ph, "P1", EN_PIPE, "R1", "J1", &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Run simulation and get junction pressure
|
||||
error = EN_openH(ph);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_initH(ph, EN_NOSAVE);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_runH(ph, &t);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(p - 43.33) < 1.e-5);
|
||||
|
||||
// Get pressure unit and check that it is PSI
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(units == EN_PSI);
|
||||
|
||||
// Change to pressure from PSI to meters and check it is meters
|
||||
error = EN_setoption(ph, EN_PRESS_UNITS, EN_METERS);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(units == EN_METERS);
|
||||
|
||||
// Change flow units to LPS to change to metric units and rerun simulation
|
||||
error = EN_setflowunits(ph, EN_LPS);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_initH(ph, EN_NOSAVE);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_runH(ph, &t);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Confirm that pressure is now in meters
|
||||
error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(p - 30.48) < 1.e-5);
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(units == EN_METERS);
|
||||
|
||||
// Set and check that pressure units are in kPa
|
||||
error = EN_setoption(ph, EN_PRESS_UNITS, EN_KPA);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(units == EN_KPA);
|
||||
error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(p - 298.76035) < 1.e-5);
|
||||
|
||||
// Set pressure to PSI and check that it has changed to PSI
|
||||
error = EN_setoption(ph, EN_PRESS_UNITS, EN_PSI);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(units == EN_PSI);
|
||||
|
||||
error = EN_closeH(ph);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(test_pda_unit_change, FixtureOpenClose)
|
||||
{
|
||||
int type;
|
||||
double pmin, preq, pexp;
|
||||
|
||||
// Switch to PDA with pressure limits of 20 - 100 psi
|
||||
error = EN_setdemandmodel(ph, EN_PDA, 20, 100, 0.5);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_setflowunits(ph, EN_LPS);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_getdemandmodel(ph, &type, &pmin, &preq, &pexp);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(pmin - (20/PSIperFT*MperFT)) < 1.e-5);
|
||||
BOOST_CHECK(abs(preq - (100/PSIperFT*MperFT)) < 1.e-5);
|
||||
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(test_rule_unit_change, FixtureOpenClose)
|
||||
{
|
||||
int index, node22, link12;
|
||||
double units;
|
||||
|
||||
// Rule variables
|
||||
int r_logop, r_object, r_objIndex, r_variable, r_relop, r_status;
|
||||
double r_value;
|
||||
|
||||
// Control variables
|
||||
int c_index, c_type, c_linkIndex, c_nodeIndex;
|
||||
double c_setting, c_level;
|
||||
|
||||
// Add new PRV and FCV to test rules
|
||||
error = EN_addlink(ph, (char *)"PRV1", EN_PRV, (char *)"10", (char *)"11", &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_addlink(ph, (char *)"FCV1", EN_FCV, (char *)"12", (char *)"13", &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Add the rule to the project
|
||||
error = EN_addrule(ph, unitrules);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Add control that checks junction pressure
|
||||
EN_getnodeindex(ph, (char *)"22", &node22);
|
||||
EN_getlinkindex(ph, (char *)"12", &link12);
|
||||
error = EN_addcontrol(ph, EN_HILEVEL, link12, 0, node22, 250, &c_index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Check that rules and controls are in US units
|
||||
error = EN_getpremise(ph, 1, 3, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(r_value == 30);
|
||||
|
||||
error = EN_getcontrol(ph, c_index, &c_type, &c_linkIndex, &c_setting, &c_nodeIndex, &c_level);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(c_level == 250);
|
||||
|
||||
// Change flow units to lps and pressure to meters
|
||||
error = EN_setflowunits(ph, EN_LPS);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(units == EN_METERS);
|
||||
|
||||
// Check that rules and controls are in meters
|
||||
|
||||
// Simple Control - 250 psi to meters
|
||||
error = EN_getcontrol(ph, c_index, &c_type, &c_linkIndex, &c_setting, &c_nodeIndex, &c_level);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(c_level - (250/PSIperFT*MperFT)) < 1.e-5); // 250 PSI to M
|
||||
|
||||
// Premise 1 - Demand GPM to LPS
|
||||
error = EN_getpremise(ph, 1, 1, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(r_value - (10/GPMperCFS*LPSperCFS)) < 1.e-5); //10 GPM to LPS
|
||||
|
||||
// Premise 2 - Head FT to Meters
|
||||
error = EN_getpremise(ph, 1, 2, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(r_value - (20*MperFT)) < 1.e-5); //20 FT to M
|
||||
|
||||
// Premise 3 - Pressure PSI to Meters
|
||||
error = EN_getpremise(ph, 1, 3, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(r_value - (30/PSIperFT*MperFT)) < 1.e-5); //30 PSI to M
|
||||
|
||||
// Premise 4 - Level FT to Meters
|
||||
error = EN_getpremise(ph, 1, 4, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(r_value - (40*MperFT)) < 1.e-5); //40 FT to M
|
||||
|
||||
// Premise 5 - Flow GPM to LPS
|
||||
error = EN_getpremise(ph, 1, 5, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(r_value - (50/GPMperCFS*LPSperCFS)) < 1.e-5); //50 GPM to LPS
|
||||
|
||||
// Premise 6 - Setting PSI to Meters
|
||||
error = EN_getpremise(ph, 1, 6, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(r_value - (60/PSIperFT*MperFT)) < 1.e-5); //60 PSI to M
|
||||
|
||||
// Premise 7 - Setting GPM to LPS
|
||||
error = EN_getpremise(ph, 1, 7, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(r_value - (70/GPMperCFS*LPSperCFS)) < 1.e-5); //70 GPM to LPS
|
||||
|
||||
// ThenAction - Setting PSI to Meters
|
||||
error = EN_getthenaction(ph, 1, 1, &r_objIndex, &r_status, &r_value);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(r_value - (80/PSIperFT*MperFT)) < 1.e-5); //80 PSI to M
|
||||
|
||||
// ElseAction - Setting GPM to LPS
|
||||
error = EN_getelseaction(ph, 1, 1, &r_objIndex, &r_status, &r_value);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(r_value - (90/GPMperCFS*LPSperCFS)) < 1.e-5); //90 GPM to LPS
|
||||
|
||||
// Change pressure units to kPa
|
||||
error = EN_setoption(ph, EN_PRESS_UNITS, EN_KPA);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Simple Control - 250 psi to kPa
|
||||
error = EN_getcontrol(ph, c_index, &c_type, &c_linkIndex, &c_setting, &c_nodeIndex, &c_level);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(c_level - (250*KPAperPSI)) < 1.e-5); //250 PSI to kPa
|
||||
|
||||
// Premise 3 - Pressure PSI to kPa
|
||||
error = EN_getpremise(ph, 1, 3, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(r_value - (30*KPAperPSI)) < 1.e-5); //30 PSI to kPa
|
||||
|
||||
// Premise 6 - Setting PSI to kPa
|
||||
error = EN_getpremise(ph, 1, 6, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(r_value - (60*KPAperPSI)) < 1.e-5); //60 PSI to kPa
|
||||
|
||||
// ThenAction - Setting PSI to kPa
|
||||
error = EN_getthenaction(ph, 1, 1, &r_objIndex, &r_status, &r_value);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(r_value - (80*KPAperPSI)) < 1.e-5); //80 PSI to kPa
|
||||
|
||||
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(test_decoupled_pressure_units, FixtureInitClose)
|
||||
{
|
||||
int index;
|
||||
long t;
|
||||
double p, units;
|
||||
|
||||
// Create basic network
|
||||
error = EN_addnode(ph, "R1", EN_RESERVOIR, &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_setnodevalue(ph, index, EN_ELEVATION, 100);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_addnode(ph, "J1", EN_JUNCTION, &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_addlink(ph, "P1", EN_PIPE, "R1", "J1", &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Test 1: Start with US flow units (GPM) and change to PSI
|
||||
error = EN_setflowunits(ph, EN_GPM);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Should succeed in setting PSI pressure units
|
||||
error = EN_setoption(ph, EN_PRESS_UNITS, EN_PSI);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(units == EN_PSI);
|
||||
|
||||
// Test 2: With US flow units, set pressure to meters (should now work)
|
||||
error = EN_setoption(ph, EN_PRESS_UNITS, EN_METERS);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(units == EN_METERS);
|
||||
|
||||
// Test 3: With US flow units, set pressure to kPa (should now work)
|
||||
error = EN_setoption(ph, EN_PRESS_UNITS, EN_KPA);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(units == EN_KPA);
|
||||
|
||||
// Test 4: Change to SI flow units (LPS) but keep kPa pressure
|
||||
error = EN_setflowunits(ph, EN_LPS);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Pressure units should change to metric default of meters
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(units == EN_METERS);
|
||||
|
||||
// Test 5: With SI flow units, set pressure to PSI (should now work)
|
||||
error = EN_setoption(ph, EN_PRESS_UNITS, EN_PSI);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(units == EN_PSI);
|
||||
|
||||
// Test 6: Run simulation and check pressure values are correctly converted
|
||||
error = EN_openH(ph);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_initH(ph, EN_NOSAVE);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_runH(ph, &t);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Get pressure in PSI (should be ~43.33 PSI for 100 ft head)
|
||||
error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(p - 43.33) < 1.e-5);
|
||||
|
||||
// Change pressure units to meters during simulation
|
||||
error = EN_setoption(ph, EN_PRESS_UNITS, EN_METERS);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Pressure should now be in meters (~30.48 m for 100 ft head)
|
||||
error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(abs(p - 30.48) < 1.e-5);
|
||||
|
||||
error = EN_closeH(ph);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(test_automatic_pressure_unit_switching, FixtureInitClose)
|
||||
{
|
||||
int index;
|
||||
double pressure_units;
|
||||
|
||||
// Create basic network
|
||||
error = EN_addnode(ph, "R1", EN_RESERVOIR, &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_setnodevalue(ph, index, EN_ELEVATION, 100);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_addnode(ph, "J1", EN_JUNCTION, &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_addlink(ph, "P1", EN_PIPE, "R1", "J1", &index);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Test 1: Start with US flow units (CFS) - should have PSI pressure units
|
||||
error = EN_setflowunits(ph, EN_CFS);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(pressure_units == EN_PSI);
|
||||
|
||||
// Test 2: Change from US flow units (CFS) to metric flow units (LPS)
|
||||
// Pressure units should automatically change from PSI to METERS
|
||||
error = EN_setflowunits(ph, EN_LPS);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(pressure_units == EN_METERS);
|
||||
|
||||
// Test 3: Change from metric flow units (LPS) back to US flow units (GPM)
|
||||
// Pressure units should automatically change from METERS to PSI
|
||||
error = EN_setflowunits(ph, EN_GPM);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(pressure_units == EN_PSI);
|
||||
|
||||
// Test 4: Change from US flow units (GPM) to another metric flow unit (MLD)
|
||||
// Pressure units should automatically change from PSI to METERS
|
||||
error = EN_setflowunits(ph, EN_MLD);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(pressure_units == EN_METERS);
|
||||
|
||||
// Test 5: Manually set pressure units to kPa while using metric flow units
|
||||
error = EN_setoption(ph, EN_PRESS_UNITS, EN_KPA);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(pressure_units == EN_KPA);
|
||||
|
||||
// Test 6: Change from metric flow units (MLD) to US flow units (MGD)
|
||||
// Pressure units should automatically change from kPa to PSI
|
||||
error = EN_setflowunits(ph, EN_MGD);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(pressure_units == EN_PSI);
|
||||
|
||||
// Test 7: Change from US flow units (MGD) to metric flow units (CMH)
|
||||
// Pressure units should automatically change from PSI to METERS
|
||||
error = EN_setflowunits(ph, EN_CMH);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(pressure_units == EN_METERS);
|
||||
|
||||
// Test 8: Set pressure to kPa again with metric flow units
|
||||
error = EN_setoption(ph, EN_PRESS_UNITS, EN_KPA);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Test 9: Change between metric flow units (CMH to CMD)
|
||||
// Pressure units should remain kPa (not changed to METERS since not switching from PSI)
|
||||
error = EN_setflowunits(ph, EN_CMD);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(pressure_units == EN_KPA);
|
||||
|
||||
// Test 10: Change from metric flow units (CMD) to US flow units (AFD)
|
||||
// Pressure units should automatically change from kPa to PSI
|
||||
error = EN_setflowunits(ph, EN_AFD);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(pressure_units == EN_PSI);
|
||||
|
||||
// Test 11: Change between US flow units (AFD to IMGD)
|
||||
// Pressure units should remain PSI
|
||||
error = EN_setflowunits(ph, EN_IMGD);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(pressure_units == EN_PSI);
|
||||
|
||||
// Test 12: Final test - metric flow units (CMS) should change PSI to METERS
|
||||
error = EN_setflowunits(ph, EN_CMS);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(pressure_units == EN_METERS);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
78
tests/test_valve.cpp
Normal file
78
tests/test_valve.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.3
|
||||
Module: test_valve.cpp
|
||||
Description: Tests EPANET toolkit api functions
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 07/28/2022
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
Tests PCV valve with position curve
|
||||
*/
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "test_toolkit.hpp"
|
||||
|
||||
BOOST_AUTO_TEST_SUITE (test_valve)
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(test_PCV_valve, FixtureOpenClose)
|
||||
|
||||
{
|
||||
int npts = 5;
|
||||
double x[] = { 0.0, 25., 50., 75., 100. };
|
||||
double y[] = {0.0, 8.9, 18.4, 40.6, 100.0};
|
||||
double v;
|
||||
int linkIndex, curveIndex, curveType;
|
||||
|
||||
// Make steady state run
|
||||
error = EN_settimeparam(ph, EN_DURATION, 0);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Convert pipe 22 to a PCV
|
||||
error = EN_getlinkindex(ph, (char*)"22", &linkIndex);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_setlinktype(ph, &linkIndex, EN_PCV, EN_UNCONDITIONAL);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_setlinkvalue(ph, linkIndex, EN_DIAMETER, 12);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_setlinkvalue(ph, linkIndex, EN_MINORLOSS, 0.19);
|
||||
|
||||
// Create the PCV's position-loss curve
|
||||
error = EN_addcurve(ph, (char*)"ValveCurve");
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getcurveindex(ph, (char*)"ValveCurve", &curveIndex);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_setcurve(ph, curveIndex, x, y, npts);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_setcurvetype(ph, curveIndex, EN_VALVE_CURVE);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_getcurvetype(ph, curveIndex, &curveType);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_REQUIRE(curveType == EN_VALVE_CURVE);
|
||||
|
||||
// Assign curve & initial setting to PCV
|
||||
error = EN_setlinkvalue(ph, linkIndex, EN_PCV_CURVE, curveIndex);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
error = EN_setlinkvalue(ph, linkIndex, EN_INITSETTING, 35.);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// Solve for hydraulics
|
||||
error = EN_solveH(ph);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
|
||||
// The PCV interpolated relative flow coeff. at 35% open is 0.127.
|
||||
// This translates to a minor loss coeff. of 0.19 / 0.127^2 = 11.78.
|
||||
// If the PCV were replaced with a TCV at that setting the resulting
|
||||
// head loss would be 0.0255 ft which should equal the PCV result.
|
||||
error = EN_getlinkvalue(ph, linkIndex, EN_HEADLOSS, &v);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_REQUIRE(abs(v - 0.0255) < 0.001);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user