Merge branch 'dev'

This commit is contained in:
Lew Rossman
2025-07-17 09:27:22 -04:00
109 changed files with 10960 additions and 39684 deletions

View File

@@ -1,19 +1,60 @@
name: C/C++ CI name: linux
on: [push] on:
push:
pull_request:
schedule:
- cron: '0 0 1 * *'
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
fail-fast: false
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v4
- name: setup_build_dir
- name: Setup build directory
run: mkdir buildproducts run: mkdir buildproducts
- name: cmake
- name: CMake
working-directory: ./buildproducts working-directory: ./buildproducts
run: cmake .. run: |
- name: make 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 working-directory: ./buildproducts
run: make 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
View 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
View 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
View 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

63
AUTHORS
View File

@@ -1,27 +1,60 @@
# Authors ordered by first contribution. # Authors ordered alphabetically.
Authors with Contributions in the Public Domain: Authors with Contributions in the Public Domain:
Lewis Rossman <LRossman@cinci.rr.com> Lewis Rossman <LRossman@cinci.rr.com>
Michael Tryby <tryby.michael@epa.gov> 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> Authors with Contributions Subject to Copyright (see LICENSE):
Feng Shang <fshang> Except where noted.
James Uber <jim@citilogics.com>
Tom Taxon <tntaxon@anl.gov> Version 2.1
Hyoungmin Woo <hyoungmin.woo@gmail.com>
Jinduan Chen <jinduan.uc@gmail.com> Jinduan Chen <jinduan.uc@gmail.com>
Yunier Soad <yunier.soad@gmail.com> Maurizio Cingi <mrzcng2@gmail.com>
Mike Kane <muke195@gmail.com>
Demetrios Eliades <eldemet@gmail.com> Demetrios Eliades <eldemet@gmail.com>
Will Furnass <will@thearete.co.uk> 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> Marios Kyriakou <mariosmsk@gmail.com>
Elad Salomons <selad@optiwater.com> Steffen Macke <sdteffen@sdteffen.de>
Maurizio Cingi <mrzcng2@gmail.com>
Bryant McDonnell <bemcdonnell@gmail.com>
Angela Marchi <angela.marchi@adelaide.edu.au> 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> 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>

View File

@@ -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 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: 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 mkdir build
cd build cd build
@@ -13,7 +16,36 @@ Note: under Windows, the third command should be `cmake .. -A Win32` for a 32-bi
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: 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. 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. 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
```

View File

@@ -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 # 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 # 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 is available at https://cmake.org/download/
# #
cmake_minimum_required (VERSION 2.8.8) cmake_minimum_required (VERSION 3.8.0)
project(EPANET) project(EPANET)
# Append local dir to module search path # Append local dir to module search path
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 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_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) option(BUILD_COVERAGE "Build library for coverage" OFF)
#IF (NOT BUILD_PY_LIB)
IF (NOT BUILD_PY_LIB)
add_subdirectory(run) add_subdirectory(run)
ENDIF (NOT BUILD_PY_LIB) #ENDIF (NOT BUILD_PY_LIB)
add_subdirectory(src/outfile) add_subdirectory(src/outfile)
IF (BUILD_TESTS) IF (BUILD_TESTS)
@@ -60,17 +60,14 @@ IF (BUILD_TESTS)
add_subdirectory(tests/util) add_subdirectory(tests/util)
ENDIF (BUILD_TESTS) ENDIF (BUILD_TESTS)
# Sets the output directory for executables and libraries. # Sets the output directory for executables and libraries.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
# Sets the position independent code property for all targets # Sets the position independent code property for all targets
SET(CMAKE_POSITION_INDEPENDENT_CODE ON) SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
IF (APPLE) IF (APPLE)
set(INSTALL_NAME_DIR @executable_path/../lib) set(INSTALL_NAME_DIR @executable_path/../lib)
set(CMAKE_MACOSX_RPATH 1) set(CMAKE_MACOSX_RPATH 1)
@@ -84,8 +81,6 @@ ENDIF (MSVC)
# configure file groups # configure file groups
file(GLOB EPANET_SOURCES RELATIVE ${PROJECT_SOURCE_DIR} src/*.c src/util/*.c) 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/*) 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}) source_group("Library" FILES ${EPANET_LIB_ALL})
# the shared library # 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) 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) set_source_files_properties(${PROJECT_SOURCE_DIR}/include/epanet2.def PROPERTIES_HEADER_FILE_ONLY TRUE)
ELSE(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)") ENDIF(MSVC AND "${CMAKE_VS_PLATFORM_NAME}" MATCHES "(Win32)")
target_include_directories(epanet2 PUBLIC ${PROJECT_SOURCE_DIR}/include) 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 .)

View File

@@ -1,6 +1,6 @@
MIT License 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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal 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 copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice, list of authors, and this permission notice shall
copies or substantial portions of the Software. be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

View File

@@ -3,9 +3,10 @@ OWA-EPANET
## Build Status ## Build Status
[![Build status](https://ci.appveyor.com/api/projects/status/19wpg4g2cmj3oihl?svg=true)](https://ci.appveyor.com/project/OpenWaterAnalytics/epanet) [![Build status](https://ci.appveyor.com/api/projects/status/19wpg4g2cmj3oihl?svg=true)](https://ci.appveyor.com/project/OpenWaterAnalytics/epanet)
[![Build Status](https://travis-ci.org/OpenWaterAnalytics/EPANET.svg)](https://travis-ci.org/OpenWaterAnalytics/EPANET) [![linux](https://github.com/OpenWaterAnalytics/EPANET/actions/workflows/ccpp.yml/badge.svg)](https://github.com/OpenWaterAnalytics/EPANET/actions/workflows/ccpp.yml)
[![macos](https://github.com/OpenWaterAnalytics/EPANET/actions/workflows/macos.yml/badge.svg)](https://github.com/OpenWaterAnalytics/EPANET/actions/workflows/macos.yml)
[![codecov](https://codecov.io/gh/OpenWaterAnalytics/EPANET/branch/master/graph/badge.svg)](https://codecov.io/gh/OpenWaterAnalytics/EPANET) [![epanet2-win32](https://github.com/OpenWaterAnalytics/EPANET/actions/workflows/win32.yml/badge.svg)](https://github.com/OpenWaterAnalytics/EPANET/actions/workflows/win32.yml)
[![epanet2-win64](https://github.com/OpenWaterAnalytics/EPANET/actions/workflows/win64.yml/badge.svg)](https://github.com/OpenWaterAnalytics/EPANET/actions/workflows/win64.yml)
## DESCRIPTION ## DESCRIPTION
@@ -17,7 +18,7 @@ Instructions for building the OWA-EPANET Toolkit's function library as well as i
## USAGE ## 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 ## 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). 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 ## 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 USEPAs 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 USEPAs 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
View 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
View 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"]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
<navindex> <navindex>
<tab type="mainpage" visible="yes" title=""/> <tab type="mainpage" visible="yes" title=""/>
<tab type="pages" visible="yes" title="" intro=""/> <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."/> intro="These topics describe the Toolkit's functions, enumerations, and error/warning codes."/>
<tab type="namespaces" visible="yes" title=""> <tab type="namespaces" visible="yes" title="">
<tab type="namespacelist" visible="yes" title="" intro=""/> <tab type="namespacelist" visible="yes" title="" intro=""/>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2681
doc/doxygen-awesome.css Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
h1 { font-size:1.5em; }

View File

@@ -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}

View File

@@ -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 ---

View File

@@ -6,7 +6,6 @@ EPANET is a program that performs extended period simulation of hydraulic and wa
<table style = "border: 0px solid black"> <table style = "border: 0px solid black">
<tr><td style="vertical-align: top"> <tr><td style="vertical-align: top">
@image html DistributionSystem.png @image html DistributionSystem.png
@image latex DistributionSystem.eps
</td></tr> </td></tr>
</table> </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 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 - 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 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 - 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. - 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 DataFlow "Data Flow Diagram"
- @subpage ToolkitVersions "Toolkit Versions" - @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. __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"> <table style = "border: 0px solid black">
<tr><td> <tr><td>
@image html Network.png @image html Network.png
@image latex Network.eps
</td></tr> </td></tr>
</table> </table>
@@ -52,22 +51,21 @@ intervals of time
- data curves that describe relationships between two quantities, such as head versus flow for pumps and - data curves that describe relationships between two quantities, such as head versus flow for pumps and
volume versus water level for tanks 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 - 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 - 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 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. - 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: 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 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 - 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 - time steps used for hydraulic, water quality and reporting
- the type of water quality analysis to perform (chemical reaction, source tracing or water age) - 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. - 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. 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"> <table style = "border: 0px solid black">
<tr><td> <tr><td>
@image html DataFlow.png @image html DataFlow.png
@image latex DataFlow.eps
</td></tr> </td></tr>
</table> </table>
@@ -104,7 +101,7 @@ with single threaded applications.
analyzed concurrently. analyzed concurrently.
Both Toolkit versions utilize identical function names and argument lists with the following exceptions: 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 - Function names in the single-threaded library begin with \b EN while those in the multi-threaded
library begin with \b EN_ . library begin with \b EN_ .
- The multi-threaded functions contain an additional argument that references a particular network project - The multi-threaded functions contain an additional argument that references a particular network project

View File

@@ -4,7 +4,7 @@
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! --> <div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul> <ul>
$navpath $navpath
<!-- <li class="footer">OWA-EPANET Toolkit 2.2 &copy 2019</li> --> <!-- <li class="footer">OWA-EPANET Toolkit 2.3 &copy 2025</li> -->
</ul> </ul>
</div> </div>
<!--END GENERATE_TREEVIEW--> <!--END GENERATE_TREEVIEW-->

View File

@@ -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. 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.
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.
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: 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. - `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-examples.dox` : generates the *Examples* section.
- `toolkit-files.dox`: generates the *Toolkit Files* 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. - `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: 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 - `Doxyfile`: the Doxygen configuration file for HTML output
- `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. - `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.
- `extrastylesheet.css`: reduces the size of the the h1 heading style. - `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. - `newfooter.html`: replaces the default Doxygen footer in HTML output with a custom one.

View File

@@ -47,7 +47,6 @@ Below is a schematic of the network to be built.
<table style = "border: 0px solid black"> <table style = "border: 0px solid black">
<tr><td> <tr><td>
@image html Example2.png @image html Example2.png
@image latex Example2.eps
</td></tr> </td></tr>
</table> </table>

View File

@@ -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 | | Water Quality Option - see @ref EN_QualityType | Integer | 4 |
| Traced Node Index | Integer | 4 | | Traced Node Index | Integer | 4 |
| Flow Units Option | 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 | | Report Statistic Type - see @ref EN_StatisticType | Integer | 4 |
| Reporting Start Time (sec) | Integer | 4 | | Reporting Start Time (sec) | Integer | 4 |
| Reporting Time Step (sec) | Integer | 4 | | Reporting Time Step (sec) | Integer | 4 |
@@ -158,6 +158,7 @@ Several additional function declaration files that provide bindings for other pr
- <b>`epanet2.bas`</b> for Visual Basic for Applications and Visual Basic 6 - <b>`epanet2.bas`</b> for Visual Basic for Applications and Visual Basic 6
- <b>`epanet2.vb`</b> for Visual Basic .NET - <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. These bindings only support the single-threaded version of the Toolkit.
*/ */

View File

@@ -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 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 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 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 PipesPage "[Pipes]" |@subpage CtrlsPage "[Controls]" | | | |
|@subpage PumpsPage "[Pumps]" |@subpage RulesPage "[Rules]" | | | | |@subpage PumpsPage "[Pumps]" |@subpage RulesPage "[Rules]" | | | |
|@subpage ValvesPage "[Valves]" |@subpage DmndsPage "[Demands]" | | | | |@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. 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>&nbsp;&nbsp; LINK</b> _linkID_ &nbsp; _status_ &nbsp;<b> AT TIME&nbsp;</b> _time_ <b>&nbsp;&nbsp; LINK</b> _linkID_ &nbsp; _status_ &nbsp;<b> AT TIME&nbsp;</b> _time_
<b>&nbsp;&nbsp; LINK</b> _linkID_ &nbsp; _status_ &nbsp;<b> AT CLOCKTIME</b> _clocktime_ &nbsp;<b> AM / PM</b> <b>&nbsp;&nbsp; LINK</b> _linkID_ &nbsp; _status_ &nbsp;<b> AT CLOCKTIME</b> _clocktime_
where: where:
<table style = "border: 0px solid black"> <table style = "border: 0px solid black">
@@ -55,6 +56,7 @@ where:
__Remarks:__ __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. 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:__ __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> ;Open Link 12 if the pressure at Node 130 is under 30 psi<br>
LINK 12 OPEN IF NODE 130 BELOW 30 LINK 12 OPEN IF NODE 130 BELOW 30
;Pump PUMP02's speed is set to 1.5 at 16 hours into the simulation<br> ;Disable setting Pump PUMP02's speed to 1.5 at 16 hours into the simulation<br>
LINK PUMP02 1.5 AT TIME 16 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 is closed at 10 am and opened at 8 pm throughout the simulation<br>
LINK 12 CLOSED AT CLOCKTIME 10 AM<br> LINK 12 CLOSED AT CLOCKTIME 10 AM<br>
@@ -92,9 +94,10 @@ __Remarks:__
- Head v. Flow for pumps - Head v. Flow for pumps
- Efficiency v. Flow for pumps - Efficiency v. Flow for pumps
- Volume v. Depth for tanks - 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 - 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). 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:__ __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] @page MixingPage [MIXING]
@@ -277,7 +300,8 @@ Defines various simulation options.
__Formats:__ __Formats:__
<table style = "border: 0px solid black"> <table style = "border: 0px solid black">
<tr><td><B>UNITS</B></td><td><B>CFS / GPM / MGD / IMGD / AFD /</B></td></tr> <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>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>&nbsp;filename</I></td></tr> <tr><td><B>HYDRAULICS</B></td><td><B>USE / SAVE </B><I>&nbsp;filename</I></td></tr>
<tr><td><B>VISCOSITY</B></td><td><I>value</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>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>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 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&nbsp;&nbsp; </B><I>nodeID</I></td></tr> <tr><td><B>QUALITY</B></td><td><B>NONE / CHEMICAL / AGE / TRACE&nbsp;&nbsp; </B><I>nodeID</I></td></tr>
<tr><td><B>DIFFUSIVITY</B></td><td><I>value</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> <tr><td><B>TOLERANCE</B></td><td><I>value</I></td></tr>
@@ -313,10 +338,13 @@ __Definitions:__
- \b LPS = liters per second - \b LPS = liters per second
- \b LPM = liters per minute - \b LPM = liters per minute
- \b MLD = million liters per day - \b MLD = million liters per day
- \b CMS = cubic meters per second
- \b CMH = cubic meters per hour - \b CMH = cubic meters per hour
- \b CMD = cubic meters per day - \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. \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 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. \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 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 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. \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:__ __Remarks:__
1. Quality is assumed to be zero for nodes not listed. 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. 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 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 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. \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 @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 links 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] @page TanksPage [TANKS]
@@ -1005,7 +1069,7 @@ Attaches a descriptive title to the network being analyzed.
__Format:__ __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:__ __Remarks:__
@@ -1028,19 +1092,26 @@ One line for each valve containing:
- Diameter, inches (mm) - Diameter, inches (mm)
- Valve type - Valve type
- Valve setting - Valve setting
- Minor loss coefficient - Minor loss coefficient when fully open
- ID of valve characteristic curve (PCVs only)
__Remarks:__ __Remarks:__
1. Valve types and settings include: 1. Valve types and settings include: \n
|Valve Type | Setting | |Valve Type | Setting |
|-----------|---------| |-----------|---------|
|<B>PRV</B> (pressure reducing valve) | Pressure, psi (m) | |<B>PRV</B> (pressure reducing valve) | Pressure (pressure units) |
|<B>PSV</B> (pressure sustaining valve) | Pressure, psi (m) | |<B>PSV</B> (pressure sustaining valve) | Pressure (pressure units) |
|<B>PBV</B> (pressure breaker valve) | Pressure, psi (m) | |<B>PBV</B> (pressure breaker valve) | Pressure (pressure units) |
|<B>FCV</B> (flow control valve) | Flow (flow 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 | |<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). 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:__ __Remarks:__
1. The [BACKDROP] section is optional and only provides support for an external GUI program that uses the EPANET engine. 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. 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. 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. 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. 3. The optional anchor node anchors the label to the node when the network layout is re-scaled during zoom-in operations.

View File

@@ -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_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_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_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_getcount(EN_Project ph, int code, int *count)
@fn int EN_gettitle(EN_Project ph, char *line1, char *line2, char *line3) @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_saveinpfile(EN_Project ph, const char *filename)
@fn int EN_close(EN_Project ph) @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 @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_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_clearreport(EN_Project ph)
@fn int EN_resetreport(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_setstatusreport(EN_Project ph, int code)
@fn int EN_getversion(int *version) @fn int EN_getversion(int *version)
@fn int EN_geterror(int errcode, char *errmsg, int maxLen) @fn int EN_geterror(int errcode, char *errmsg, int maxLen)
@fn int EN_getstatistic(EN_Project ph, int type, double* value) @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_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 @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_setoption(EN_Project ph, int option, double value)
@fn int EN_getflowunits(EN_Project ph, int *units) @fn int EN_getflowunits(EN_Project ph, int *units)
@fn int EN_setflowunits(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_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_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_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_deletenode(EN_Project ph, int index, int actionCode)
@fn int EN_getnodeindex(EN_Project ph, char *id, int *index) @fn int EN_getnodeindex(EN_Project ph, const char *id, int *out_index)
@fn int EN_getnodeid(EN_Project ph, int index, char *id) @fn int EN_getnodeid(EN_Project ph, int index, char *out_id)
@fn int EN_setnodeid(EN_Project ph, int index, char *newid) @fn int EN_setnodeid(EN_Project ph, int index, const char *newid)
@fn int EN_getnodetype(EN_Project ph, int index, int *code) @fn int EN_getnodetype(EN_Project ph, int index, int *out_nodeType)
@fn int EN_getnodevalue(EN_Project ph, int index, int code, double *value) @fn int EN_getnodevalue(EN_Project ph, int index, int property, double *out_value)
@fn int EN_setnodevalue(EN_Project ph, int index, int code, double v) @fn int EN_getnodevalues(EN_Project ph, int property, double *out_values)
@fn int EN_setjuncdata(EN_Project ph, int index, double elev, double dmnd, char *dmndpat) @fn int EN_setnodevalue(EN_Project ph, int index, int property, double value)
@fn int EN_settankdata(EN_Project ph, int index, double elev, double initlvl, @fn int EN_setjuncdata(EN_Project ph, int index, double elev, double dmnd, const char *dmndpat)
double minlvl, double maxlvl, double diam, double minvol, char *volcurve) @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 *x, double *y) @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) @fn int EN_setcoord(EN_Project ph, int index, double x, double y)
@} @}*/
*/
/** /**
@addtogroup Demands @addtogroup Demands
@{ @{
@fn int EN_getdemandmodel(EN_Project ph, int *type, double *pmin, double *preq, double *pexp) @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_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_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_getnumdemands(EN_Project ph, int nodeIndex, int *numDemands)
@fn int EN_getbasedemand(EN_Project ph, int nodeIndex, int demandIndex, double *baseDemand) @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_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_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_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_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 @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_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_getlinkid(EN_Project ph, int index, char *id)
@fn int EN_setlinkid(EN_Project ph, int index, char *newid) @fn int EN_setlinkid(EN_Project ph, int index, const char *newid)
@fn int EN_getlinktype(EN_Project ph, int index, int *linkType) @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_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_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_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_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_getpumptype(EN_Project ph, int linkIndex, int *out_pumpType)
@fn int EN_getheadcurveindex(EN_Project ph, int pumpIndex, int *curveIndex) @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_setheadcurveindex(EN_Project ph, int pumpIndex, int curveIndex)
@fn int EN_getvertexcount(EN_Project ph, int index, int *count) @fn int EN_getvertexcount(EN_Project ph, int index, int *out_count)
@fn int EN_getvertex(EN_Project ph, int index, int vertex, double *x, double *y) @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) @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 @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_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_getpatternid(EN_Project ph, int index, char *id)
@fn int EN_setpatternid(EN_Project ph, int index, char *id) @fn int EN_setpatternid(EN_Project ph, int index, const char *id)
@fn int EN_getpatternlen(EN_Project ph, int index, int *len) @fn int EN_getpatternlen(EN_Project ph, int index, int *out_len)
@fn int EN_getpatternvalue(EN_Project ph, int index, int period, double *value) @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_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_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 @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_deletecurve(EN_Project ph, int index)
@fn int EN_getcurveindex(EN_Project ph, char *id, int *index) @fn int EN_getcurveindex(EN_Project ph, const char *id, int *out_index)
@fn int EN_getcurveid(EN_Project ph, int index, char *id) @fn int EN_getcurveid(EN_Project ph, int index, char *out_id)
@fn int EN_setcurveid(EN_Project ph, int index, char *id) @fn int EN_setcurveid(EN_Project ph, int index, const char *id)
@fn int EN_getcurvelen(EN_Project ph, int index, int *len) @fn int EN_getcurvelen(EN_Project ph, int index, int *out_len)
@fn int EN_getcurvetype(EN_Project ph, int index, int *type) @fn int EN_getcurvetype(EN_Project ph, int index, int *out_type)
@fn int EN_getcurvevalue(EN_Project ph, int curveIndex, int pointIndex, double *x, double *y) @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_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) @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 @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_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_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_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_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_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 @addtogroup Enumerations
@{ @{
\enum EN_SizeLimits \typedef EN_SizeLimits
\enum EN_ObjectType \typedef EN_ObjectType
\enum EN_CountType \typedef EN_CountType
\enum EN_NodeType \typedef EN_NodeType
\enum EN_LinkType \typedef EN_LinkType
\enum EN_PumpType \typedef EN_PumpType
\enum EN_PumpStateType \typedef EN_PumpStateType
\enum EN_CurveType \typedef EN_CurveType
\enum EN_QualityType \typedef EN_QualityType
\enum EN_SourceType \typedef EN_SourceType
\enum EN_ControlType \typedef EN_ControlType
\enum EN_HeadLossType \typedef EN_HeadLossType
\enum EN_NodeProperty \typedef EN_NodeProperty
\enum EN_LinkProperty \typedef EN_LinkProperty
\enum EN_LinkStatusType \typedef EN_LinkStatusType
\enum EN_TimeParameter \typedef EN_TimeParameter
\enum EN_Option \typedef EN_TimestepEvent
\enum EN_FlowUnits \typedef EN_Option
\enum EN_DemandModel \typedef EN_FlowUnits
\enum EN_MixingModel \typedef EN_PressUnits
\enum EN_StatisticType \typedef EN_DemandModel
\enum EN_InitHydOption \typedef EN_MixingModel
\enum EN_ActionCodeType \typedef EN_StatisticType
\enum EN_AnalysisStatistic \typedef EN_InitHydOption
\enum EN_StatusReport \typedef EN_ActionCodeType
\enum EN_RuleObject \typedef EN_AnalysisStatistic
\enum EN_RuleVariable \typedef EN_StatusReport
\enum EN_RuleOperator \typedef EN_RuleObject
\enum EN_RuleStatus \typedef EN_RuleVariable
\typedef EN_RuleOperator
\typedef EN_RuleStatus
\def EN_MISSING \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 | | 226 | No head curve or power rating for pump |
| 227 | Invalid head curve for pump | | 227 | Invalid head curve for pump |
| 230 | Nonincreasing x-values for curve | | 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 | | 240 | Function call refers to nonexistent water quality source |
| 241 | Function call refers to nonexistent control | | 241 | Function call refers to nonexistent control |
| 250 | Function call contains invalid format (e.g. too long an ID name) | | 250 | Function call contains invalid format (e.g. too long an ID name) |
| 251 | Function call contains invalid parameter code | | 251 | Function call contains invalid parameter code |
| 252 | Function call rferes to an invalid ID name |
| 253 | Function call refers to nonexistent demand category | | 253 | Function call refers to nonexistent demand category |
| 254 | Function call refers to node with no coordinates | | 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 | | 257 | Function call refers to nonexistent rule |
| 258 | Function call refers to nonexistent rule clause | | 258 | Function call refers to nonexistent rule clause |
| 259 | Function call attempts to delete a node that still has links connected to it | | 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 | | 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 | | 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 | | 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 | | 301 | Identical file names used for different types of files |
| 302 | Cannot open input file | | 302 | Cannot open input file |

View File

@@ -2,7 +2,7 @@
/** /**
@page Units Measurement Units @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 | | 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) | |Flow | CFS (cubic feet / sec) | LPS (liters / sec) |
| | GPM (gallons / min) | LPM (liters / min) | | | GPM (gallons / min) | LPM (liters / min) |
| | MGD (million gal / day) | MLD (megaliters / day) | | | MGD (million gal / day) | MLD (megaliters / day) |
| | IMGD (Imperial MGD) | CMH (cubic meters / hr) | | | IMGD (Imperial MGD) | CMS (cubic meters / sec) |
| | AFD (acre-feet / day) | CMD (cubic meters / day) | | | AFD (acre-feet / day) | CMH (cubic meters / hr) |
| | | CMD (cubic meters / day) |
|Friction Factor | unitless | unitless | |Friction Factor | unitless | unitless |
|Head | feet | meters | |Head | feet | meters |
|Length | feet | meters | |Length | feet | meters |
|Minor Loss Coeff. | unitless | unitless | |Minor Loss Coeff. | unitless | unitless |
|Power | horsepower | kwatts | |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. (Bulk) | 1/day (1st-order)| 1/day (1st-order) |
|Reaction Coeff. (Wall) | mass/sq-ft/day (0-order) | mass/sq-m/day (0-order) | |Reaction Coeff. (Wall) | mass/sq-ft/day (0-order) | mass/sq-m/day (0-order) |
| | ft/day (1st-order) | meters/day (1st-order) | | | ft/day (1st-order) | meters/day (1st-order) |

View File

@@ -34,7 +34,7 @@ void runHydraulics(EN_Project ph, char *inputFile, char *reportFile)
ERRCODE(EN_solveH(ph)); ERRCODE(EN_solveH(ph));
ERRCODE(EN_saveH(ph)); ERRCODE(EN_saveH(ph));
ERRCODE(EN_report(ph)); ERRCODE(EN_report(ph));
EN_geterror(ph, errcode, errmsg); EN_geterror(errcode, errmsg, EN_MAXMSG);
if (errcode) printf("\n%s\n", errmsg); if (errcode) printf("\n%s\n", errmsg);
} }
\endcode \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 . 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} \code {.c}
int index; 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.). 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. 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.
@@ -178,15 +178,23 @@ int runConcurrentQuality(EN_Project ph)
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: 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: | |For Nodes: | For Links: |
|----------------------------------- | ----------------------------------------- | |------------------------------------ | ----------------------------------------- |
|\b EN_DEMAND (demand) |\b EN_FLOW (flow rate) | |\b EN_DEMAND (total node outflow |\b EN_FLOW (flow rate) |
|\b EN_DEMANDDEFICIT (demand deficit) |\b EN_VELOCITY (flow velocity) | |\b EN_HEAD (hydraulic head) |\b EN_VELOCITY (flow velocity) |
|\b EN_HEAD (hydraulic head) |\b EN_HEADLOSS (head loss) | |\b EN_PRESSURE (pressure) |\b EN_HEADLOSS (head loss) |
|\b EN_PRESSURE (pressure) |\b EN_STATUS (link status) | |\b EN_TANKLEVEL (tank water level) |\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_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_ENERGY (pump energy usage) |
|\b EN_QUALITY (water quality) |\b EN_PUMP_EFFIC (pump efficiency) | |\b EN_SOURCEMASS (source mass inflow)|\b EN_PUMP_EFFIC (pump efficiency) |
|\b EN_SOURCEMASS (source mass inflow)| | | |\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): 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} \code {.c}

View File

@@ -5,7 +5,7 @@ Attribute VB_Name = "Module1"
'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT 'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT
'(EPANET2.DLL) '(EPANET2.DLL)
'Last updated on 11/04/2019 'Last updated on 04/23/2025
' These are codes used by the DLL functions ' These are codes used by the DLL functions
Public Const EN_ELEVATION = 0 ' Node parameters Public Const EN_ELEVATION = 0 ' Node parameters
@@ -25,7 +25,6 @@ Public Const EN_SOURCEMASS = 13
Public Const EN_INITVOLUME = 14 Public Const EN_INITVOLUME = 14
Public Const EN_MIXMODEL = 15 Public Const EN_MIXMODEL = 15
Public Const EN_MIXZONEVOL = 16 Public Const EN_MIXZONEVOL = 16
Public Const EN_TANKDIAM = 17 Public Const EN_TANKDIAM = 17
Public Const EN_MINVOLUME = 18 Public Const EN_MINVOLUME = 18
Public Const EN_VOLCURVE = 19 Public Const EN_VOLCURVE = 19
@@ -37,6 +36,11 @@ Public Const EN_TANKVOLUME = 24
Public Const EN_MAXVOLUME = 25 Public Const EN_MAXVOLUME = 25
Public Const EN_CANOVERFLOW = 26 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_DIAMETER = 0 ' Link parameters
Public Const EN_LENGTH = 1 Public Const EN_LENGTH = 1
@@ -54,7 +58,6 @@ Public Const EN_SETTING = 12
Public Const EN_ENERGY = 13 Public Const EN_ENERGY = 13
Public Const EN_LINKQUAL = 14 Public Const EN_LINKQUAL = 14
Public Const EN_LINKPATTERN = 15 Public Const EN_LINKPATTERN = 15
Public Const EN_PUMP_STATE = 16 Public Const EN_PUMP_STATE = 16
Public Const EN_PUMP_EFFIC = 17 Public Const EN_PUMP_EFFIC = 17
Public Const EN_PUMP_POWER = 18 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_ECURVE = 20
Public Const EN_PUMP_ECOST = 21 Public Const EN_PUMP_ECOST = 21
Public Const EN_PUMP_EPAT = 22 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_DURATION = 0 ' Time parameters
Public Const EN_HYDSTEP = 1 Public Const EN_HYDSTEP = 1
@@ -78,6 +88,7 @@ Public Const EN_HTIME = 11
Public Const EN_QTIME = 12 Public Const EN_QTIME = 12
Public Const EN_HALTFLAG = 13 Public Const EN_HALTFLAG = 13
Public Const EN_NEXTEVENT = 14 Public Const EN_NEXTEVENT = 14
Public Const EN_NEXTEVENTTANK = 15
Public Const EN_ITERATIONS = 0 ' Run statistics Public Const EN_ITERATIONS = 0 ' Run statistics
Public Const EN_RELATIVEERROR = 1 Public Const EN_RELATIVEERROR = 1
@@ -86,6 +97,7 @@ Public Const EN_MAXFLOWCHANGE = 3
Public Const EN_MASSBALANCE = 4 Public Const EN_MASSBALANCE = 4
Public Const EN_DEFICIENTNODES = 5 Public Const EN_DEFICIENTNODES = 5
Public Const EN_DEMANDREDUCTION = 6 Public Const EN_DEMANDREDUCTION = 6
Public Const EN_LEAKAGELOSS = 7
Public Const EN_NODE = 0 ' Component types Public Const EN_NODE = 0 ' Component types
Public Const EN_LINK = 1 Public Const EN_LINK = 1
@@ -115,6 +127,15 @@ Public Const EN_PBV = 5
Public Const EN_FCV = 6 Public Const EN_FCV = 6
Public Const EN_TCV = 7 Public Const EN_TCV = 7
Public Const EN_GPV = 8 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_NONE = 0 ' Quality analysis types
Public Const EN_CHEM = 1 Public Const EN_CHEM = 1
@@ -140,6 +161,13 @@ Public Const EN_LPM = 6
Public Const EN_MLD = 7 Public Const EN_MLD = 7
Public Const EN_CMH = 8 Public Const EN_CMH = 8
Public Const EN_CMD = 9 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_DDA = 0 ' Demand driven analysis
Public Const EN_PDA = 1 ' Pressure driven analysis Public Const EN_PDA = 1 ' Pressure driven analysis
@@ -167,13 +195,18 @@ Public Const EN_BULKORDER = 19
Public Const EN_WALLORDER = 20 Public Const EN_WALLORDER = 20
Public Const EN_TANKORDER = 21 Public Const EN_TANKORDER = 21
Public Const EN_CONCENLIMIT = 22 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_LOWLEVEL = 0 ' Control types
Public Const EN_HILEVEL = 1 Public Const EN_HILEVEL = 1
Public Const EN_TIMER = 2 Public Const EN_TIMER = 2
Public Const EN_TIMEOFDAY = 3 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_MINIMUM = 2
Public Const EN_MAXIMUM = 3 Public Const EN_MAXIMUM = 3
Public Const EN_RANGE = 4 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_SAVE_AND_INIT = 11
Public Const EN_CONST_HP = 0 ' Constant horsepower pump curve 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_CUSTOM = 2 ' User-defined custom pump curve
Public Const EN_NOCURVE = 3 ' No 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_EFFIC_CURVE = 2 ' Efficiency curve
Public Const EN_HLOSS_CURVE = 3 ' Head loss curve Public Const EN_HLOSS_CURVE = 3 ' Head loss curve
Public Const EN_GENERIC_CURVE = 4 ' Generic 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_UNCONDITIONAL = 0 ' Unconditional object deletion
Public Const EN_CONDITIONAL = 1 ' Conditional 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_CLOSED = 2
Public Const EN_R_IS_ACTIVE = 3 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 '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 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 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 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 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 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 ENsaveinpfile Lib "epanet2.dll" (ByVal filename As String) As Long
Declare Function ENclose Lib "epanet2.dll" () 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 'Hydraulic Analysis Functions
Declare Function ENsolveH Lib "epanet2.dll" () As Long Declare Function ENsolveH Lib "epanet2.dll" () As Long
Declare Function ENsaveH 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 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 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 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 'Analysis Options Functions
Declare Function ENgetoption Lib "epanet2.dll" (ByVal option_ As Long, value As Single) As Long 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 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 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 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 'Nodal Demand Functions
Declare Function ENgetdemandmodel Lib "epanet2.dll" (type_ As Long, pmin As Single, preq As Single, pexp As Single) As Long 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 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 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 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 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 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 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 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 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 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 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 'Pump Functions
Declare Function ENgetheadcurveindex Lib "epanet2.dll" (ByVal linkIndex As Long, curveIndex As Long) As Long 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 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 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 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 'Data Curve Functions
Declare Function ENaddcurve Lib "epanet2.dll" (ByVal id As String) As Long 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 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 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 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 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 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 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,6 +432,8 @@ Public Const EN_MISSING As Double = -1.0E10
Declare Function ENdeletecontrol Lib "epanet2.dll" (ByVal index As Long) As Long 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 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 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 'Rule-Based Control Functions
Declare Function ENaddrule Lib "epanet2.dll" (ByVal rule As String) As Long Declare Function ENaddrule Lib "epanet2.dll" (ByVal rule As String) 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 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 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 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
View 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
}
}

View File

@@ -25,6 +25,7 @@ EXPORTS
ENgetbasedemand = _ENgetbasedemand@12 ENgetbasedemand = _ENgetbasedemand@12
ENgetcomment = _ENgetcomment@12 ENgetcomment = _ENgetcomment@12
ENgetcontrol = _ENgetcontrol@24 ENgetcontrol = _ENgetcontrol@24
ENgetcontrolenabled = _ENgetcontrolenabled@8
ENgetcoord = _ENgetcoord@12 ENgetcoord = _ENgetcoord@12
ENgetcount = _ENgetcount@8 ENgetcount = _ENgetcount@8
ENgetcurve = _ENgetcurve@20 ENgetcurve = _ENgetcurve@20
@@ -44,13 +45,14 @@ EXPORTS
ENgetlinkid = _ENgetlinkid@8 ENgetlinkid = _ENgetlinkid@8
ENgetlinkindex = _ENgetlinkindex@8 ENgetlinkindex = _ENgetlinkindex@8
ENgetlinknodes = _ENgetlinknodes@12 ENgetlinknodes = _ENgetlinknodes@12
ENsetlinknodes = _ENsetlinknodes@12
ENgetlinktype = _ENgetlinktype@8 ENgetlinktype = _ENgetlinktype@8
ENgetlinkvalue = _ENgetlinkvalue@12 ENgetlinkvalue = _ENgetlinkvalue@12
ENgetlinkvalues = _ENgetlinkvalues@8
ENgetnodeid = _ENgetnodeid@8 ENgetnodeid = _ENgetnodeid@8
ENgetnodeindex = _ENgetnodeindex@8 ENgetnodeindex = _ENgetnodeindex@8
ENgetnodetype = _ENgetnodetype@8 ENgetnodetype = _ENgetnodetype@8
ENgetnodevalue = _ENgetnodevalue@12 ENgetnodevalue = _ENgetnodevalue@12
ENgetnodevalues = _ENgetnodevalues@8
ENgetnumdemands = _ENgetnumdemands@8 ENgetnumdemands = _ENgetnumdemands@8
ENgetoption = _ENgetoption@8 ENgetoption = _ENgetoption@8
ENgetpatternid = _ENgetpatternid@8 ENgetpatternid = _ENgetpatternid@8
@@ -63,8 +65,10 @@ EXPORTS
ENgetqualtype = _ENgetqualtype@8 ENgetqualtype = _ENgetqualtype@8
ENgetresultindex = _ENgetresultindex@12 ENgetresultindex = _ENgetresultindex@12
ENgetrule = _ENgetrule@20 ENgetrule = _ENgetrule@20
ENgetruleenabled = _ENgetruleenabled@8
ENgetruleID = _ENgetruleID@8 ENgetruleID = _ENgetruleID@8
ENgetstatistic = _ENgetstatistic@8 ENgetstatistic = _ENgetstatistic@8
ENgettag = _ENgettag@12
ENgetthenaction = _ENgetthenaction@20 ENgetthenaction = _ENgetthenaction@20
ENgettimeparam = _ENgettimeparam@8 ENgettimeparam = _ENgettimeparam@8
ENgettitle = _ENgettitle@12 ENgettitle = _ENgettitle@12
@@ -74,11 +78,13 @@ EXPORTS
ENinit = _ENinit@16 ENinit = _ENinit@16
ENinitH = _ENinitH@4 ENinitH = _ENinitH@4
ENinitQ = _ENinitQ@4 ENinitQ = _ENinitQ@4
ENloadpatternfile = _ENloadpatternfile@8
ENnextH = _ENnextH@4 ENnextH = _ENnextH@4
ENnextQ = _ENnextQ@4 ENnextQ = _ENnextQ@4
ENopen = _ENopen@12 ENopen = _ENopen@12
ENopenH = _ENopenH@0 ENopenH = _ENopenH@0
ENopenQ = _ENopenQ@0 ENopenQ = _ENopenQ@0
ENopenX = _ENopenX@12
ENreport = _ENreport@0 ENreport = _ENreport@0
ENresetreport = _ENresetreport@0 ENresetreport = _ENresetreport@0
ENrunH = _ENrunH@4 ENrunH = _ENrunH@4
@@ -89,9 +95,11 @@ EXPORTS
ENsetbasedemand = _ENsetbasedemand@12 ENsetbasedemand = _ENsetbasedemand@12
ENsetcomment = _ENsetcomment@12 ENsetcomment = _ENsetcomment@12
ENsetcontrol = _ENsetcontrol@24 ENsetcontrol = _ENsetcontrol@24
ENsetcontrolenabled = _ENsetcontrolenabled@8
ENsetcoord = _ENsetcoord@20 ENsetcoord = _ENsetcoord@20
ENsetcurve = _ENsetcurve@16 ENsetcurve = _ENsetcurve@16
ENsetcurveid = _ENsetcurveid@8 ENsetcurveid = _ENsetcurveid@8
ENsetcurvetype = _ENsetcurvetype@8
ENsetcurvevalue = _ENsetcurvevalue@16 ENsetcurvevalue = _ENsetcurvevalue@16
ENsetdemandmodel = _ENsetdemandmodel@16 ENsetdemandmodel = _ENsetdemandmodel@16
ENsetdemandname = _ENsetdemandname@12 ENsetdemandname = _ENsetdemandname@12
@@ -117,15 +125,19 @@ EXPORTS
ENsetpremisevalue = _ENsetpremisevalue@12 ENsetpremisevalue = _ENsetpremisevalue@12
ENsetqualtype = _ENsetqualtype@16 ENsetqualtype = _ENsetqualtype@16
ENsetreport = _ENsetreport@4 ENsetreport = _ENsetreport@4
ENsetruleenabled = _ENsetruleenabled@8
ENsetrulepriority = _ENsetrulepriority@8 ENsetrulepriority = _ENsetrulepriority@8
ENsetstatusreport = _ENsetstatusreport@4 ENsetstatusreport = _ENsetstatusreport@4
ENsettag = _ENsettag@12
ENsettankdata = _ENsettankdata@32 ENsettankdata = _ENsettankdata@32
ENsetthenaction = _ENsetthenaction@20 ENsetthenaction = _ENsetthenaction@20
ENsettimeparam = _ENsettimeparam@8 ENsettimeparam = _ENsettimeparam@8
ENsettitle = _ENsettitle@12 ENsettitle = _ENsettitle@12
ENsetvertex = _ENsetvertex@24
ENsetvertices = _ENsetvertices@16 ENsetvertices = _ENsetvertices@16
ENsolveH = _ENsolveH@0 ENsolveH = _ENsolveH@0
ENsolveQ = _ENsolveQ@0 ENsolveQ = _ENsolveQ@0
ENstepQ = _ENstepQ@4 ENstepQ = _ENstepQ@4
ENtimetonextevent = _ENtimetonextevent@12
ENusehydfile = _ENusehydfile@4 ENusehydfile = _ENusehydfile@4
ENwriteline = _ENwriteline@4 ENwriteline = _ENwriteline@4

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: epanet2.h Module: epanet2.h
Description: declarations of the legacy style EPANET 2 API functions Description: declarations of the legacy style EPANET 2 API functions
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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 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 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 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 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 a legacy style API function declared here please refer to its complementary named
function in epanet2_2.h. function in epanet2_2.h.
@@ -73,13 +73,20 @@ extern "C" {
int DLLEXPORT ENopen(const char *inpFile, const char *rptFile, int DLLEXPORT ENopen(const char *inpFile, const char *rptFile,
const char *outFile); 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 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 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); int DLLEXPORT ENgetcount(int object, int *count);
@@ -107,9 +114,9 @@ extern "C" {
int DLLEXPORT ENcloseH(); 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 ENreport();
int DLLEXPORT ENcopyreport(char *filename); int DLLEXPORT ENcopyreport(const char *filename);
int DLLEXPORT ENclearreport(); int DLLEXPORT ENclearreport();
int DLLEXPORT ENresetreport(); int DLLEXPORT ENresetreport();
int DLLEXPORT ENsetreport(char *format); int DLLEXPORT ENsetreport(const char *format);
int DLLEXPORT ENsetstatusreport(int level); int DLLEXPORT ENsetstatusreport(int level);
@@ -159,6 +166,13 @@ extern "C" {
int DLLEXPORT ENgetresultindex(int type, int index, int *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 Analysis Options Functions
@@ -182,8 +196,8 @@ extern "C" {
int DLLEXPORT ENgetqualtype(int *qualType, int *traceNode); int DLLEXPORT ENgetqualtype(int *qualType, int *traceNode);
int DLLEXPORT ENsetqualtype(int qualType, char *chemName, char *chemUnits, int DLLEXPORT ENsetqualtype(int qualType, const char *chemName,
char *traceNode); 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 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 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 ENgetnodetype(int index, int *nodeType);
int DLLEXPORT ENgetnodevalue(int index, int property, EN_API_FLOAT_TYPE *value); 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 ENsetnodevalue(int index, int property, EN_API_FLOAT_TYPE value);
int DLLEXPORT ENsetjuncdata(int index, EN_API_FLOAT_TYPE elev, 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, int DLLEXPORT ENsettankdata(int index, EN_API_FLOAT_TYPE elev,
EN_API_FLOAT_TYPE initlvl, EN_API_FLOAT_TYPE minlvl, EN_API_FLOAT_TYPE initlvl, EN_API_FLOAT_TYPE minlvl,
EN_API_FLOAT_TYPE maxlvl, EN_API_FLOAT_TYPE diam, 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); 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); EN_API_FLOAT_TYPE preq, EN_API_FLOAT_TYPE pexp);
int DLLEXPORT ENadddemand(int nodeIndex, EN_API_FLOAT_TYPE baseDemand, 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 ENdeletedemand(int nodeIndex, int demandIndex);
int DLLEXPORT ENgetnumdemands(int nodeIndex, int *numDemands); 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, int DLLEXPORT ENgetbasedemand(int nodeIndex, int demandIndex,
EN_API_FLOAT_TYPE *baseDemand); EN_API_FLOAT_TYPE *baseDemand);
@@ -252,7 +269,7 @@ extern "C" {
int DLLEXPORT ENgetdemandname(int nodeIndex, int demandIndex, char *demandName); 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 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 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); int DLLEXPORT ENgetlinktype(int index, int *linkType);
@@ -280,6 +298,8 @@ extern "C" {
int DLLEXPORT ENgetlinkvalue(int index, int property, EN_API_FLOAT_TYPE *value); 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 ENsetlinkvalue(int index, int property, EN_API_FLOAT_TYPE value);
int DLLEXPORT ENsetpipedata(int index, EN_API_FLOAT_TYPE length, int DLLEXPORT ENsetpipedata(int index, EN_API_FLOAT_TYPE length,
@@ -290,6 +310,8 @@ extern "C" {
int DLLEXPORT ENgetvertex(int index, int vertex, double *x, double *y); 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); 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 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 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); 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 ENsetpattern(int index, EN_API_FLOAT_TYPE *values, int len);
int DLLEXPORT ENloadpatternfile(const char *filename, const char *id);
/******************************************************************** /********************************************************************
Data Curve Functions Data Curve Functions
********************************************************************/ ********************************************************************/
int DLLEXPORT ENaddcurve(char *id); int DLLEXPORT ENaddcurve(const char *id);
int DLLEXPORT ENdeletecurve(int index); 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 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 ENgetcurvelen(int index, int *len);
int DLLEXPORT ENgetcurvetype(int index, int *type); int DLLEXPORT ENgetcurvetype(int index, int *type);
int DLLEXPORT ENsetcurvetype(int index, int type);
int DLLEXPORT ENgetcurvevalue(int curveIndex, int pointIndex, int DLLEXPORT ENgetcurvevalue(int curveIndex, int pointIndex,
EN_API_FLOAT_TYPE *x, EN_API_FLOAT_TYPE *y); 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, int DLLEXPORT ENsetcontrol(int index, int type, int linkIndex,
EN_API_FLOAT_TYPE setting, int nodeIndex, EN_API_FLOAT_TYPE level); 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);
/******************************************************************** /********************************************************************
@@ -424,6 +453,10 @@ extern "C" {
int DLLEXPORT ENsetrulepriority(int index, EN_API_FLOAT_TYPE priority); 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) #if defined(__cplusplus)
} }
#endif #endif

View File

@@ -3,7 +3,7 @@ unit epanet2;
{ Declarations of imported procedures from the EPANET PROGRAMMERs TOOLKIT } { Declarations of imported procedures from the EPANET PROGRAMMERs TOOLKIT }
{ (EPANET2.DLL) } { (EPANET2.DLL) }
{Last updated on 11/12/19} {Last updated on 04/23/2025}
interface interface
@@ -12,7 +12,9 @@ const
{ These are codes used by the DLL functions } { These are codes used by the DLL functions }
EN_MAXID = 31; { Max. # characters in ID name } EN_MAXID = 31; { Max. # characters in ID name }
EN_MAXMSG = 255; { Max. # characters in strings } 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_ELEVATION = 0; { Node parameters }
EN_BASEDEMAND = 1; EN_BASEDEMAND = 1;
@@ -31,7 +33,6 @@ const
EN_INITVOLUME = 14; EN_INITVOLUME = 14;
EN_MIXMODEL = 15; EN_MIXMODEL = 15;
EN_MIXZONEVOL = 16; EN_MIXZONEVOL = 16;
EN_TANKDIAM = 17; EN_TANKDIAM = 17;
EN_MINVOLUME = 18; EN_MINVOLUME = 18;
EN_VOLCURVE = 19; EN_VOLCURVE = 19;
@@ -43,6 +44,11 @@ const
EN_MAXVOLUME = 25; EN_MAXVOLUME = 25;
EN_CANOVERFLOW = 26; 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_DIAMETER = 0; { Link parameters }
EN_LENGTH = 1; EN_LENGTH = 1;
@@ -67,6 +73,13 @@ const
EN_PUMP_ECURVE = 20; EN_PUMP_ECURVE = 20;
EN_PUMP_ECOST = 21; EN_PUMP_ECOST = 21;
EN_PUMP_EPAT = 22; 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_DURATION = 0; { Time parameters }
EN_HYDSTEP = 1; EN_HYDSTEP = 1;
@@ -92,6 +105,7 @@ const
EN_MASSBALANCE = 4; EN_MASSBALANCE = 4;
EN_DEFICIENTNODES = 5; EN_DEFICIENTNODES = 5;
EN_DEMANDREDUCTION = 6; EN_DEMANDREDUCTION = 6;
EN_LEAKAGELOSS = 7;
EN_NODE = 0; { Component Types } EN_NODE = 0; { Component Types }
EN_LINK = 1; EN_LINK = 1;
@@ -121,6 +135,7 @@ const
EN_FCV = 6; EN_FCV = 6;
EN_TCV = 7; EN_TCV = 7;
EN_GPV = 8; EN_GPV = 8;
EN_PCV = 9;
EN_CLOSED = 0; { Link status types } EN_CLOSED = 0; { Link status types }
EN_OPEN = 1; EN_OPEN = 1;
@@ -154,6 +169,13 @@ const
EN_MLD = 7; EN_MLD = 7;
EN_CMH = 8; EN_CMH = 8;
EN_CMD = 9; 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_DDA = 0; { Demand model types }
EN_PDA = 1; EN_PDA = 1;
@@ -181,6 +203,10 @@ const
EN_WALLORDER = 20; EN_WALLORDER = 20;
EN_TANKORDER = 21; EN_TANKORDER = 21;
EN_CONCENLIMIT = 22; EN_CONCENLIMIT = 22;
EN_DEMANDPATTERN = 23;
EN_EMITBACKFLOW = 24;
EN_PRESS_UNITS = 25;
EN_STATUS_REPORT = 26;
EN_LOWLEVEL = 0; { Control types } EN_LOWLEVEL = 0; { Control types }
EN_HILEVEL = 1; EN_HILEVEL = 1;
@@ -213,6 +239,7 @@ const
EN_EFFIC_CURVE = 2; EN_EFFIC_CURVE = 2;
EN_HLOSS_CURVE = 3; EN_HLOSS_CURVE = 3;
EN_GENERIC_CURVE = 4; EN_GENERIC_CURVE = 4;
EN_VALVE_CURVE = 5;
EN_UNCONDITIONAL = 0; { Deletion action codes } EN_UNCONDITIONAL = 0; { Deletion action codes }
EN_CONDITIONAL = 1; EN_CONDITIONAL = 1;
@@ -254,169 +281,205 @@ const
EN_R_IS_CLOSED = 2; EN_R_IS_CLOSED = 2;
EN_R_IS_ACTIVE = 3; EN_R_IS_ACTIVE = 3;
EN_FALSE = 0; { boolean false }
EN_TRUE = 1; { boolean true }
{$MACRO ON}
{$ifdef MSWINDOWS}
EpanetLib = 'epanet2.dll'; 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} {Project Functions}
function ENepanet(F1: PAnsiChar; F2: PAnsiChar; F3: PAnsiChar; F4: Pointer): 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; stdcall; 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; stdcall; external EpanetLib; function ENopen(F1: PAnsiChar; F2: PAnsiChar; F3: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENgetcount(Code: Integer; var Count: Integer): Integer; stdcall; external EpanetLib; function ENopenX(F1: PAnsiChar; F2: PAnsiChar; F3: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENgettitle(Line1: PAnsiChar; Line2: PAnsiChar; Line3: PAnsiChar): Integer; stdcall; external EpanetLib; function ENgetcount(Code: Integer; var Count: Integer): Integer; cdecl; external EpanetLib;
function ENsettitle(Line1: PAnsiChar; Line2: PAnsiChar; Line3: PAnsiChar): Integer; stdcall; external EpanetLib; function ENgettitle(Line1: PAnsiChar; Line2: PAnsiChar; Line3: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENgetcomment(ObjType: Integer; Index: Integer; Comment: PAnsiChar): Integer; stdcall; external EpanetLib; function ENsettitle(Line1: PAnsiChar; Line2: PAnsiChar; Line3: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENsetcomment(ObjType: Integer; Index: Integer; Comment: PAnsiChar): Integer; stdcall; external EpanetLib; function ENgetcomment(ObjType: Integer; Index: Integer; Comment: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENsaveinpfile(F: PAnsiChar): Integer; stdcall; external EpanetLib; function ENsetcomment(ObjType: Integer; Index: Integer; Comment: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENclose: Integer; stdcall; 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} {Hydraulic Functions}
function ENsolveH: Integer; stdcall; external EpanetLib; function ENsolveH: Integer; cdecl; external EpanetLib;
function ENsaveH: Integer; stdcall; external EpanetLib; function ENsaveH: Integer; cdecl; external EpanetLib;
function ENopenH: Integer; stdcall; external EpanetLib; function ENopenH: Integer; cdecl; external EpanetLib;
function ENinitH(SaveFlag: Integer): Integer; stdcall; external EpanetLib; function ENinitH(SaveFlag: Integer): Integer; cdecl; external EpanetLib;
function ENrunH(var T: LongInt): Integer; stdcall; external EpanetLib; function ENrunH(var T: TimeType): Integer; cdecl; external EpanetLib;
function ENnextH(var Tstep: LongInt): Integer; stdcall; external EpanetLib; function ENnextH(var Tstep: TimeType): Integer; cdecl; external EpanetLib;
function ENcloseH: Integer; stdcall; external EpanetLib; function ENcloseH: Integer; cdecl; external EpanetLib;
function ENsavehydfile(F: PAnsiChar): Integer; stdcall; external EpanetLib; function ENsavehydfile(F: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENusehydfile(F: PAnsiChar): Integer; stdcall; external EpanetLib; function ENusehydfile(F: PAnsiChar): Integer; cdecl; external EpanetLib;
{Quality Functions} {Quality Functions}
function ENsolveQ: Integer; stdcall; external EpanetLib; function ENsolveQ: Integer; cdecl; external EpanetLib;
function ENopenQ: Integer; stdcall; external EpanetLib; function ENopenQ: Integer; cdecl; external EpanetLib;
function ENinitQ(SaveFlag: Integer): Integer; stdcall; external EpanetLib; function ENinitQ(SaveFlag: Integer): Integer; cdecl; external EpanetLib;
function ENrunQ(var T: LongInt): Integer; stdcall; external EpanetLib; function ENrunQ(var T: TimeType): Integer; cdecl; external EpanetLib;
function ENnextQ(var Tstep: LongInt): Integer; stdcall; external EpanetLib; function ENnextQ(var Tstep: TimeType): Integer; cdecl; external EpanetLib;
function ENstepQ(var Tleft: LongInt): Integer; stdcall; external EpanetLib; function ENstepQ(var Tleft: TimeType): Integer; cdecl; external EpanetLib;
function ENcloseQ: Integer; stdcall; external EpanetLib; function ENcloseQ: Integer; cdecl; external EpanetLib;
{Reporting Functions} {Reporting Functions}
function ENwriteline(S: PAnsiChar): Integer; stdcall; external EpanetLib; function ENwriteline(S: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENreport: Integer; stdcall; external EpanetLib; function ENreport: Integer; cdecl; external EpanetLib;
function ENcopyreport(F: PAnsiChar): Integer; stdcall; external EpanetLib; function ENcopyreport(F: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENclearreport: Integer; stdcall; external EpanetLib; function ENclearreport: Integer; cdecl; external EpanetLib;
function ENresetreport: Integer; stdcall; external EpanetLib; function ENresetreport: Integer; cdecl; external EpanetLib;
function ENsetreport(S: PAnsiChar): Integer; stdcall; external EpanetLib; function ENsetreport(S: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENsetstatusreport(Code: Integer): Integer; stdcall; external EpanetLib; function ENsetstatusreport(Code: Integer): Integer; cdecl; external EpanetLib;
function ENgetversion(var Version: Integer): Integer; stdcall; external EpanetLib; function ENgetversion(var Version: Integer): Integer; cdecl; external EpanetLib;
function ENgeterror(Errcode: Integer; Errmsg: PAnsiChar; MaxLen: Integer): Integer; stdcall; external EpanetLib; function ENgeterror(Errcode: Integer; Errmsg: PAnsiChar; MaxLen: Integer): Integer; cdecl; external EpanetLib;
function ENgetstatistic(StatType: Integer; var Value: Single): Integer; stdcall; external EpanetLib; function ENgetstatistic(StatType: Integer; var Value: Single): Integer; cdecl; external EpanetLib;
function ENgetresultindex(Code: Integer; Index: Integer; var Value: Integer): Integer; stdcall; 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} {Analysis Options Functions}
function ENgetoption(Code: Integer; var Value: Single): Integer; stdcall; external EpanetLib; function ENgetoption(Code: Integer; var Value: Single): Integer; cdecl; external EpanetLib;
function ENsetoption(Code: Integer; Value: Single): Integer; stdcall; external EpanetLib; function ENsetoption(Code: Integer; Value: Single): Integer; cdecl; external EpanetLib;
function ENgetflowunits(var Code: Integer): Integer; stdcall; external EpanetLib; function ENgetflowunits(var Code: Integer): Integer; cdecl; external EpanetLib;
function ENsetflowunits(Code: Integer): Integer; stdcall; external EpanetLib; function ENsetflowunits(Code: Integer): Integer; cdecl; external EpanetLib;
function ENgettimeparam(Code: Integer; var Value: LongInt): Integer; stdcall; external EpanetLib; function ENgettimeparam(Code: Integer; var Value: TimeType): Integer; cdecl; external EpanetLib;
function ENsettimeparam(Code: Integer; Value: LongInt): Integer; stdcall; 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; stdcall; 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; stdcall; 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; stdcall; external EpanetLib; function ENsetqualtype(QualCode: Integer; ChemName: PAnsiChar; ChemUnits: PAnsiChar; TraceNodeID: PAnsiChar): Integer; cdecl; external EpanetLib;
{Node Functions} {Node Functions}
function ENaddnode(ID: PAnsiChar; NodeType: Integer; var Index: Integer): Integer; stdcall; external EpanetLib; function ENaddnode(ID: PAnsiChar; NodeType: Integer; var Index: Integer): Integer; cdecl; external EpanetLib;
function ENdeletenode(Index: Integer; ActionCode: Integer): Integer; stdcall; external EpanetLib; function ENdeletenode(Index: Integer; ActionCode: Integer): Integer; cdecl; external EpanetLib;
function ENgetnodeindex(ID: PAnsiChar; var Index: Integer): Integer; stdcall; external EpanetLib; function ENgetnodeindex(ID: PAnsiChar; var Index: Integer): Integer; cdecl; external EpanetLib;
function ENgetnodeid(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib; function ENgetnodeid(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENsetnodeid(Index: Integer; NewID: PAnsiChar): Integer; stdcall; external EpanetLib; function ENsetnodeid(Index: Integer; NewID: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENgetnodetype(Index: Integer; var Code: Integer): Integer; stdcall; external EpanetLib; function ENgetnodetype(Index: Integer; var Code: Integer): Integer; cdecl; external EpanetLib;
function ENgetnodevalue(Index: Integer; Code: Integer; var Value: Single): Integer; stdcall; external EpanetLib; function ENgetnodevalue(Index: Integer; Code: Integer; var Value: Single): Integer; cdecl; external EpanetLib;
function ENsetnodevalue(Index: Integer; Code: Integer; Value: Single): Integer; stdcall; 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; stdcall; 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; stdcall; 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; stdcall; 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; stdcall; 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} {Demand Functions}
function ENgetdemandmodel(var Model: Integer; var Pmin: Single; var Preq: Single; var Pexp: Single): 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; stdcall; external EpanetLib; function ENsetdemandmodel(Model: Integer; Pmin: Single; Preq: Single; Pexp: Single): Integer; cdecl; external EpanetLib;
function ENgetnumdemands(NodeIndex: Integer; var NumDemands: Integer): Integer; stdcall; external EpanetLib; function ENgetnumdemands(NodeIndex: Integer; var NumDemands: Integer): Integer; cdecl; external EpanetLib;
function ENadddemand(NodeIndex: Integer; BaseDemand: Single; PatName: PAnsiChar; DemandName: PAnsiChar): Integer; stdcall; external EpanetLib; function ENadddemand(NodeIndex: Integer; BaseDemand: Single; PatName: PAnsiChar; DemandName: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENdeletedemand(NodeIndex: Integer; DemandIndex: Integer): Integer; stdcall; external EpanetLib; function ENdeletedemand(NodeIndex: Integer; DemandIndex: Integer): Integer; cdecl; external EpanetLib;
function ENgetdemandindex(NodeIndex: Integer; DemandName: PAnsiChar; var DemandIndex: Integer): Integer; stdcall; 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; stdcall; external EpanetLib; function ENgetbasedemand(NodeIndex: Integer; DemandIndex: Integer; var BaseDemand: Single): Integer; cdecl; external EpanetLib;
function ENsetbasedemand(NodeIndex: Integer; DemandIndex: Integer; BaseDemand: Single): Integer; stdcall; external EpanetLib; function ENsetbasedemand(NodeIndex: Integer; DemandIndex: Integer; BaseDemand: Single): Integer; cdecl; external EpanetLib;
function ENgetdemandpattern(NodeIndex: Integer; DemandIndex: Integer; var PatIndex: Integer): Integer; stdcall; external EpanetLib; function ENgetdemandpattern(NodeIndex: Integer; DemandIndex: Integer; var PatIndex: Integer): Integer; cdecl; external EpanetLib;
function ENsetdemandpattern(NodeIndex: Integer; DemandIndex: Integer; PatIndex: Integer): Integer; stdcall; external EpanetLib; function ENsetdemandpattern(NodeIndex: Integer; DemandIndex: Integer; PatIndex: Integer): Integer; cdecl; external EpanetLib;
function ENgetdemandname(NodeIndex: Integer; DemandIndex: Integer; DemandName: PAnsiChar): Integer; stdcall; external EpanetLib; function ENgetdemandname(NodeIndex: Integer; DemandIndex: Integer; DemandName: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENsetdemandname(NodeIndex: Integer; DemandIndex: Integer; DemandName: PAnsiChar): Integer; stdcall; external EpanetLib; function ENsetdemandname(NodeIndex: Integer; DemandIndex: Integer; DemandName: PAnsiChar): Integer; cdecl; external EpanetLib;
{Link Functions} {Link Functions}
function ENaddlink(ID: PAnsiChar; LinkType: Integer; FromNode: PAnsiChar; ToNode: PAnsiChar; var Index: Integer): 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; stdcall; external EpanetLib; function ENdeletelink(Index: Integer; ActionCode: Integer): Integer; cdecl; external EpanetLib;
function ENgetlinkindex(ID: PAnsiChar; var Index: Integer): Integer; stdcall; external EpanetLib; function ENgetlinkindex(ID: PAnsiChar; var Index: Integer): Integer; cdecl; external EpanetLib;
function ENgetlinkid(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib; function ENgetlinkid(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENsetlinkid(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib; function ENsetlinkid(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENgetlinktype(Index: Integer; var Code: Integer): Integer; stdcall; external EpanetLib; function ENgetlinktype(Index: Integer; var Code: Integer): Integer; cdecl; external EpanetLib;
function ENsetlinktype(var Index: Integer; LinkType: Integer; ActionCode: Integer): Integer; stdcall; 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; stdcall; 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; stdcall; external EpanetLib; function ENsetlinknodes(Index: Integer; Node1: Integer; Node2: Integer): Integer; cdecl; external EpanetLib;
function ENgetlinkvalue(Index: Integer; Code: Integer; var Value: Single): Integer; stdcall; external EpanetLib; function ENgetlinkvalue(Index: Integer; Code: Integer; var Value: Single): Integer; cdecl; external EpanetLib;
function ENsetlinkvalue(Index: Integer; Code: Integer; Value: Single): Integer; stdcall; 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; stdcall; 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 ENgetvertexcount(Index: Integer; var Count: Integer): Integer; cdecl; external EpanetLib;
function ENgetvertex(Index: Integer; Vertex: Integer; var X: Double; var Y: Double): Integer; stdcall; external EpanetLib; function ENgetvertex(Index: Integer; Vertex: Integer; var X: Double; var Y: Double): Integer; cdecl; external EpanetLib;
function ENsetvertices(Index: Integer; var X: Double; var Y: Double; Count: Integer): Integer; stdcall; 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} {Pump Functions}
function ENgetpumptype(LinkIndex: Integer; var PumpType: Integer): Integer; stdcall; external EpanetLib; function ENgetpumptype(LinkIndex: Integer; var PumpType: Integer): Integer; cdecl; external EpanetLib;
function ENgetheadcurveindex(LinkIndex: Integer; var CurveIndex: Integer): Integer; stdcall; external EpanetLib; function ENgetheadcurveindex(LinkIndex: Integer; var CurveIndex: Integer): Integer; cdecl; external EpanetLib;
function ENsetheadcurveindex(LinkIndex: Integer; CurveIndex: Integer): Integer; stdcall; external EpanetLib; function ENsetheadcurveindex(LinkIndex: Integer; CurveIndex: Integer): Integer; cdecl; external EpanetLib;
{Pattern Functions} {Pattern Functions}
function ENaddpattern(ID: PAnsiChar): Integer; stdcall; external EpanetLib; function ENaddpattern(ID: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENdeletepattern(Index: Integer): Integer; stdcall; external EpanetLib; function ENdeletepattern(Index: Integer): Integer; cdecl; external EpanetLib;
function ENgetpatternindex(ID: PAnsiChar; var Index: Integer): Integer; stdcall; external EpanetLib; function ENgetpatternindex(ID: PAnsiChar; var Index: Integer): Integer; cdecl; external EpanetLib;
function ENgetpatternid(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib; function ENgetpatternid(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENsetpatternid(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib; function ENsetpatternid(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENgetpatternlen(Index: Integer; var Len: Integer): Integer; stdcall; external EpanetLib; function ENgetpatternlen(Index: Integer; var Len: Integer): Integer; cdecl; external EpanetLib;
function ENgetpatternvalue(Index: Integer; Period: Integer; var Value: Single): Integer; stdcall; external EpanetLib; function ENgetpatternvalue(Index: Integer; Period: Integer; var Value: Single): Integer; cdecl; external EpanetLib;
function ENsetpatternvalue(Index: Integer; Period: Integer; Value: Single): Integer; stdcall; external EpanetLib; function ENsetpatternvalue(Index: Integer; Period: Integer; Value: Single): Integer; cdecl; external EpanetLib;
function ENgetaveragepatternvalue(Index: Integer; var Value: Single): Integer; stdcall; external EpanetLib; function ENgetaveragepatternvalue(Index: Integer; var Value: Single): Integer; cdecl; external EpanetLib;
function ENsetpattern(Index: Integer; var F: Single; N: Integer): Integer; stdcall; external EpanetLib; function ENsetpattern(Index: Integer; var F: Single; N: Integer): Integer; cdecl; external EpanetLib;
{Curve Functions} {Curve Functions}
function ENaddcurve(ID: PAnsiChar): Integer; stdcall; external EpanetLib; function ENaddcurve(ID: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENdeletecurve(Index: Integer): Integer; stdcall; external EpanetLib; function ENdeletecurve(Index: Integer): Integer; cdecl; external EpanetLib;
function ENgetcurveindex(ID: PAnsiChar; var Index: Integer): Integer; stdcall; external EpanetLib; function ENgetcurveindex(ID: PAnsiChar; var Index: Integer): Integer; cdecl; external EpanetLib;
function ENgetcurveid(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib; function ENgetcurveid(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENsetcurveid(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib; function ENsetcurveid(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENgetcurvelen(Index: Integer; var Len: Integer): Integer; stdcall; external EpanetLib; function ENgetcurvelen(Index: Integer; var Len: Integer): Integer; cdecl; external EpanetLib;
function ENgetcurvetype(Index: Integer; var CurveType: Integer): Integer; stdcall; external EpanetLib; function ENgetcurvetype(Index: Integer; var CurveType: Integer): Integer; cdecl; external EpanetLib;
function ENgetcurvevalue(CurveIndex: Integer; PointIndex: Integer; var X: Single; var Y: Single): Integer; stdcall; external EpanetLib; function ENsetcurvetype(Index: Integer; CurveType: Integer): Integer; cdecl; external EpanetLib;
function ENsetcurvevalue(CurveIndex: Integer; PointIndex: Integer; X: Single; Y: Single): Integer; stdcall; external EpanetLib; function ENgetcurvevalue(CurveIndex: Integer; PointIndex: Integer; var X: Single; var Y: Single): Integer; cdecl; external EpanetLib;
function ENgetcurve(Index: Integer; ID: PAnsiChar; var N: Integer; var X: Single; var Y: Single): Integer; stdcall; external EpanetLib; function ENsetcurvevalue(CurveIndex: Integer; PointIndex: Integer; X: Single; Y: Single): Integer; cdecl; external EpanetLib;
function ENsetcurve(Index: Integer; var X: Single; var Y: Single; N: Integer): Integer; stdcall; 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} {Control Functions}
function ENaddcontrol(Ctype: Integer; Link: Integer; Setting: Single; Node: Integer; Level: Single; var Index: Integer): 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; stdcall; 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; stdcall; 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; stdcall; 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} {Rule-Based Control Functions}
function ENaddrule(Rule: PAnsiChar): Integer; stdcall; external EpanetLib; function ENaddrule(Rule: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENdeleterule(Index: Integer): Integer; stdcall; external EpanetLib; function ENdeleterule(Index: Integer): Integer; cdecl; external EpanetLib;
function ENgetrule(Index: Integer; var Npremises: Integer; var NthenActions: Integer; function ENgetrule(Index: Integer; var Npremises: Integer; var NthenActions: Integer;
var NelseActions: Integer; var Priority: Single): Integer; stdcall; external EpanetLib; var NelseActions: Integer; var Priority: Single): Integer; cdecl; external EpanetLib;
function ENgetruleID(Index: Integer; ID: PAnsiChar): Integer; stdcall; external EpanetLib; function ENgetruleID(Index: Integer; ID: PAnsiChar): Integer; cdecl; external EpanetLib;
function ENsetrulepriority(Index: Integer; Priority: Single): Integer; stdcall; external EpanetLib; function ENsetrulepriority(Index: Integer; Priority: Single): Integer; cdecl; external EpanetLib;
function ENgetpremise(RuleIndex: Integer; PremiseIndex: Integer; var LogOp: Integer; function ENgetpremise(RuleIndex: Integer; PremiseIndex: Integer; var LogOp: Integer;
var ObjType: Integer; var ObjIndex: Integer; var Param: Integer; var RelOp: 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; function ENsetpremise(RuleIndex: Integer; PremiseIndex: Integer; LogOp: Integer; ObjType: Integer;
ObjIndex: Integer; Param: Integer; RelOp: Integer; Status: 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; stdcall; external EpanetLib; function ENsetpremiseindex(RuleIndex: Integer; PremiseIndex: Integer; ObjIndex: Integer): Integer; cdecl; external EpanetLib;
function ENsetpremisestatus(RuleIndex: Integer; PremiseIndex: Integer; Status: Integer): Integer; stdcall; external EpanetLib; function ENsetpremisestatus(RuleIndex: Integer; PremiseIndex: Integer; Status: Integer): Integer; cdecl; external EpanetLib;
function ENsetpremisevalue(RuleIndex: Integer; PremiseIndex: Integer; Value: Single): Integer; stdcall; external EpanetLib; function ENsetpremisevalue(RuleIndex: Integer; PremiseIndex: Integer; Value: Single): Integer; cdecl; external EpanetLib;
function ENgetthenaction(RuleIndex: Integer; ActionIndex: Integer; var LinkIndex: Integer; 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; 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; 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; 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 implementation

View File

@@ -4,7 +4,7 @@
'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT 'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT
'(EPANET2.DLL) for use with VB.Net. '(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.Runtime.InteropServices
Imports System.Text Imports System.Text
@@ -29,7 +29,6 @@ Public Const EN_SOURCEMASS = 13
Public Const EN_INITVOLUME = 14 Public Const EN_INITVOLUME = 14
Public Const EN_MIXMODEL = 15 Public Const EN_MIXMODEL = 15
Public Const EN_MIXZONEVOL = 16 Public Const EN_MIXZONEVOL = 16
Public Const EN_TANKDIAM = 17 Public Const EN_TANKDIAM = 17
Public Const EN_MINVOLUME = 18 Public Const EN_MINVOLUME = 18
Public Const EN_VOLCURVE = 19 Public Const EN_VOLCURVE = 19
@@ -37,11 +36,15 @@ Public Const EN_MINLEVEL = 20
Public Const EN_MAXLEVEL = 21 Public Const EN_MAXLEVEL = 21
Public Const EN_MIXFRACTION = 22 Public Const EN_MIXFRACTION = 22
Public Const EN_TANK_KBULK = 23 Public Const EN_TANK_KBULK = 23
Public Const EN_TANKVOLUME = 24 Public Const EN_TANKVOLUME = 24
Public Const EN_MAXVOLUME = 25 Public Const EN_MAXVOLUME = 25
Public Const EN_CANOVERFLOW = 26 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_DIAMETER = 0 ' Link parameters
Public Const EN_LENGTH = 1 Public Const EN_LENGTH = 1
@@ -59,7 +62,6 @@ Public Const EN_SETTING = 12
Public Const EN_ENERGY = 13 Public Const EN_ENERGY = 13
Public Const EN_LINKQUAL = 14 Public Const EN_LINKQUAL = 14
Public Const EN_LINKPATTERN = 15 Public Const EN_LINKPATTERN = 15
Public Const EN_PUMP_STATE = 16 Public Const EN_PUMP_STATE = 16
Public Const EN_PUMP_EFFIC = 17 Public Const EN_PUMP_EFFIC = 17
Public Const EN_PUMP_POWER = 18 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_ECURVE = 20
Public Const EN_PUMP_ECOST = 21 Public Const EN_PUMP_ECOST = 21
Public Const EN_PUMP_EPAT = 22 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_DURATION = 0 ' Time parameters
Public Const EN_HYDSTEP = 1 Public Const EN_HYDSTEP = 1
@@ -91,6 +100,7 @@ Public Const EN_MAXFLOWCHANGE = 3
Public Const EN_MASSBALANCE = 4 Public Const EN_MASSBALANCE = 4
Public Const EN_DEFICIENTNODES = 5 Public Const EN_DEFICIENTNODES = 5
Public Const EN_DEMANDREDUCTION = 6 Public Const EN_DEMANDREDUCTION = 6
Public Const EN_LEAKAGELOSS = 7
Public Const EN_NODE = 0 ' Component types Public Const EN_NODE = 0 ' Component types
Public Const EN_LINK = 1 Public Const EN_LINK = 1
@@ -120,6 +130,7 @@ Public Const EN_PBV = 5
Public Const EN_FCV = 6 Public Const EN_FCV = 6
Public Const EN_TCV = 7 Public Const EN_TCV = 7
Public Const EN_GPV = 8 Public Const EN_GPV = 8
Public Const EN_PCV = 9
Public Const EN_NONE = 0 ' Quality analysis types Public Const EN_NONE = 0 ' Quality analysis types
Public Const EN_CHEM = 1 Public Const EN_CHEM = 1
@@ -145,6 +156,13 @@ Public Const EN_LPM = 6
Public Const EN_MLD = 7 Public Const EN_MLD = 7
Public Const EN_CMH = 8 Public Const EN_CMH = 8
Public Const EN_CMD = 9 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_DDA = 0 ' Demand driven analysis
Public Const EN_PDA = 1 ' Pressure 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_WALLORDER = 20
Public Const EN_TANKORDER = 21 Public Const EN_TANKORDER = 21
Public Const EN_CONCENLIMIT = 22 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_LOWLEVEL = 0 ' Control types
Public Const EN_HILEVEL = 1 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_EFFIC_CURVE = 2 ' Efficiency curve
Public Const EN_HLOSS_CURVE = 3 ' Head loss curve Public Const EN_HLOSS_CURVE = 3 ' Head loss curve
Public Const EN_GENERIC_CURVE = 4 ' Generic 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_UNCONDITIONAL = 0 ' Unconditional object deletion
Public Const EN_CONDITIONAL = 1 ' Conditional 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_R_IS_ACTIVE = 3
Public Const EN_MISSING As Double = -1.0E10 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 '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 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 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 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 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 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 ENsaveinpfile Lib "epanet2.dll" (ByVal filename As String) As Int32
Declare Function ENclose Lib "epanet2.dll" () 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 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 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 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 'Analysis Options Functions
Declare Function ENgetoption Lib "epanet2.dll" (ByVal option As Int32, value As Single) As Int32 Declare Function ENgetoption Lib "epanet2.dll" (ByVal option As Int32, value As Single) As Int32
@@ -315,6 +349,7 @@ 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 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 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 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 '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 ENgetdemandmodel Lib "epanet2.dll" (type_ As Int32, pmin As Single, preq As Single, 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 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 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 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 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 'Pump Functions
Declare Function ENgetheadcurveindex Lib "epanet2.dll" (ByVal linkIndex As Int32, curveIndex As Int32) As Int32 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 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 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 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 'Data Curve Functions
Declare Function ENaddcurve Lib "epanet2.dll" (ByVal id As String) As Int32 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 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 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 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 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 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 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 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 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 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 'Rule-Based Control Functions
Declare Function ENaddrule Lib "epanet2.dll" (ByVal rule As String) As Int32 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 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 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 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 End Module

File diff suppressed because it is too large Load Diff

View File

@@ -3,13 +3,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: epanet2_enums.h Module: epanet2_enums.h
Description: enumerations of symbolic constants used by the API functions Description: enumerations of symbolic constants used by the API functions
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 11/06/2019 Last Updated: 04/23/2025
****************************************************************************** ******************************************************************************
*/ */
@@ -17,13 +17,11 @@
#ifndef EPANET2_ENUMS_H #ifndef EPANET2_ENUMS_H
#define EPANET2_ENUMS_H #define EPANET2_ENUMS_H
// --- Define the EPANET toolkit constants // --- Define the EPANET toolkit constants
/// Character array size limits
/// Size Limts /*! \enum EN_SizeLimits
/** * Limits on the size of character arrays used to store ID names
Limits on the size of character arrays used to store ID names * and text messages.
and text messages.
*/ */
typedef enum { typedef enum {
EN_MAXID = 31, //!< Max. # characters in ID name EN_MAXID = 31, //!< Max. # characters in ID name
@@ -31,9 +29,9 @@ typedef enum {
} EN_SizeLimits; } EN_SizeLimits;
/// Node properties /// Node properties
/** /*! \enum EN_NodeProperty
These node properties are used with @ref EN_getnodevalue and @ref EN_setnodevalue. * 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. * Those marked as read only are computed values that can only be retrieved.
*/ */
typedef enum { typedef enum {
EN_ELEVATION = 0, //!< Elevation EN_ELEVATION = 0, //!< Elevation
@@ -62,8 +60,13 @@ typedef enum {
EN_TANK_KBULK = 23, //!< Tank bulk decay coefficient EN_TANK_KBULK = 23, //!< Tank bulk decay coefficient
EN_TANKVOLUME = 24, //!< Current computed tank volume (read only) EN_TANKVOLUME = 24, //!< Current computed tank volume (read only)
EN_MAXVOLUME = 25, //!< Tank maximum volume (read only) EN_MAXVOLUME = 25, //!< Tank maximum volume (read only)
EN_CANOVERFLOW = 26, //!< Tank can overflow (= 1) or not (= 0) 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_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; } EN_NodeProperty;
/// Link properties /// Link properties
@@ -78,7 +81,7 @@ typedef enum {
EN_MINORLOSS = 3, //!< Pipe/valve minor loss coefficient EN_MINORLOSS = 3, //!< Pipe/valve minor loss coefficient
EN_INITSTATUS = 4, //!< Initial status (see @ref EN_LinkStatusType) EN_INITSTATUS = 4, //!< Initial status (see @ref EN_LinkStatusType)
EN_INITSETTING = 5, //!< Initial pump speed or valve setting 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_KWALL = 7, //!< Pipe wall chemical reaction coefficient
EN_FLOW = 8, //!< Current computed flow rate (read only) EN_FLOW = 8, //!< Current computed flow rate (read only)
EN_VELOCITY = 9, //!< Current computed flow velocity (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_HCURVE = 19, //!< Pump head v. flow curve index
EN_PUMP_ECURVE = 20, //!< Pump efficiency v. flow curve index EN_PUMP_ECURVE = 20, //!< Pump efficiency v. flow curve index
EN_PUMP_ECOST = 21, //!< Pump average energy price 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; } EN_LinkProperty;
/// Time parameters /// 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_NEXTEVENTTANK = 15 //!< Index of tank with shortest time to become empty or full (read only)
} EN_TimeParameter; } 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 /// Analysis convergence statistics
/** /**
These statistics report the convergence criteria for the most current hydraulic analysis 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_MAXFLOWCHANGE = 3, //!< Largest flow change in links
EN_MASSBALANCE = 4, //!< Cumulative water quality mass balance ratio EN_MASSBALANCE = 4, //!< Cumulative water quality mass balance ratio
EN_DEFICIENTNODES = 5, //!< Number of pressure deficient nodes 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; } EN_AnalysisStatistic;
/// Types of network objects /// Types of network objects
@@ -188,25 +211,26 @@ typedef enum {
EN_PBV = 5, //!< Pressure breaker valve EN_PBV = 5, //!< Pressure breaker valve
EN_FCV = 6, //!< Flow control valve EN_FCV = 6, //!< Flow control valve
EN_TCV = 7, //!< Throttle 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; } EN_LinkType;
/// Link status /// Link status
/** /**
One of these values is returned when @ref EN_getlinkvalue is used to retrieve a link's 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. also used with @ref EN_setlinkvalue to set values for these same properties.
*/ */
typedef enum { typedef enum {
EN_CLOSED = 0, EN_CLOSED = 0, //!< Link is closed and cannot convey any flow
EN_OPEN = 1 EN_OPEN = 1 //!< Link is open and is able to convey flow
} EN_LinkStatusType; } EN_LinkStatusType;
/// Pump states /// Pump states
/** /**
One of these codes is returned when @ref EN_getlinkvalue is used to retrieve a pump's 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 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. \b EN_PUMP_XFLOW 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. indicates that the pump is being asked to deliver more than its maximum flow.
*/ */
typedef enum { typedef enum {
@@ -231,7 +255,7 @@ typedef enum {
/// Water quality source types /// Water quality source types
/** /**
These are the different types of external water quality sources that can be assigned 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 { typedef enum {
EN_CONCEN = 0, //!< Sets the concentration of external inflow entering a node EN_CONCEN = 0, //!< Sets the concentration of external inflow entering a node
@@ -242,9 +266,9 @@ typedef enum {
/// Head loss formulas /// 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. @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. that can be set with @ref EN_setlinkvalue.
*/ */
typedef enum { typedef enum {
@@ -257,7 +281,7 @@ typedef enum {
/** /**
These choices for flow units are used with @ref EN_getflowunits and @ref EN_setflowunits. 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 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. in US Customary units. Otherwise they are in metric units.
*/ */
typedef enum { typedef enum {
@@ -270,9 +294,23 @@ typedef enum {
EN_LPM = 6, //!< Liters per minute EN_LPM = 6, //!< Liters per minute
EN_MLD = 7, //!< Million liters per day EN_MLD = 7, //!< Million liters per day
EN_CMH = 8, //!< Cubic meters per hour 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; } 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 /// Demand models
/** /**
These choices for modeling consumer demands are used with @ref EN_getdemandmodel 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_BULKORDER = 19, //!< Bulk water reaction order for pipes
EN_WALLORDER = 20, //!< Wall reaction order for pipes (either 0 or 1) EN_WALLORDER = 20, //!< Wall reaction order for pipes (either 0 or 1)
EN_TANKORDER = 21, //!< Bulk water reaction order for tanks 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; } EN_Option;
/// Simple control types /// Simple control types
@@ -336,9 +378,10 @@ typedef enum {
/// Reporting statistic choices /// Reporting statistic choices
/** /**
These options determine what kind of statistical post-processing should be done on 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 the time series of simulation results before they are reported using @ref EN_report
@ref EN_report. An option can be chosen by using \b STATISTIC _option_ as the argument or saved to the project's binary output file. These options are used in the
to @ref EN_setreport. @ref EN_gettimeparam and @ref EN_settimeparam functions when `EN_STATISTIC` is the
time parameter being set or retrieved.
*/ */
typedef enum { typedef enum {
EN_SERIES = 0, //!< Report all time series points EN_SERIES = 0, //!< Report all time series points
@@ -351,7 +394,7 @@ typedef enum {
/// Tank mixing models /// Tank mixing models
/** /**
These are the different types of models that describe water quality mixing in storage tanks. 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. @ref EN_getnodevalue and @ref EN_setnodevalue.
*/ */
typedef enum { typedef enum {
@@ -393,7 +436,8 @@ typedef enum {
EN_PUMP_CURVE = 1, //!< Pump head v. flow curve EN_PUMP_CURVE = 1, //!< Pump head v. flow curve
EN_EFFIC_CURVE = 2, //!< Pump efficiency v. flow curve EN_EFFIC_CURVE = 2, //!< Pump efficiency v. flow curve
EN_HLOSS_CURVE = 3, //!< Valve head loss 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; } EN_CurveType;
/// Deletion action codes /// 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. controls or if a deleted node has any links connected to it.
*/ */
typedef enum { 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_CONDITIONAL = 1 //!< Cancel object deletion if it appears in controls or has connecting links
} EN_ActionCodeType; } EN_ActionCodeType;
/// Status reporting levels /// Status reporting levels
/** /**
These choices specify the level of status reporting written to a project's report 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 { typedef enum {
EN_NO_REPORT = 0, //!< No status reporting EN_NO_REPORT = 0, //!< No status reporting
@@ -464,5 +509,10 @@ typedef enum {
} EN_RuleStatus; } 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 #endif //EPANET2_ENUMS_H

View File

@@ -1,5 +1,5 @@
# EPANET COMMAND LINE EXECUTABLE # 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. # Sets for output directory for executables and libraries.
@@ -31,3 +31,4 @@ if(NOT WIN32)
else(NOT WIN32) else(NOT WIN32)
target_link_libraries(runepanet LINK_PUBLIC epanet2) target_link_libraries(runepanet LINK_PUBLIC epanet2)
endif(NOT WIN32) endif(NOT WIN32)

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: main.c Module: main.c
Description: main stub for a command line executable version of EPANET Description: main stub for a command line executable version of EPANET
Authors: see AUTHORS Authors: see AUTHORS

View File

@@ -1,13 +1,13 @@
/* /*
***************************************************************************** *****************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: enumstxt.h Module: enumstxt.h
Description: text strings for enumerated data types Description: text strings for enumerated data types
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 06/20/2019 Last Updated: 03/10/2025
****************************************************************************** ******************************************************************************
*/ */
@@ -27,7 +27,8 @@ char *LinkTxt[] = {w_CV,
w_PBV, w_PBV,
w_FCV, w_FCV,
w_TCV, w_TCV,
w_GPV}; w_GPV,
w_PCV};
char *StatTxt[] = {t_XHEAD, char *StatTxt[] = {t_XHEAD,
t_TEMPCLOSED, t_TEMPCLOSED,
@@ -58,7 +59,8 @@ char *RptFlowUnitsTxt[] = {u_CFS,
u_LPM, u_LPM,
u_MLD, u_MLD,
u_CMH, u_CMH,
u_CMD}; u_CMD,
u_CMS};
char *FlowUnitsTxt[] = {w_CFS, char *FlowUnitsTxt[] = {w_CFS,
w_GPM, w_GPM,
@@ -69,11 +71,14 @@ char *FlowUnitsTxt[] = {w_CFS,
w_LPM, w_LPM,
w_MLD, w_MLD,
w_CMH, w_CMH,
w_CMD}; w_CMD,
w_CMS};
char *PressUnitsTxt[] = {w_PSI, char *PressUnitsTxt[] = {w_PSI,
w_KPA, w_KPA,
w_METERS}; w_METERS,
w_BAR,
w_FEET};
char *DemandModelTxt[] = { w_DDA, char *DemandModelTxt[] = { w_DDA,
w_PDA, w_PDA,
@@ -111,6 +116,18 @@ char *RptFlagTxt[] = {w_NO,
w_YES, w_YES,
w_FULL}; 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, char *SectTxt[] = {s_TITLE, s_JUNCTIONS, s_RESERVOIRS,
s_TANKS, s_PIPES, s_PUMPS, s_TANKS, s_PIPES, s_PUMPS,
s_VALVES, s_CONTROLS, s_RULES, s_VALVES, s_CONTROLS, s_RULES,
@@ -120,7 +137,7 @@ char *SectTxt[] = {s_TITLE, s_JUNCTIONS, s_RESERVOIRS,
s_REACTIONS, s_MIXING, s_REPORT, s_REACTIONS, s_MIXING, s_REPORT,
s_TIMES, s_OPTIONS, s_COORDS, s_TIMES, s_OPTIONS, s_COORDS,
s_VERTICES, s_LABELS, s_BACKDROP, s_VERTICES, s_LABELS, s_BACKDROP,
s_TAGS, s_END, s_TAGS, s_LEAKAGE, s_END,
NULL}; NULL};
char *Fldname[] = {t_ELEV, t_DEMAND, t_HEAD, char *Fldname[] = {t_ELEV, t_DEMAND, t_HEAD,

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: epanet2.c Module: epanet2.c
Description: implementation of the legacy EPANET API functions Description: implementation of the legacy EPANET API functions
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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; 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) int DLLEXPORT ENgettitle(char *line1, char *line2, char *line3)
{ {
return EN_gettitle(_defaultProject, line1, line2, 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) ; 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); 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); 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) int DLLEXPORT ENgetcount(int object, int *count)
{ {
return EN_getcount(_defaultProject, object, 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 ENcloseH() { return EN_closeH(_defaultProject); }
int DLLEXPORT ENsavehydfile(char *filename) int DLLEXPORT ENsavehydfile(const char *filename)
{ {
return EN_savehydfile(_defaultProject, filename); return EN_savehydfile(_defaultProject, filename);
} }
int DLLEXPORT ENusehydfile(char *filename) int DLLEXPORT ENusehydfile(const char *filename)
{ {
return EN_usehydfile(_defaultProject, 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 ENreport() { return EN_report(_defaultProject); }
int DLLEXPORT ENcopyreport(char *filename) int DLLEXPORT ENcopyreport(const char *filename)
{ {
return EN_copyreport(_defaultProject, 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 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) int DLLEXPORT ENsetstatusreport(int level)
{ {
return EN_setstatusreport(_defaultProject, 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 ENgetversion(int *version) { return EN_getversion(version); }
int DLLEXPORT ENgeterror(int errcode, char *errmsg, int maxLen) 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); 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); return EN_getqualtype(_defaultProject, qualType, traceNode);
} }
int DLLEXPORT ENsetqualtype(int qualType, char *chemName, char *chemUnits, int DLLEXPORT ENsetqualtype(int qualType, const char *chemName,
char *traceNode) const char *chemUnits, const char *traceNode)
{ {
return EN_setqualtype(_defaultProject, qualType, chemName, chemUnits, 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); return EN_addnode(_defaultProject, id, nodeType, index);
} }
@@ -305,7 +336,7 @@ int DLLEXPORT ENdeletenode(int index, int actionCode)
return EN_deletenode(_defaultProject, index, 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); return EN_getnodeindex(_defaultProject, id, index);
} }
@@ -315,7 +346,7 @@ int DLLEXPORT ENgetnodeid(int index, char *id)
return EN_getnodeid(_defaultProject, index, 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); return EN_setnodeid(_defaultProject, index, newid);
} }
@@ -333,13 +364,27 @@ int DLLEXPORT ENgetnodevalue(int index, int property, EN_API_FLOAT_TYPE *value)
return errcode; 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) int DLLEXPORT ENsetnodevalue(int index, int property, EN_API_FLOAT_TYPE value)
{ {
return EN_setnodevalue(_defaultProject, index, property, value); return EN_setnodevalue(_defaultProject, index, property, value);
} }
int DLLEXPORT ENsetjuncdata(int index, EN_API_FLOAT_TYPE elev, EN_API_FLOAT_TYPE dmnd, 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); 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, int DLLEXPORT ENsettankdata(int index, EN_API_FLOAT_TYPE elev,
EN_API_FLOAT_TYPE initlvl, EN_API_FLOAT_TYPE minlvl, EN_API_FLOAT_TYPE initlvl, EN_API_FLOAT_TYPE minlvl,
EN_API_FLOAT_TYPE maxlvl, EN_API_FLOAT_TYPE diam, 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, return EN_settankdata(_defaultProject, index, elev, initlvl, minlvl, maxlvl,
diam, minvol, volcurve); 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, 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); 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); 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); 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); 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); 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); 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); 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); return EN_getlinkindex(_defaultProject, id, index);
} }
@@ -468,7 +514,7 @@ int DLLEXPORT ENgetlinkid(int index, char *id)
return EN_getlinkid(_defaultProject, index, 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); 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; *value = (EN_API_FLOAT_TYPE)v;
return errcode; 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) int DLLEXPORT ENsetlinkvalue(int index, int property, EN_API_FLOAT_TYPE value)
{ {
@@ -522,6 +581,11 @@ int DLLEXPORT ENgetvertex(int index, int vertex, double *x, double *y)
return EN_getvertex(_defaultProject, index, vertex, x, 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) int DLLEXPORT ENsetvertices(int index, double *x, double *y, int count)
{ {
return EN_setvertices(_defaultProject, index, x, y, 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); return EN_addpattern(_defaultProject, id);
} }
@@ -564,7 +628,7 @@ int DLLEXPORT ENdeletepattern(int index)
return EN_deletepattern(_defaultProject, 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); return EN_getpatternindex(_defaultProject, id, index);
} }
@@ -574,7 +638,7 @@ int DLLEXPORT ENgetpatternid(int index, char *id)
return EN_getpatternid(_defaultProject, index, 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); return EN_setpatternid(_defaultProject, index, id);
} }
@@ -621,13 +685,18 @@ int DLLEXPORT ENsetpattern(int index, EN_API_FLOAT_TYPE *values, int len)
return errcode; return errcode;
} }
int DLLEXPORT ENloadpatternfile(const char *filename, const char *id)
{
return EN_loadpatternfile(_defaultProject, filename, id);
}
/******************************************************************** /********************************************************************
Data Curve Functions Data Curve Functions
********************************************************************/ ********************************************************************/
int DLLEXPORT ENaddcurve(char *id) int DLLEXPORT ENaddcurve(const char *id)
{ {
return EN_addcurve(_defaultProject, id); return EN_addcurve(_defaultProject, id);
} }
@@ -637,7 +706,7 @@ int DLLEXPORT ENdeletecurve(int index)
return EN_deletecurve(_defaultProject, 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); return EN_getcurveindex(_defaultProject, id, index);
} }
@@ -647,7 +716,7 @@ int DLLEXPORT ENgetcurveid(int index, char *id)
return EN_getcurveid(_defaultProject, index, 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); return EN_setcurveid(_defaultProject, index, id);
} }
@@ -662,6 +731,11 @@ int DLLEXPORT ENgetcurvetype(int index, int *type)
return EN_getcurvetype(_defaultProject, index, 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, int DLLEXPORT ENgetcurvevalue(int curveIndex, int pointIndex, EN_API_FLOAT_TYPE *x,
EN_API_FLOAT_TYPE *y) EN_API_FLOAT_TYPE *y)
{ {
@@ -761,6 +835,17 @@ int DLLEXPORT ENsetcontrol(int index, int type, int linkIndex,
nodeIndex, level); 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 Rule-Based Controls Functions
@@ -863,3 +948,14 @@ int DLLEXPORT ENsetrulepriority(int index, EN_API_FLOAT_TYPE priority)
{ {
return EN_setrulepriority(_defaultProject, index, 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);
}

View File

@@ -14,6 +14,7 @@ DAT(120,"cannot solve water quality transport equations")
// These errors apply only to an input file // These errors apply only to an input file
DAT(200,"one or more errors in input file") DAT(200,"one or more errors in input file")
DAT(201,"syntax error") DAT(201,"syntax error")
DAT(299,"invalid section keyword")
// These errors apply to both an input file and to API functions // These errors apply to both an input file and to API functions
DAT(202,"illegal numeric value") 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(226,"no head curve or power rating for pump")
DAT(227,"invalid head curve for pump") DAT(227,"invalid head curve for pump")
DAT(230,"nonincreasing x-values for curve") 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 // These errors apply only to API functions
DAT(240,"nonexistent source") 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(260,"attempt to delete node assigned as a Trace Node")
DAT(261,"attempt to delete a node or link contained in a control") 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(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 // File errors
DAT(301,"identical file names") DAT(301,"identical file names")

186
src/flowbalance.c Normal file
View 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;
}

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: funcs.h Module: funcs.h
Description: prototypes of external functions called by various modules Description: prototypes of external functions called by various modules
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 11/15/2019 Last Updated: 04/23/2025
****************************************************************************** ******************************************************************************
*/ */
#ifndef FUNCS_H #ifndef FUNCS_H
@@ -19,6 +19,7 @@ void initpointers(Project *);
int allocdata(Project *); int allocdata(Project *);
void freedata(Project *); void freedata(Project *);
int openproject(Project *, const char *, const char *, const char *, int);
int openfiles(Project *, const char *, const char *,const char *); int openfiles(Project *, const char *, const char *,const char *);
int openhydfile(Project *); int openhydfile(Project *);
int openoutfile(Project *); int openoutfile(Project *);
@@ -28,17 +29,20 @@ int buildadjlists(Network *);
void freeadjlists(Network *); void freeadjlists(Network *);
int incontrols(Project *, int, int); int incontrols(Project *, int, int);
int changevalvetype(Project *, int, int);
int valvecheck(Project *, int, int, int, int); int valvecheck(Project *, int, int, int, int);
int findnode(Network *, char *); int unlinked(Project *);
int findlink(Network *, char *);
int findnode(Network *, const char *);
int findlink(Network *, const char *);
int findtank(Network *, int); int findtank(Network *, int);
int findvalve(Network *, int); int findvalve(Network *, int);
int findpump(Network *, int); int findpump(Network *, int);
int findpattern(Network *, char *); int findpattern(Network *, const char *);
int findcurve(Network *, char *); int findcurve(Network *, const char *);
Pdemand finddemand(Pdemand, int); Pdemand finddemand(Pdemand, int);
int adddemand(Snode *, double, int, char *); int adddemand(Snode *, double, int, const char *);
void freedemands(Snode *); void freedemands(Snode *);
int addlinkvertex(Slink *, double, double); int addlinkvertex(Slink *, double, double);
@@ -46,11 +50,13 @@ void freelinkvertices(Slink *);
void adjustpatterns(Network *, int); void adjustpatterns(Network *, int);
void adjustcurves(Network *, int); void adjustcurves(Network *, int);
int adjustpumpparams(Project *, int);
int resizecurve(Scurve *, int); int resizecurve(Scurve *, int);
int setcontrol(Project *, int, int, double, int, double, Scontrol *);
int getcomment(Network *, int, int, char *); int getcomment(Network *, int, int, char *);
int setcomment(Network *, int, int, const 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 *); int namevalid(const char *);
void getTmpName(char *); void getTmpName(char *);
@@ -67,7 +73,7 @@ int getdata(Project *);
void setdefaults(Project *); void setdefaults(Project *);
void initreport(Report *); void initreport(Report *);
void adjustdata(Project *); void adjustdata(Project *);
int inittanks(Project *); void inittanks(Project *);
void initunits(Project *); void initunits(Project *);
void convertunits(Project *); void convertunits(Project *);
@@ -75,7 +81,6 @@ void convertunits(Project *);
int netsize(Project *); int netsize(Project *);
int readdata(Project *); int readdata(Project *);
int updatepumpparams(Project *, int);
int findmatch(char *, char *[]); int findmatch(char *, char *[]);
int match(const char *, const char *); int match(const char *, const char *);
int gettokens(char *, char **, int, char *); int gettokens(char *, char **, int, char *);
@@ -98,6 +103,7 @@ int controldata(Project *);
int energydata(Project *); int energydata(Project *);
int sourcedata(Project *); int sourcedata(Project *);
int emitterdata(Project *); int emitterdata(Project *);
int leakagedata(Project *);
int qualdata(Project *); int qualdata(Project *);
int reactdata(Project *); int reactdata(Project *);
int mixingdata(Project *); int mixingdata(Project *);
@@ -106,6 +112,7 @@ int reportdata(Project *);
int timedata(Project *); int timedata(Project *);
int optiondata(Project *); int optiondata(Project *);
int vertexdata(Project *); int vertexdata(Project *);
int tagdata(Project *);
// ------- RULES.C ------------------ // ------- RULES.C ------------------
@@ -117,28 +124,30 @@ void freerules(Project *);
int ruledata(Project *); int ruledata(Project *);
void ruleerrmsg(Project *); void ruleerrmsg(Project *);
void adjustrules(Project *, int, int); void adjustrules(Project *, int, int);
void adjusttankrules(Project *); void adjusttankrules(Project *, int);
Spremise *getpremise(Spremise *, int); Spremise *getpremise(Spremise *, int);
Saction *getaction(Saction *, int); Saction *getaction(Saction *, int);
int writerule(Project *, FILE *, int); int writerule(Project *, FILE *, int);
int checkrules(Project *, long); int checkrules(Project *, long);
void updateruleunits(Project *pr, double dcf, double pcf, double hcf, double qcf);
// ------- REPORT.C ----------------- // ------- REPORT.C -----------------
int clearreport(Project *); int clearreport(Project *);
int copyreport(Project *, char *); int copyreport(Project *, const char *);
int writereport(Project *); int writereport(Project *);
void writelogo(Project *); void writelogo(Project *);
void writesummary(Project *); void writesummary(Project *);
void writehydstat(Project *, int, double); void writehydstat(Project *, int, double);
void writeheader(Project *, int,int); void writeheader(Project *, int,int);
void writeline(Project *, char *); void writeline(Project *, const char *);
void writerelerr(Project *, int, double); void writerelerr(Project *, int, double);
void writestatchange(Project *, int,char,char); void writestatchange(Project *, int,char,char);
void writecontrolaction(Project *, int, int); void writecontrolaction(Project *, int, int);
void writeruleaction(Project *, int, char *); void writeruleaction(Project *, int, char *);
int writehydwarn(Project *, int,double); int writehydwarn(Project *, int,double);
void writehyderr(Project *, int); void writehyderr(Project *, int);
void writeflowbalance(Project *);
void writemassbalance(Project *); void writemassbalance(Project *);
void writetime(Project *, char *); void writetime(Project *, char *);
char *clocktime(char *, long); char *clocktime(char *, long);
@@ -153,6 +162,7 @@ void closehyd(Project *);
void setlinkstatus(Project *, int, char, StatusType *, double *); void setlinkstatus(Project *, int, char, StatusType *, double *);
void setlinksetting(Project *, int, double, StatusType *, double *); void setlinksetting(Project *, int, double, StatusType *, double *);
int tanktimestep(Project *, long *); int tanktimestep(Project *, long *);
int controltimestep(Project *, long *);
void getenergy(Project *, int, double *, double *); void getenergy(Project *, int, double *, double *);
double tankvolume(Project *, int, double); double tankvolume(Project *, int, double);
double tankgrade(Project *, int, double); double tankgrade(Project *, int, double);
@@ -164,6 +174,7 @@ void headlosscoeffs(Project *);
void matrixcoeffs(Project *); void matrixcoeffs(Project *);
void emitterheadloss(Project *, int, double *, double *); void emitterheadloss(Project *, int, double *, double *);
void demandheadloss(Project *, int, double, double, double *, double *); void demandheadloss(Project *, int, double, double, double *, double *);
double pcvlosscoeff(Project *, int, double);
// ------- QUALITY.C -------------------- // ------- QUALITY.C --------------------
@@ -190,4 +201,19 @@ int savefinaloutput(Project *);
int saveinpfile(Project *, const char *); 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 #endif

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: hash.c Module: hash.c
Description: implementation of a simple hash table Description: implementation of a simple hash table
Authors: see AUTHORS Authors: see AUTHORS
@@ -26,7 +26,7 @@ typedef struct DataEntryStruct
} DataEntry; } DataEntry;
// Hash a string to an integer // Hash a string to an integer
unsigned int gethash(char *str) unsigned int gethash(const char *str)
{ {
unsigned int hash = 5381; unsigned int hash = 5381;
unsigned int retHash; unsigned int retHash;
@@ -61,7 +61,7 @@ HashTable *hashtable_create()
} }
// Insert an entry into the hash table // 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); unsigned int i = gethash(key);
DataEntry *entry; 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 // 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); unsigned int i = gethash(key);
DataEntry *entry; DataEntry *entry;
@@ -96,7 +96,7 @@ int hashtable_update(HashTable *ht, char *key, int new_data)
} }
// Delete an entry in the hash table // 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); unsigned int i = gethash(key);
DataEntry *entry, *preventry; DataEntry *entry, *preventry;
@@ -122,7 +122,7 @@ int hashtable_delete(HashTable *ht, char *key)
} }
// Find the data for a particular 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); unsigned int i = gethash(key);
DataEntry *entry; DataEntry *entry;
@@ -141,7 +141,7 @@ int hashtable_find(HashTable *ht, char *key)
} }
// Find a particular key in the hash table // 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); unsigned int i = gethash(key);
DataEntry *entry; DataEntry *entry;

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: hash.h Module: hash.h
Description: header for a simple hash table Description: header for a simple hash table
Authors: see AUTHORS Authors: see AUTHORS
@@ -18,11 +18,11 @@
typedef struct DataEntryStruct *HashTable; typedef struct DataEntryStruct *HashTable;
HashTable *hashtable_create(void); HashTable *hashtable_create(void);
int hashtable_insert(HashTable *, char *, int); int hashtable_insert(HashTable *, const char *, int);
int hashtable_find(HashTable *, char *); int hashtable_find(HashTable *, const char *);
char *hashtable_findkey(HashTable *, char *); char *hashtable_findkey(HashTable *, const char *);
void hashtable_free(HashTable *); void hashtable_free(HashTable *);
int hashtable_update(HashTable *ht, char *key, int new_data); int hashtable_update(HashTable *ht, const char *key, int new_data);
int hashtable_delete(HashTable *ht, char *key); int hashtable_delete(HashTable *ht, const char *key);
#endif #endif

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: hydcoeffs.c Module: hydcoeffs.c
Description: computes coefficients for a hydraulic solution matrix Description: computes coefficients for a hydraulic solution matrix
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 10/04/2019 Last Updated: 06/15/2024
****************************************************************************** ******************************************************************************
*/ */
@@ -36,6 +36,7 @@ const double CBIG = 1.e8;
// Exported functions // Exported functions
//void resistcoeff(Project *, int ); //void resistcoeff(Project *, int );
//double pcvlosscoeff(Project *, int, double);
//void headlosscoeffs(Project *); //void headlosscoeffs(Project *);
//void matrixcoeffs(Project *); //void matrixcoeffs(Project *);
//void emitterheadloss(Project *, int, double *, double *); //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 gpvcoeff(Project *pr, int k);
static void pbvcoeff(Project *pr, int k); static void pbvcoeff(Project *pr, int k);
static void tcvcoeff(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 prvcoeff(Project *pr, int k, int n1, int n2);
static void psvcoeff(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); 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) void resistcoeff(Project *pr, int k)
/* /*
**-------------------------------------------------------------------- **--------------------------------------------------------------------
@@ -108,6 +145,10 @@ void resistcoeff(Project *pr, int k)
link->R = CBIG; link->R = CBIG;
break; break;
case PCV:
link->R = pcvlosscoeff(pr, k, link->Kc);
break;
// ... For all other links (e.g. valves) use a small resistance // ... For all other links (e.g. valves) use a small resistance
default: default:
link->R = CSMALL; link->R = CSMALL;
@@ -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) void headlosscoeffs(Project *pr)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
@@ -148,6 +270,9 @@ void headlosscoeffs(Project *pr)
case TCV: case TCV:
tcvcoeff(pr, k); tcvcoeff(pr, k);
break; break;
case PCV:
pcvcoeff(pr, k);
break;
case GPV: case GPV:
gpvcoeff(pr, k); gpvcoeff(pr, k);
break; break;
@@ -185,6 +310,7 @@ void matrixcoeffs(Project *pr)
linkcoeffs(pr); linkcoeffs(pr);
emittercoeffs(pr); emittercoeffs(pr);
demandcoeffs(pr); demandcoeffs(pr);
if (hyd->HasLeakage) leakagecoeffs(pr);
// Update nodal flow balances with demands and add onto r.h.s. coeffs. // Update nodal flow balances with demands and add onto r.h.s. coeffs.
nodecoeffs(pr); nodecoeffs(pr);
@@ -381,7 +507,7 @@ void emitterheadloss(Project *pr, int i, double *hloss, double *hgrad)
** Input: i = node index ** Input: i = node index
** Output: hloss = head loss across node's emitter ** Output: hloss = head loss across node's emitter
** hgrad = head loss gradient ** 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 // Use linear head loss function for small gradient
if (*hgrad < hyd->RQtol) if (*hgrad < hyd->RQtol)
{ {
*hgrad = hyd->RQtol; *hgrad = hyd->RQtol / hyd->Qexp;
*hloss = (*hgrad) * q; *hloss = (*hgrad) * q;
} }
// Otherwise use normal emitter head loss function // Otherwise use normal emitter head loss function
else *hloss = (*hgrad) * q / hyd->Qexp; 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++) for (i = 1; i <= net->Njuncs; i++)
{ {
// Skip junctions with non-positive demands // 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 // Find head loss for demand outflow at node's elevation
demandheadloss(pr, i, dp, n, &hloss, &hgrad); 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; Hydraul *hyd = &pr->hydraul;
double d = hyd->DemandFlow[i]; double d = hyd->DemandFlow[i];
double dfull = hyd->NodeDemand[i]; double dfull = hyd->FullDemand[i];
double r = d / dfull; double r = d / dfull;
// Use lower barrier function for negative demand // Evaluate inverted demand function
if (r <= 0) r = fabs(d) / dfull;
{
*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; *hgrad = n * dp * pow(r, n - 1.0) / dfull;
// ... use linear function for very small gradient *hloss = (*hgrad) * d / n;
if (*hgrad < hyd->RQtol)
{
*hgrad = hyd->RQtol;
*hloss = (*hgrad) * d;
}
else *hloss = (*hgrad) * d / n;
}
// Use upper barrier function for demand above full value // Add barrier functions
else addlowerbarrier(d, hloss, hgrad);
{ addupperbarrier(d-dfull, hloss, hgrad);
*hgrad = CBIG;
*hloss = dp + CBIG * (d - dfull);
}
} }
@@ -553,7 +667,7 @@ void pipecoeff(Project *pr, int k)
// ... use linear function for very small gradient // ... use linear function for very small gradient
if (hgrad < hyd->RQtol) if (hgrad < hyd->RQtol)
{ {
hgrad = hyd->RQtol; hgrad = hyd->RQtol / hyd->Hexp;
hloss = hgrad * q; hloss = hgrad * q;
} }
// ... otherwise use original formula // ... otherwise use original formula
@@ -744,17 +858,23 @@ void pumpcoeff(Project *pr, int k)
{ {
// ... compute pump curve's gradient // ... compute pump curve's gradient
hgrad = -r / q / q; 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) if (hgrad > CBIG)
{ {
hgrad = CBIG; hyd->P[k] = 1.0 / CBIG;
hloss = -hgrad * hyd->LinkFlow[k]; 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; hyd->P[k] = 1.0 / CSMALL;
hloss = -hgrad * hyd->LinkFlow[k]; hyd->Y[k] = hyd->LinkFlow[k];
return;
} }
// ... otherwise compute head loss from pump curve // ... otherwise compute head loss from pump curve
else 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) 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->F[j] += hyd->Xflow[n1];
} }
sm->Aij[sm->Ndx[k]] -= 1.0 / CBIG; // Preserve connectivity
sm->Aii[j] += 1.0 / CBIG;
return; return;
} }
@@ -1131,7 +1283,7 @@ void valvecoeff(Project *pr, int k)
// Guard against too small a head loss gradient // Guard against too small a head loss gradient
if (hgrad < hyd->RQtol) if (hgrad < hyd->RQtol)
{ {
hgrad = hyd->RQtol; hgrad = hyd->RQtol / 2.0;
hloss = flow * hgrad; hloss = flow * hgrad;
} }
else hloss = flow * hgrad / 2.0; else hloss = flow * hgrad / 2.0;

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: hydraul.c Module: hydraul.c
Description: implements EPANET's hydraulic engine Description: implements EPANET's hydraulic engine
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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 const double QZERO = 1.e-6; // Equivalent to zero flow in cfs
// Imported functions // Imported functions
extern int validateproject(Project *);
extern int createsparse(Project *); extern int createsparse(Project *);
extern void freesparse(Project *); extern void freesparse(Project *);
extern int hydsolve(Project *, int *, double *); extern int hydsolve(Project *, int *, double *);
@@ -34,11 +35,11 @@ void initlinkflow(Project *, int, char, double);
void demands(Project *); void demands(Project *);
int controls(Project *); int controls(Project *);
long timestep(Project *); long timestep(Project *);
void controltimestep(Project *, long *);
void ruletimestep(Project *, long *); void ruletimestep(Project *, long *);
void addenergy(Project *, long); void addenergy(Project *, long);
void tanklevels(Project *, long); void tanklevels(Project *, long);
void resetpumpflow(Project *, int); void resetpumpflow(Project *, int);
void getallpumpsenergy(Project *);
int openhyd(Project *pr) int openhyd(Project *pr)
/* /*
@@ -53,9 +54,9 @@ int openhyd(Project *pr)
int errcode = 0; int errcode = 0;
Slink *link; Slink *link;
// Check for too few nodes & no fixed grade nodes // Check for valid project data (see VALIDATE.C)
if (pr->network.Nnodes < 2) errcode = 223; errcode = validateproject(pr);
else if (pr->network.Ntanks == 0) errcode = 224; if (errcode > 0) return errcode;
// Allocate memory for sparse matrix structures (see SMATRIX.C) // Allocate memory for sparse matrix structures (see SMATRIX.C)
ERRCODE(createsparse(pr)); ERRCODE(createsparse(pr));
@@ -64,21 +65,15 @@ int openhyd(Project *pr)
ERRCODE(allocmatrix(pr)); ERRCODE(allocmatrix(pr));
// Check for unconnected nodes // Check for unconnected nodes
if (!errcode) for (i = 1; i <= pr->network.Njuncs; i++) ERRCODE(unlinked(pr));
{
if (pr->network.Adjlist[i] == NULL)
{
errcode = 233;
break;
}
}
// Initialize link flows // Initialize link flows
if (!errcode) for (i = 1; i <= pr->network.Nlinks; i++) if (!errcode) for (i = 1; i <= pr->network.Nlinks; i++)
{ {
link = &pr->network.Link[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; return errcode;
} }
@@ -112,8 +107,10 @@ void inithyd(Project *pr, int initflag)
hyd->OldStatus[net->Nlinks+i] = TEMPCLOSED; 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->EmitterFlow,0,(net->Nnodes+1)*sizeof(double));
memset(hyd->LeakageFlow,0,(net->Nnodes+1)*sizeof(double));
for (i = 1; i <= net->Nnodes; i++) for (i = 1; i <= net->Nnodes; i++)
{ {
net->Node[i].ResultIndex = i; net->Node[i].ResultIndex = i;
@@ -127,8 +124,21 @@ void inithyd(Project *pr, int initflag)
link->ResultIndex = i; link->ResultIndex = i;
// Initialize status and setting // Initialize status and setting
hyd->LinkStatus[i] = link->Status; hyd->LinkStatus[i] = link->InitStatus;
hyd->LinkSetting[i] = link->Kc; 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 // Compute flow resistance
resistcoeff(pr, i); resistcoeff(pr, i);
@@ -163,8 +173,13 @@ void inithyd(Project *pr, int initflag)
pump->Energy.KwHrsPerFlow = 0.0; pump->Energy.KwHrsPerFlow = 0.0;
pump->Energy.MaxKwatts = 0.0; pump->Energy.MaxKwatts = 0.0;
pump->Energy.TotalCost = 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 // Re-position hydraulics file
if (pr->outfile.Saveflag) if (pr->outfile.Saveflag)
{ {
@@ -239,6 +254,9 @@ int nexthyd(Project *pr, long *tstep)
long hydstep; // Actual time step long hydstep; // Actual time step
int errcode = 0; // Error code int errcode = 0; // Error code
// Compute current power and efficiency of all pumps
getallpumpsenergy(pr);
// Save current results to hydraulics file and // Save current results to hydraulics file and
// force end of simulation if Haltflag is active // force end of simulation if Haltflag is active
if (pr->outfile.Saveflag) errcode = savehyd(pr, &time->Htime); if (pr->outfile.Saveflag) errcode = savehyd(pr, &time->Htime);
@@ -250,10 +268,13 @@ int nexthyd(Project *pr, long *tstep)
if (time->Htime < time->Dur) hydstep = timestep(pr); if (time->Htime < time->Dur) hydstep = timestep(pr);
if (pr->outfile.Saveflag) errcode = savehydstep(pr,&hydstep); if (pr->outfile.Saveflag) errcode = savehydstep(pr,&hydstep);
// Compute pumping energy // Accumulate pumping energy
if (time->Dur == 0) addenergy(pr,0); if (time->Dur == 0) addenergy(pr,0);
else if (time->Htime < time->Dur) addenergy(pr,hydstep); else if (time->Htime < time->Dur) addenergy(pr,hydstep);
// Update flow balance
updateflowbalance(pr, hydstep);
// More time remains - update current time // More time remains - update current time
if (time->Htime < time->Dur) if (time->Htime < time->Dur)
{ {
@@ -267,6 +288,8 @@ int nexthyd(Project *pr, long *tstep)
// No more time remains - force completion of analysis // No more time remains - force completion of analysis
else else
{ {
endflowbalance(pr);
if (pr->report.Statflag) writeflowbalance(pr);
time->Htime++; time->Htime++;
if (pr->quality.OpenQflag) time->Qtime++; if (pr->quality.OpenQflag) time->Qtime++;
} }
@@ -286,6 +309,7 @@ void closehyd(Project *pr)
{ {
freesparse(pr); freesparse(pr);
freematrix(pr); freematrix(pr);
freeadjlists(&pr->network);
} }
@@ -305,16 +329,12 @@ int allocmatrix(Project *pr)
hyd->P = (double *) calloc(net->Nlinks+1,sizeof(double)); hyd->P = (double *) calloc(net->Nlinks+1,sizeof(double));
hyd->Y = (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)), hyd->Xflow = (double *) calloc(MAX((net->Nnodes+1), (net->Nlinks+1)),
sizeof(double)); sizeof(double));
hyd->OldStatus = (StatusType *) calloc(net->Nlinks+net->Ntanks+1, hyd->OldStatus = (StatusType *) calloc(net->Nlinks+net->Ntanks+1,
sizeof(StatusType)); sizeof(StatusType));
ERRCODE(MEMCHECK(hyd->P)); ERRCODE(MEMCHECK(hyd->P));
ERRCODE(MEMCHECK(hyd->Y)); ERRCODE(MEMCHECK(hyd->Y));
ERRCODE(MEMCHECK(hyd->DemandFlow));
ERRCODE(MEMCHECK(hyd->EmitterFlow));
ERRCODE(MEMCHECK(hyd->Xflow)); ERRCODE(MEMCHECK(hyd->Xflow));
ERRCODE(MEMCHECK(hyd->OldStatus)); ERRCODE(MEMCHECK(hyd->OldStatus));
return errcode; return errcode;
@@ -334,8 +354,6 @@ void freematrix(Project *pr)
free(hyd->P); free(hyd->P);
free(hyd->Y); free(hyd->Y);
free(hyd->DemandFlow);
free(hyd->EmitterFlow);
free(hyd->Xflow); free(hyd->Xflow);
free(hyd->OldStatus); free(hyd->OldStatus);
} }
@@ -457,6 +475,7 @@ void setlinksetting(Project *pr, int index, double value, StatusType *s,
else else
{ {
if (*k == MISSING && *s <= CLOSED) *s = OPEN; if (*k == MISSING && *s <= CLOSED) *s = OPEN;
if (t == PCV) link->R = pcvlosscoeff(pr, index, link->Kc);
*k = value; *k = value;
} }
} }
@@ -492,12 +511,14 @@ void demands(Project *pr)
{ {
// pattern period (k) = (elapsed periods) modulus (periods per pattern) // pattern period (k) = (elapsed periods) modulus (periods per pattern)
j = demand->Pat; j = demand->Pat;
if (j == 0)
j = hyd->DefPat;
k = p % (long)net->Pattern[j].Length; k = p % (long)net->Pattern[j].Length;
djunc = (demand->Base) * net->Pattern[j].F[k] * hyd->Dmult; djunc = (demand->Base) * net->Pattern[j].F[k] * hyd->Dmult;
if (djunc > 0.0) hyd->Dsystem += djunc; if (djunc > 0.0) hyd->Dsystem += djunc;
sum += djunc; sum += djunc;
} }
hyd->NodeDemand[i] = sum; hyd->FullDemand[i] = sum;
// Initialize pressure dependent demand // Initialize pressure dependent demand
hyd->DemandFlow[i] = sum; hyd->DemandFlow[i] = sum;
@@ -562,6 +583,10 @@ int controls(Project *pr)
{ {
// Make sure that link is defined // Make sure that link is defined
control = &net->Control[i]; control = &net->Control[i];
if (!control->isEnabled)
{
continue;
}
reset = 0; reset = 0;
if ( (k = control->Link) <= 0) continue; if ( (k = control->Link) <= 0) continue;
link = &net->Link[k]; link = &net->Link[k];
@@ -610,6 +635,7 @@ int controls(Project *pr)
{ {
hyd->LinkStatus[k] = s2; hyd->LinkStatus[k] = s2;
hyd->LinkSetting[k] = k2; hyd->LinkSetting[k] = k2;
if (link->Type == PCV) link->R = pcvlosscoeff(pr, k, k2);
if (pr->report.Statflag) writecontrolaction(pr,k,i); if (pr->report.Statflag) writecontrolaction(pr,k,i);
setsum++; setsum++;
} }
@@ -673,7 +699,7 @@ int tanktimestep(Project *pr, long *tstep)
Hydraul *hyd = &pr->hydraul; Hydraul *hyd = &pr->hydraul;
int i, n, tankIdx = 0; int i, n, tankIdx = 0;
double h, q, v; double h, q, v, xt;
long t; long t;
Stank *tank; Stank *tank;
@@ -696,7 +722,9 @@ int tanktimestep(Project *pr, long *tstep)
else continue; else continue;
// Find time to fill/drain tank // 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) if (t > 0 && t < *tstep)
{ {
*tstep = t; *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 ** Input: *tstep = current time step
@@ -720,7 +748,7 @@ void controltimestep(Project *pr, long *tstep)
Network *net = &pr->network; Network *net = &pr->network;
Hydraul *hyd = &pr->hydraul; Hydraul *hyd = &pr->hydraul;
int i, j, k, n; int i, j, k, n, controlIndex = 0;
double h, q, v; double h, q, v;
long t, t1, t2; long t, t1, t2;
Slink *link; Slink *link;
@@ -731,7 +759,10 @@ void controltimestep(Project *pr, long *tstep)
{ {
t = 0; t = 0;
control = &net->Control[i]; control = &net->Control[i];
if (!control->isEnabled)
{
continue;
}
// Control depends on a tank level // Control depends on a tank level
if ( (n = control->Node) > 0) if ( (n = control->Node) > 0)
{ {
@@ -777,9 +808,14 @@ void controltimestep(Project *pr, long *tstep)
k = control->Link; k = control->Link;
link = &net->Link[k]; link = &net->Link[k];
if ( (link->Type > PIPE && hyd->LinkSetting[k] != control->Setting) 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 // Skip closed pumps
pump = &net->Pump[j]; pump = &net->Pump[j];
k = pump->Link; k = pump->Link;
if (hyd->LinkStatus[k] <= CLOSED) continue; if (pump->Energy.CurrentEffic == 0.0) continue;
q = MAX(QZERO, ABS(hyd->LinkFlow[k])); q = MAX(QZERO, ABS(hyd->LinkFlow[k]));
// Find pump-specific energy cost // Find pump-specific energy cost
@@ -915,11 +951,10 @@ void addenergy(Project *pr, long hstep)
} }
else c *= f0; else c *= f0;
// Find pump energy & efficiency
getenergy(pr, k, &p, &e);
psum += p;
// Update pump's cumulative statistics // Update pump's cumulative statistics
p = pump->Energy.CurrentPower;
e = pump->Energy.CurrentEffic;
psum += p;
pump->Energy.TimeOnLine += dt; pump->Energy.TimeOnLine += dt;
pump->Energy.Efficiency += e * dt; pump->Energy.Efficiency += e * dt;
pump->Energy.KwHrsPerFlow += p / q * 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) void tanklevels(Project *pr, long tstep)
/* /*
**---------------------------------------------------------------- **----------------------------------------------------------------
@@ -1114,4 +1170,3 @@ void resetpumpflow(Project *pr, int i)
if (pump->Ptype == CONST_HP) if (pump->Ptype == CONST_HP)
pr->hydraul.LinkFlow[i] = pump->Q0; pr->hydraul.LinkFlow[i] = pump->Q0;
} }

View File

@@ -1,14 +1,14 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: hydsolver.c Module: hydsolver.c
Description: computes flows and pressures throughout a pipe network using Description: computes flows and pressures throughout a pipe network using
Todini's Global Gradient Algorithm Todini's Global Gradient Algorithm
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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 newlinkflows(Project *, Hydbalance *, double *, double *);
static void newemitterflows(Project *, Hydbalance *, double *, double *); static void newemitterflows(Project *, Hydbalance *, double *, double *);
static void newdemandflows(Project *, Hydbalance *, double *, double *); static void newdemandflows(Project *, Hydbalance *, double *, double *);
static void newleakageflows(Project *, Hydbalance *, double *, double *);
static void checkhydbalance(Project *, Hydbalance *); static void checkhydbalance(Project *, Hydbalance *);
static int hasconverged(Project *, double *, 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 valveChange; // Valve status change flag
int statChange; // Non-valve status change flag int statChange; // Non-valve status change flag
Hydbalance hydbal; // Hydraulic balance errors Hydbalance hydbal; // Hydraulic balance errors
double fullDemand; // Full demand for a node (cfs)
// Initialize status checking & relaxation factor // Initialize status checking & relaxation factor
nextcheck = hyd->CheckFreq; nextcheck = hyd->CheckFreq;
@@ -178,7 +178,7 @@ int hydsolve(Project *pr, int *iter, double *relerr)
nextcheck = *iter + hyd->CheckFreq; 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 // check on pumps, CV's, and pipes connected to tank
else if (*iter <= hyd->MaxCheck && *iter == nextcheck) else if (*iter <= hyd->MaxCheck && *iter == nextcheck)
{ {
@@ -195,12 +195,12 @@ int hydsolve(Project *pr, int *iter, double *relerr)
errcode = 110; 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++) for (i = 1; i <= net->Njuncs; i++)
{ {
fullDemand = hyd->NodeDemand[i]; hyd->NodeDemand[i] = hyd->DemandFlow[i] +
hyd->NodeDemand[i] = hyd->DemandFlow[i] + hyd->EmitterFlow[i]; hyd->EmitterFlow[i] +
hyd->DemandFlow[i] = fullDemand; hyd->LeakageFlow[i];
} }
// Save convergence info // Save convergence info
@@ -381,6 +381,7 @@ double newflows(Project *pr, Hydbalance *hbal)
newlinkflows(pr, hbal, &qsum, &dqsum); newlinkflows(pr, hbal, &qsum, &dqsum);
newemitterflows(pr, hbal, &qsum, &dqsum); newemitterflows(pr, hbal, &qsum, &dqsum);
newdemandflows(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 // Return ratio of total flow corrections to total flow
if (qsum > hyd->Hacc) return (dqsum / qsum); 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) 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++) for (i = 1; i <= net->Njuncs; i++)
{ {
// Skip junctions with no positive demand // 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) // Find change in demand flow (see hydcoeffs.c)
demandheadloss(pr, i, dp, n, &hloss, &hgrad); demandheadloss(pr, i, dp, n, &hloss, &hgrad);
dh = hyd->NodeHead[i] - net->Node[i].El - hyd->Pmin; dh = hyd->NodeHead[i] - net->Node[i].El - hyd->Pmin;
dq = (hloss - dh) / hgrad; dq = (hloss - dh) / hgrad;
dq *= hyd->RelaxFactor; 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; hyd->DemandFlow[i] -= dq;
// Update system flow summation // Update system flow summation
@@ -637,11 +681,15 @@ int hasconverged(Project *pr, double *relerr, Hydbalance *hbal)
if (hyd->FlowChangeLimit > 0.0 && if (hyd->FlowChangeLimit > 0.0 &&
hbal->maxflowchange > hyd->FlowChangeLimit) return 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 // Check for pressure driven analysis convergence
if (hyd->DemandModel == PDA) return pdaconverged(pr); if (hyd->DemandModel == PDA) return pdaconverged(pr);
return 1; return 1;
} }
int pdaconverged(Project *pr) int pdaconverged(Project *pr)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
@@ -654,31 +702,44 @@ int pdaconverged(Project *pr)
{ {
Hydraul *hyd = &pr->hydraul; 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; int i, converged = 1;
double totalDemand = 0.0, totalReduction = 0.0; double totalDemand = 0.0, totalReduction = 0.0;
double dp = hyd->Preq - hyd->Pmin;
double p, q, r;
hyd->DeficientNodes = 0; hyd->DeficientNodes = 0;
hyd->DemandReduction = 0.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++) for (i = 1; i <= pr->network.Njuncs; i++)
{ {
// Skip nodes whose required demand is non-positive // Skip nodes whose required demand is non-positive
if (hyd->NodeDemand[i] <= 0.0) continue; if (hyd->FullDemand[i] <= 0.0) continue;
// Check for negative demand flow or positive demand flow at negative pressure // Evaluate demand equation at current pressure solution
if (hyd->DemandFlow[i] < -TOL) converged = 0; p = hyd->NodeHead[i] - pr->network.Node[i].El;
if (hyd->DemandFlow[i] > TOL && if (p <= hyd->Pmin)
hyd->NodeHead[i] - pr->network.Node[i].El - hyd->Pmin < -TOL) 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 if demand has not converged
if (fabs(q - hyd->DemandFlow[i]) > QTOL)
converged = 0; converged = 0;
// Accumulate total required demand and demand deficit // Accumulate demand deficient node count and demand deficit
if (hyd->DemandFlow[i] + 0.0001 < hyd->NodeDemand[i]) if (hyd->DemandFlow[i] + QTOL < hyd->FullDemand[i])
{ {
hyd->DeficientNodes++; hyd->DeficientNodes++;
totalDemand += hyd->NodeDemand[i]; totalDemand += hyd->FullDemand[i];
totalReduction += hyd->NodeDemand[i] - hyd->DemandFlow[i]; totalReduction += hyd->FullDemand[i] - hyd->DemandFlow[i];
} }
} }
if (totalDemand > 0.0) if (totalDemand > 0.0)

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: hydstatus.c Module: hydstatus.c
Description: updates hydraulic status of network elements Description: updates hydraulic status of network elements
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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 prvstatus(Project *, int, StatusType, double, double, double);
static StatusType psvstatus(Project *, int, StatusType, double, double, double); static StatusType psvstatus(Project *, int, StatusType, double, double, double);
static StatusType fcvstatus(Project *, int, StatusType, 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) int valvestatus(Project *pr)
@@ -155,10 +155,8 @@ int linkstatus(Project *pr)
} }
// Check for flow into (out of) full (empty) tanks // Check for flow into (out of) full (empty) tanks
if (n1 > net->Njuncs || n2 > net->Njuncs) if (n1 > net->Njuncs) tankstatus(pr, k, n1, hyd->LinkFlow[k]);
{ if (n2 > net->Njuncs) tankstatus(pr, k, n2, -hyd->LinkFlow[k]);
tankstatus(pr, k, n1, n2);
}
// Note any change in link status; do not revise link flow // Note any change in link status; do not revise link flow
if (status != hyd->LinkStatus[k]) if (status != hyd->LinkStatus[k])
@@ -224,6 +222,7 @@ StatusType pumpstatus(Project *pr, int k, double dh)
{ {
// Use huge value for constant HP pump // Use huge value for constant HP pump
hmax = BIG; hmax = BIG;
if (hyd->LinkFlow[k] < TINY) return TEMPCLOSED;
} }
else else
{ {
@@ -394,16 +393,25 @@ StatusType fcvstatus(Project *pr, int k, StatusType s, double h1, double h2)
{ {
status = ACTIVE; 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; 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 ** Input: k = link index
** n1 = start node of link ** n = tank node index
** n2 = end node of link ** q = link flow rate out of (+) or into (-) tank
** Output: none ** Output: none
** Purpose: closes link flowing into full or out of empty tank ** 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; Network *net = &pr->network;
Hydraul *hyd = &pr->hydraul; Hydraul *hyd = &pr->hydraul;
int i, n; int i;
double h, q;
Stank *tank; Stank *tank;
Slink *link = &net->Link[k]; Slink *link = &net->Link[k];
// Return if link is closed // Return if link is closed
if (hyd->LinkStatus[k] <= CLOSED) return; 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 // Ignore reservoirs
i = n - net->Njuncs;
tank = &net->Tank[i]; tank = &net->Tank[i];
if (tank->A == 0.0) return; if (tank->A == 0.0) return;
// Find head difference across link // Can't add flow to a full tank
h = hyd->NodeHead[n1] - hyd->NodeHead[n2]; if (hyd->NodeHead[n] >= tank->Hmax && !tank->CanOverflow && q < 0.0)
// 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; hyd->LinkStatus[k] = TEMPCLOSED;
}
}
// If tank is empty, then prevent flow out of it // Can't remove flow from an empty tank
if (hyd->NodeHead[n1] <= tank->Hmin + hyd->Htol) else if (hyd->NodeHead[n] <= tank->Hmin && q > 0.0)
{
// 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; hyd->LinkStatus[k] = TEMPCLOSED;
}
}
} }

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: inpfile.c Module: inpfile.c
Description: saves network data to an EPANET formatted text file Description: saves network data to an EPANET formatted text file
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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 *TstatTxt[];
extern char *RptFlagTxt[]; extern char *RptFlagTxt[];
extern char *SectTxt[]; extern char *SectTxt[];
extern char *BackflowTxt[];
extern char *CurveTypeTxt[];
void saveauxdata(Project *pr, FILE *f) 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; int sect, newsect;
char *tok; char *tok;
char write;
char line[MAXLINE + 1]; char line[MAXLINE + 1];
char s[MAXLINE + 1]; char s[MAXLINE + 1];
FILE *InFile = pr->parser.InFile; FILE *InFile = pr->parser.InFile;
@@ -78,31 +79,23 @@ void saveauxdata(Project *pr, FILE *f)
{ {
case _LABELS: case _LABELS:
case _BACKDROP: case _BACKDROP:
case _TAGS:
fprintf(f, "\n%s", line); fprintf(f, "\n%s", line);
} }
} }
} }
// Write line of auxilary data to file // Write line of auxiliary data to file
else else
{ {
write = FALSE;
switch (sect) 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 _LABELS:
case _BACKDROP: case _BACKDROP:
write = TRUE; break; fprintf(f, "%s", line);
break;
default: default:
break; break;
} }
if (write) fprintf(f, "%s", line);
} }
} }
fclose(InFile); fclose(InFile);
@@ -151,40 +144,46 @@ int saveinpfile(Project *pr, const char *fname)
// (Leave demands for [DEMANDS] section) // (Leave demands for [DEMANDS] section)
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_JUNCTIONS); 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++) for (i = 1; i <= net->Njuncs; i++)
{ {
node = &net->Node[i]; node = &net->Node[i];
fprintf(f, "\n %-31s %12.4f", node->ID, node->El * pr->Ucf[ELEV]); fprintf(f, "\n %-31s\t%-12.4f", node->ID, node->El * pr->Ucf[ELEV]);
if (node->Comment) fprintf(f, " ;%s", node->Comment); if (node->Comment) fprintf(f, "\t;%s", node->Comment);
} }
// Write [RESERVOIRS] section // Write [RESERVOIRS] section
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_RESERVOIRS); fprintf(f, s_RESERVOIRS);
fprintf(f, "\n;;%-31s\t%-12s\t%-31s",
"ID", "Head", "Pattern");
for (i = 1; i <= net->Ntanks; i++) for (i = 1; i <= net->Ntanks; i++)
{ {
tank = &net->Tank[i]; tank = &net->Tank[i];
if (tank->A == 0.0) if (tank->A == 0.0)
{ {
node = &net->Node[tank->Node]; node = &net->Node[tank->Node];
sprintf(s, " %-31s %12.4f", node->ID, node->El * pr->Ucf[ELEV]); 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); if ((j = tank->Pat) > 0) sprintf(s1, "%s", net->Pattern[j].ID);
else strcpy(s1, " "); else strcpy(s1, " ");
fprintf(f, "\n%s %-31s", s, s1); fprintf(f, "\n%s\t%-31s", s, s1);
if (node->Comment) fprintf(f, " ;%s", node->Comment); if (node->Comment) fprintf(f, "\t;%s", node->Comment);
} }
} }
// Write [TANKS] section // Write [TANKS] section
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_TANKS); 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++) for (i = 1; i <= net->Ntanks; i++)
{ {
tank = &net->Tank[i]; tank = &net->Tank[i];
if (tank->A > 0.0) if (tank->A > 0.0)
{ {
node = &net->Node[tank->Node]; 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], node->ID, node->El * pr->Ucf[ELEV],
(tank->H0 - node->El) * pr->Ucf[ELEV], (tank->H0 - node->El) * pr->Ucf[ELEV],
(tank->Hmin - 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); if ((j = tank->Vcurve) > 0) sprintf(s1, "%s", net->Curve[j].ID);
else if (tank->CanOverflow) strcpy(s1, "*"); else if (tank->CanOverflow) strcpy(s1, "*");
else strcpy(s1, " "); else strcpy(s1, " ");
fprintf(f, "\n%s %-31s", s, s1); fprintf(f, "\n%s\t%-31s", s, s1);
if (tank->CanOverflow) fprintf(f, " YES "); if (tank->CanOverflow) fprintf(f, "\t%-12s", "YES");
if (node->Comment) fprintf(f, " ;%s", node->Comment); if (node->Comment) fprintf(f, "\t;%s", node->Comment);
} }
} }
// Write [PIPES] section // Write [PIPES] section
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_PIPES); 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++) for (i = 1; i <= net->Nlinks; i++)
{ {
link = &net->Link[i]; link = &net->Link[i];
if (link->Type <= PIPE) if (link->Type <= PIPE)
{ {
d = link->Diam; d = link->Diam;
kc = link->Kc; kc = link->InitSetting;
if (hyd->Formflag == DW) kc = kc * pr->Ucf[ELEV] * 1000.0; if (hyd->Formflag == DW) kc = kc * pr->Ucf[ELEV] * 1000.0;
km = link->Km * SQR(d) * SQR(d) / 0.02517; 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->ID, net->Node[link->N1].ID, net->Node[link->N2].ID,
link->Len * pr->Ucf[LENGTH], d * pr->Ucf[DIAM], kc, km); link->Len * pr->Ucf[LENGTH], d * pr->Ucf[DIAM], kc, km);
if (link->Type == CVPIPE) sprintf(s2, "CV"); 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, " "); else strcpy(s2, " ");
fprintf(f, "\n%s %-6s", s, s2); fprintf(f, "\n%s\t%-6s", s, s2);
if (link->Comment) fprintf(f, " ;%s", link->Comment); if (link->Comment) fprintf(f, "\t;%s", link->Comment);
} }
} }
// Write [PUMPS] section // Write [PUMPS] section
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_PUMPS); 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++) for (i = 1; i <= net->Npumps; i++)
{ {
n = net->Pump[i].Link; n = net->Pump[i].Link;
link = &net->Link[n]; link = &net->Link[n];
pump = &net->Pump[i]; 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); net->Node[link->N2].ID);
// Pump has constant power // 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 // Pump has a head curve
else if ((j = pump->Hcurve) > 0) 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 // Old format used for pump curve
@@ -259,25 +262,26 @@ int saveinpfile(Project *pr, const char *fname)
// Optional speed pattern // Optional speed pattern
if ((j = pump->Upat) > 0) if ((j = pump->Upat) > 0)
{ {
sprintf(s1, " PATTERN %s", net->Pattern[j].ID); sprintf(s1, "\tPATTERN %s", net->Pattern[j].ID);
strcat(s, s1); strcat(s, s1);
} }
// Optional speed setting // 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); strcat(s, s1);
} }
fprintf(f, "\n%s", s); 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 // Write [VALVES] section
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_VALVES); 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++) for (i = 1; i <= net->Nvalves; i++)
{ {
n = net->Valve[i].Link; n = net->Valve[i].Link;
@@ -285,8 +289,7 @@ int saveinpfile(Project *pr, const char *fname)
d = link->Diam; d = link->Diam;
// Valve setting // Valve setting
kc = link->Kc; kc = link->InitSetting;
if (kc == MISSING) kc = 0.0;
switch (link->Type) switch (link->Type)
{ {
case FCV: case FCV:
@@ -302,36 +305,44 @@ int saveinpfile(Project *pr, const char *fname)
} }
km = link->Km * SQR(d) * SQR(d) / 0.02517; 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, link->ID, net->Node[link->N1].ID,
net->Node[link->N2].ID, d * pr->Ucf[DIAM], net->Node[link->N2].ID, d * pr->Ucf[DIAM],
LinkTxt[link->Type]); LinkTxt[link->Type]);
// For GPV, setting = head curve index // 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); // For PCV add loss curve if present
fprintf(f, "\n%s %s", s, s1); else if (link->Type == PCV && (j = net->Valve[i].Curve) > 0)
if (link->Comment) fprintf(f, " ;%s", link->Comment); {
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 // Write [DEMANDS] section
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_DEMANDS); fprintf(f, s_DEMANDS);
fprintf(f, "\n;;%-31s\t%-14s\t%-31s\t%-31s",
"Junction", "Demand", "Pattern", "Category");
ucf = pr->Ucf[DEMAND]; ucf = pr->Ucf[DEMAND];
for (i = 1; i <= net->Njuncs; i++) for (i = 1; i <= net->Njuncs; i++)
{ {
node = &net->Node[i]; node = &net->Node[i];
for (demand = node->D; demand != NULL; demand = demand->next) for (demand = node->D; demand != NULL; demand = demand->next)
{ {
sprintf(s, " %-31s %14.6f", node->ID, ucf * demand->Base); if (demand->Base == 0.0) continue;
if ((j = demand->Pat) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID); 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, " "); else strcpy(s1, " ");
fprintf(f, "\n%s %-31s", s, s1); fprintf(f, "\n%s\t%-31s", s, s1);
if (demand->Name) fprintf(f, " ;%s", demand->Name); if (demand->Name) fprintf(f, "\t;%s", demand->Name);
} }
} }
@@ -339,25 +350,42 @@ int saveinpfile(Project *pr, const char *fname)
// Write [EMITTERS] section // Write [EMITTERS] section
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_EMITTERS); fprintf(f, s_EMITTERS);
fprintf(f, "\n;;%-31s\t%-14s",
"Junction", "Coefficient");
for (i = 1; i <= net->Njuncs; i++) for (i = 1; i <= net->Njuncs; i++)
{ {
node = &net->Node[i]; node = &net->Node[i];
if (node->Ke == 0.0) continue; if (node->Ke == 0.0) continue;
ke = pr->Ucf[FLOW] / pow(pr->Ucf[PRESSURE] * node->Ke, (1.0 / hyd->Qexp)); 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 // Write [STATUS] section
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_STATUS); fprintf(f, s_STATUS);
fprintf(f, "\n;;%-31s\t%-12s",
"ID", "Status/Setting");
for (i = 1; i <= net->Nlinks; i++) for (i = 1; i <= net->Nlinks; i++)
{ {
link = &net->Link[i]; link = &net->Link[i];
if (link->Type <= PUMP) 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 // 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); n = findpump(net, i);
pump = &net->Pump[n]; pump = &net->Pump[n];
if (pump->Hcurve == 0 && pump->Ptype != CONST_HP && 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) // Write fixed-status valves
else if (link->Kc == MISSING) 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) // (Use 6 pattern factors per line)
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_PATTERNS); fprintf(f, s_PATTERNS);
fprintf(f, "\n;;%-31s\t%-12s",
"ID", "Multipliers");
for (i = 1; i <= net->Npats; i++) for (i = 1; i <= net->Npats; i++)
{ {
if (net->Pattern[i].Comment) fprintf(f, "\n;%s", net->Pattern[i].Comment); if (net->Pattern[i].Comment) fprintf(f, "\n;%s", net->Pattern[i].Comment);
for (j = 0; j < net->Pattern[i].Length; j++) for (j = 0; j < net->Pattern[i].Length; j++)
{ {
if (j % 6 == 0) fprintf(f, "\n %-31s", net->Pattern[i].ID); 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 // Write [CURVES] section
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_CURVES); fprintf(f, s_CURVES);
fprintf(f, "\n;;%-31s\t%-12s\t%-12s", "ID", "X-Value", "Y-Value");
for (i = 1; i <= net->Ncurves; i++) 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]; curve = &net->Curve[i];
fprintf(f, "\n %-31s %12.4f %12.4f", curve->ID, curve->X[j], curve->Y[j]); if (curve->Comment) fprintf(f, "\n;%s", curve->Comment);
if (curve->Npts > 0)
{
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]; link = &net->Link[j];
// Get text of control's link status/setting // 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]); 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], fprintf(f, "\n%s AT %s %s", s, ControlTxt[TIMEOFDAY],
clocktime(rpt->Atime, control->Time)); clocktime(rpt->Atime, control->Time));
break; break;
default: continue;
} }
if (control->isEnabled == FALSE) fprintf(f, " DISABLED");
} }
// Write [RULES] section // Write [RULES] section
@@ -483,6 +528,7 @@ int saveinpfile(Project *pr, const char *fname)
{ {
fprintf(f, "\nRULE %s", pr->network.Rule[i].label); fprintf(f, "\nRULE %s", pr->network.Rule[i].label);
writerule(pr, f, i); // see RULES.C writerule(pr, f, i); // see RULES.C
if (pr->network.Rule[i].isEnabled == FALSE) fprintf(f, "\nDISABLED");
fprintf(f, "\n"); fprintf(f, "\n");
} }
@@ -490,40 +536,43 @@ int saveinpfile(Project *pr, const char *fname)
// (Skip nodes with default quality of 0) // (Skip nodes with default quality of 0)
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_QUALITY); fprintf(f, s_QUALITY);
fprintf(f, "\n;;%-31s\t%-14s", "ID", "InitQual");
for (i = 1; i <= net->Nnodes; i++) for (i = 1; i <= net->Nnodes; i++)
{ {
node = &net->Node[i]; node = &net->Node[i];
if (node->C0 == 0.0) continue; 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 // Write [SOURCES] section
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_SOURCES); 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++) for (i = 1; i <= net->Nnodes; i++)
{ {
node = &net->Node[i]; node = &net->Node[i];
source = node->S; source = node->S;
if (source == NULL) continue; 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); source->C0);
if ((j = source->Pat) > 0) if ((j = source->Pat) > 0)
{ {
sprintf(s1, "%s", net->Pattern[j].ID); sprintf(s1, "%s", net->Pattern[j].ID);
} }
else strcpy(s1, ""); else strcpy(s1, "");
fprintf(f, "\n%s %s", s, s1); fprintf(f, "\n%s\t%s", s, s1);
} }
// Write [MIXING] section // Write [MIXING] section
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_MIXING); fprintf(f, s_MIXING);
fprintf(f, "\n;;%-31s\t%-8s", "ID", "Model");
for (i = 1; i <= net->Ntanks; i++) for (i = 1; i <= net->Ntanks; i++)
{ {
tank = &net->Tank[i]; tank = &net->Tank[i];
if (tank->A == 0.0) continue; if (tank->A == 0.0) continue;
fprintf(f, "\n %-31s %-8s %12.4f", net->Node[tank->Node].ID, fprintf(f, "\n %-31s\t%-8s\t%12.4f", net->Node[tank->Node].ID,
MixTxt[tank->MixModel], (tank->V1max / tank->Vmax)); MixTxt[tank->MixModel], tank->V1frac);
} }
// Write [REACTIONS] section // 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 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 // Pipe-specific parameters
for (i = 1; i <= net->Nlinks; i++) 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->Type > PIPE) continue;
if (link->Kb != qual->Kbulk) 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) 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->A == 0.0) continue;
if (tank->Kb != qual->Kbulk) 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); tank->Kb * SECperDAY);
} }
} }
@@ -666,8 +719,11 @@ int saveinpfile(Project *pr, const char *fname)
break; 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 DEMAND MULTIPLIER %-.4f", hyd->Dmult);
fprintf(f, "\n EMITTER EXPONENT %-.4f", 1.0 / hyd->Qexp); 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 VISCOSITY %-.6f", hyd->Viscos / VISCOS);
fprintf(f, "\n DIFFUSIVITY %-.6f", qual->Diffus / DIFFUS); fprintf(f, "\n DIFFUSIVITY %-.6f", qual->Diffus / DIFFUS);
fprintf(f, "\n SPECIFIC GRAVITY %-.6f", hyd->SpGrav); fprintf(f, "\n SPECIFIC GRAVITY %-.6f", hyd->SpGrav);
@@ -775,31 +831,49 @@ int saveinpfile(Project *pr, const char *fname)
else fprintf(f, "\n %-20sNO",field->Name); 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 // Write [COORDINATES] section
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_COORDS); fprintf(f, s_COORDS);
fprintf(f, "\n;;%-31s\t%-14s\t%-14s", "ID", "X-Coord", "Y-Coord");
for (i = 1; i <= net->Nnodes; i++) for (i = 1; i <= net->Nnodes; i++)
{ {
node = &net->Node[i]; node = &net->Node[i];
if (node->X == MISSING || node->Y == MISSING) continue; 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 // Write [VERTICES] section
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, s_VERTICES); fprintf(f, s_VERTICES);
fprintf(f, "\n;;%-31s\t%-14s\t%-14s", "ID", "X-Coord", "Y-Coord");
for (i = 1; i <= net->Nlinks; i++) for (i = 1; i <= net->Nlinks; i++)
{ {
link = &net->Link[i]; link = &net->Link[i];
if (link->Vertices != NULL) if (link->Vertices != NULL)
{ {
for (j = 0; j < link->Vertices->Npts; j++) 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]); 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"); fprintf(f, "\n");
saveauxdata(pr, f); saveauxdata(pr, f);

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: input1.c Module: input1.c
Description: retrieves network data from an EPANET input file Description: retrieves network data from an EPANET input file
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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 // Defined in ENUMSTXT.H
extern char *Fldname[]; extern char *Fldname[];
extern char *RptFlowUnitsTxt[]; extern char *RptFlowUnitsTxt[];
extern char *PressUnitsTxt[];
extern void reindextanks(Project *pr);
int getdata(Project *pr) int getdata(Project *pr)
/* /*
@@ -58,13 +61,18 @@ int getdata(Project *pr)
// Read in network data // Read in network data
rewind(pr->parser.InFile); rewind(pr->parser.InFile);
ERRCODE(readdata(pr)); errcode = readdata(pr);
// Adjust data and convert it to internal units // Adjust data and convert it to internal units
if (!errcode) adjustdata(pr); // (error code 200 means there are non-fatal errors in input file)
if (!errcode) initunits(pr); if (errcode == 0 || errcode == 200)
ERRCODE(inittanks(pr)); {
if (!errcode) convertunits(pr); reindextanks(pr);
adjustdata(pr);
inittanks(pr);
initunits(pr);
convertunits(pr);
}
return errcode; return errcode;
} }
@@ -96,8 +104,7 @@ void setdefaults(Project *pr)
pr->Warnflag = FALSE; // Warning flag is off pr->Warnflag = FALSE; // Warning flag is off
parser->Unitsflag = US; // US unit system parser->Unitsflag = US; // US unit system
parser->Flowflag = GPM; // Flow units are gpm parser->Flowflag = GPM; // Flow units are gpm
parser->Pressflag = PSI; // Pressure units are psi parser->Pressflag = DEFAULTUNIT; // Pressure units set based on unit system
parser->DefPat = 0; // Default demand pattern index
out->Hydflag = SCRATCH; // No external hydraulics file out->Hydflag = SCRATCH; // No external hydraulics file
rpt->Tstatflag = SERIES; // Generate time series output rpt->Tstatflag = SERIES; // Generate time series output
@@ -121,6 +128,8 @@ void setdefaults(Project *pr)
hyd->Epump = EPUMP; // Default pump efficiency hyd->Epump = EPUMP; // Default pump efficiency
hyd->Emax = 0.0; // Zero peak energy usage hyd->Emax = 0.0; // Zero peak energy usage
hyd->Qexp = 2.0; // Flow exponent for emitters 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->Dmult = 1.0; // Demand multiplier
hyd->RQtol = RQTOL; // Default hydraulics parameters hyd->RQtol = RQTOL; // Default hydraulics parameters
hyd->CheckFreq = CHECKFREQ; hyd->CheckFreq = CHECKFREQ;
@@ -212,9 +221,7 @@ void adjustdata(Project *pr)
int i; int i;
double ucf; // Unit conversion factor double ucf; // Unit conversion factor
Pdemand demand; // Pointer to demand record
Slink *link; Slink *link;
Snode *node;
Stank *tank; Stank *tank;
// Use 1 hr pattern & report time step if none specified // 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 // Report start time cannot be greater than simulation duration
if (time->Rstart > time->Dur) time->Rstart = 0; 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 no quality timestep, then make it 1/10 of hydraulic timestep
if (time->Qstep == 0) time->Qstep = time->Hstep / 10; if (time->Qstep == 0) time->Qstep = time->Hstep / 10;
@@ -258,6 +262,7 @@ void adjustdata(Project *pr)
case MLD: // megaliters/day case MLD: // megaliters/day
case CMH: // cubic meters/hr case CMH: // cubic meters/hr
case CMD: // cubic meters/day case CMD: // cubic meters/day
case CMS: // cubic meters/second
parser->Unitsflag = SI; parser->Unitsflag = SI;
break; break;
default: default:
@@ -265,8 +270,11 @@ void adjustdata(Project *pr)
} }
// Revise pressure units depending on flow units // Revise pressure units depending on flow units
if (parser->Unitsflag != SI) parser->Pressflag = PSI; if (parser->Pressflag == DEFAULTUNIT)
else if (parser->Pressflag == PSI) parser->Pressflag = METERS; {
if (parser->Unitsflag == SI) parser->Pressflag = METERS;
else parser->Pressflag = PSI;
}
// Store value of viscosity & diffusivity // Store value of viscosity & diffusivity
ucf = 1.0; ucf = 1.0;
@@ -322,26 +330,20 @@ void adjustdata(Project *pr)
if (tank->Kb == MISSING) tank->Kb = qual->Kbulk; if (tank->Kb == MISSING) tank->Kb = qual->Kbulk;
} }
// Use default pattern if none assigned to a demand // Set default pattern index
parser->DefPat = findpattern(net, parser->DefPatID); i = findpattern(net, parser->DefPatID);
if (parser->DefPat > 0) for (i = 1; i <= net->Nnodes; i++) if (i > 0)
{ hyd->DefPat = i;
node = &net->Node[i];
for (demand = node->D; demand != NULL; demand = demand->next)
{
if (demand->Pat == 0) demand->Pat = parser->DefPat;
}
}
// Remove QUALITY as a reporting variable if no WQ analysis // Remove QUALITY as a reporting variable if no WQ analysis
if (qual->Qualflag == NONE) rpt->Field[QUALITY].Enabled = FALSE; if (qual->Qualflag == NONE) rpt->Field[QUALITY].Enabled = FALSE;
} }
int inittanks(Project *pr) void inittanks(Project *pr)
/* /*
**--------------------------------------------------------------- **---------------------------------------------------------------
** Input: none ** Input: none
** Output: returns error code ** Output: none
** Purpose: initializes volumes in non-cylindrical tanks ** Purpose: initializes volumes in non-cylindrical tanks
**--------------------------------------------------------------- **---------------------------------------------------------------
*/ */
@@ -350,7 +352,7 @@ int inittanks(Project *pr)
int i, j, n = 0; int i, j, n = 0;
double a; double a;
int errcode = 0, levelerr; int errcode = 0;
char errmsg[MAXMSG+1] = ""; char errmsg[MAXMSG+1] = "";
Stank *tank; Stank *tank;
Scurve *curve; Scurve *curve;
@@ -360,26 +362,13 @@ int inittanks(Project *pr)
tank = &net->Tank[j]; tank = &net->Tank[j];
if (tank->A == 0.0) continue; // Skip reservoirs if (tank->A == 0.0) continue; // Skip reservoirs
// Check for valid lower/upper tank levels // See if tank has a volume curve
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
i = tank->Vcurve; i = tank->Vcurve;
if (i > 0) if (i > 0)
{ {
curve = &net->Curve[i]; curve = &net->Curve[i];
n = curve->Npts - 1; 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 // Find min., max., and initial volumes from curve
tank->Vmin = interp(curve->Npts, curve->X, curve->Y, tank->Hmin); tank->Vmin = interp(curve->Npts, curve->X, curve->Y, tank->Hmin);
tank->Vmax = interp(curve->Npts, curve->X, curve->Y, tank->Hmax); tank->Vmax = interp(curve->Npts, curve->X, curve->Y, tank->Hmax);
@@ -390,17 +379,6 @@ int inittanks(Project *pr)
tank->A = sqrt(4.0 * a / PI); 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;
}
}
return errcode;
} }
void initunits(Project *pr) void initunits(Project *pr)
@@ -430,8 +408,6 @@ void initunits(Project *pr)
strcpy(rpt->Field[DEMAND].Units, RptFlowUnitsTxt[parser->Flowflag]); strcpy(rpt->Field[DEMAND].Units, RptFlowUnitsTxt[parser->Flowflag]);
strcpy(rpt->Field[ELEV].Units, u_METERS); strcpy(rpt->Field[ELEV].Units, u_METERS);
strcpy(rpt->Field[HEAD].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[LENGTH].Units, u_METERS);
strcpy(rpt->Field[DIAM].Units, u_MMETERS); strcpy(rpt->Field[DIAM].Units, u_MMETERS);
strcpy(rpt->Field[FLOW].Units, RptFlowUnitsTxt[parser->Flowflag]); 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 == MLD) qcf = MLDperCFS;
if (parser->Flowflag == CMH) qcf = CMHperCFS; if (parser->Flowflag == CMH) qcf = CMHperCFS;
if (parser->Flowflag == CMD) qcf = CMDperCFS; if (parser->Flowflag == CMD) qcf = CMDperCFS;
if (parser->Flowflag == CMS) qcf = CMSperCFS;
hcf = MperFT; hcf = MperFT;
if (parser->Pressflag == METERS) pcf = MperFT * hyd->SpGrav;
else pcf = KPAperPSI * PSIperFT * hyd->SpGrav;
wcf = KWperHP; wcf = KWperHP;
} }
else // US units else // US units
@@ -457,7 +432,6 @@ void initunits(Project *pr)
strcpy(rpt->Field[DEMAND].Units, RptFlowUnitsTxt[parser->Flowflag]); strcpy(rpt->Field[DEMAND].Units, RptFlowUnitsTxt[parser->Flowflag]);
strcpy(rpt->Field[ELEV].Units, u_FEET); strcpy(rpt->Field[ELEV].Units, u_FEET);
strcpy(rpt->Field[HEAD].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[LENGTH].Units, u_FEET);
strcpy(rpt->Field[DIAM].Units, u_INCHES); strcpy(rpt->Field[DIAM].Units, u_INCHES);
strcpy(rpt->Field[FLOW].Units, RptFlowUnitsTxt[parser->Flowflag]); 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 == IMGD) qcf = IMGDperCFS;
if (parser->Flowflag == AFD) qcf = AFDperCFS; if (parser->Flowflag == AFD) qcf = AFDperCFS;
hcf = 1.0; hcf = 1.0;
pcf = PSIperFT * hyd->SpGrav;
wcf = 1.0; 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, ""); strcpy(rpt->Field[QUALITY].Units, "");
ccf = 1.0; ccf = 1.0;
if (qual->Qualflag == CHEM) if (qual->Qualflag == CHEM)
@@ -533,12 +513,11 @@ void convertunits(Project *pr)
Parser *parser = &pr->parser; Parser *parser = &pr->parser;
int i, j, k; int i, j, k;
double ucf; // Unit conversion factor double ucf, ecf; // Unit conversion factor
Pdemand demand; // Pointer to demand record Pdemand demand; // Pointer to demand record
Snode *node; Snode *node;
Stank *tank; Stank *tank;
Slink *link; Slink *link;
Spump *pump;
Scontrol *control; Scontrol *control;
// Convert nodal elevations & initial WQ // Convert nodal elevations & initial WQ
@@ -565,7 +544,9 @@ void convertunits(Project *pr)
hyd->Preq /= pr->Ucf[PRESSURE]; hyd->Preq /= pr->Ucf[PRESSURE];
// Convert emitter discharge coeffs. to head loss coeff. // 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++) for (i = 1; i <= net->Njuncs; i++)
{ {
node = &net->Node[i]; node = &net->Node[i];
@@ -588,7 +569,6 @@ void convertunits(Project *pr)
tank->Kb /= SECperDAY; tank->Kb /= SECperDAY;
tank->V = tank->V0; tank->V = tank->V0;
tank->C = node->C0; tank->C = node->C0;
tank->V1max *= tank->Vmax;
} }
// Convert hydraulic convergence criteria // Convert hydraulic convergence criteria
@@ -620,33 +600,17 @@ void convertunits(Project *pr)
// Convert units on reaction coeffs. // Convert units on reaction coeffs.
link->Kb /= SECperDAY; link->Kb /= SECperDAY;
link->Kw /= SECperDAY; link->Kw /= SECperDAY;
// Convert leakage parameters
link->LeakArea /= pr->Ucf[LENGTH];
link->LeakExpan /= pr->Ucf[LENGTH];
} }
else if (link->Type == PUMP) else if (link->Type == PUMP)
{ {
// Convert units for pump curve parameters link->Km /= pr->Ucf[POWER];
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];
}
}
else else
{ {
// For flow control valves, convert flow setting // For flow control valves, convert flow setting
@@ -667,6 +631,7 @@ void convertunits(Project *pr)
break; break;
} }
} }
link->InitSetting = link->Kc;
} }
// Convert units on control settings // Convert units on control settings

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: input2.c Module: input2.c
Description: reads and interprets network data from an EPANET input file Description: reads and interprets network data from an EPANET input file
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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 "hash.h"
#include "text.h" #include "text.h"
#define MAXERRS 10 // Max. input errors reported
extern char *SectTxt[]; // Input section keywords (see ENUMSTXT.H) extern char *SectTxt[]; // Input section keywords (see ENUMSTXT.H)
// Exported functions // Exported functions
int addnodeID(Network *n, int, char *); int addnodeID(Network *, int, char *);
int addlinkID(Network *n, int, char *); int addlinkID(Network *, int, char *);
int getunitsoption(Project *, char *);
// Imported functions int getheadlossoption(Project *, char *);
extern int powercurve(double, double, double, double, double, double *,
double *, double *);
// Local functions // Local functions
static int newline(Project *, int, char *); static int newline(Project *, int, char *);
static int addpattern(Network *, char *); static int addpattern(Network *, char *);
static int addcurve(Network *, char *); static int addcurve(Network *, char *);
static int unlinked(Project *);
static int getpumpparams(Project *);
static void inperrmsg(Project *, int, int, char *); static void inperrmsg(Project *, int, int, char *);
@@ -101,7 +95,11 @@ int netsize(Project *pr)
if (sect == _END) break; if (sect == _END) break;
continue; continue;
} }
else continue; else
{
sect = -1;
continue;
}
} }
// Add to count of current object // Add to count of current object
@@ -123,6 +121,12 @@ int netsize(Project *pr)
errcode = addcurve(&pr->network, tok); errcode = addcurve(&pr->network, tok);
parser->MaxCurves = pr->network.Ncurves; parser->MaxCurves = pr->network.Ncurves;
break; 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; if (errcode) break;
} }
@@ -130,11 +134,6 @@ int netsize(Project *pr)
parser->MaxNodes = parser->MaxJuncs + parser->MaxTanks; parser->MaxNodes = parser->MaxJuncs + parser->MaxTanks;
parser->MaxLinks = parser->MaxPipes + parser->MaxPumps + parser->MaxValves; parser->MaxLinks = parser->MaxPipes + parser->MaxPumps + parser->MaxValves;
if (parser->MaxPats < 1) parser->MaxPats = 1; 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; return errcode;
} }
@@ -152,6 +151,7 @@ int readdata(Project *pr)
char line[MAXLINE + 1], // Line from input data file char line[MAXLINE + 1], // Line from input data file
wline[MAXLINE + 1]; // Working copy of input line wline[MAXLINE + 1]; // Working copy of input line
char errmsg[MAXMSG + 1] = "";
int sect, newsect, // Data sections int sect, newsect, // Data sections
errcode = 0, // Error code errcode = 0, // Error code
inperr, errsum; // Error code & total error count inperr, errsum; // Error code & total error count
@@ -213,7 +213,7 @@ int readdata(Project *pr)
// Check if max. line length exceeded // Check if max. line length exceeded
if (strlen(line) >= MAXLINE) 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, pr->Msg);
writeline(pr, line); writeline(pr, line);
errsum++; errsum++;
@@ -231,9 +231,11 @@ int readdata(Project *pr)
} }
else else
{ {
inperrmsg(pr, 201, sect, line); sect = -1;
parser->ErrTok = 0;
errsum++; errsum++;
break; inperrmsg(pr, 299, sect, line);
continue;
} }
} }
@@ -249,26 +251,13 @@ int readdata(Project *pr)
errsum++; errsum++;
} }
} }
else else continue;
{
errcode = 200;
break;
} }
} }
// Stop if reach end of file or max. error count
if (errsum == MAXERRS) break;
}
// Check for errors // Check for errors
if (errsum > 0) errcode = 200; 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 input buffer
free(parser->X); free(parser->X);
return errcode; return errcode;
@@ -315,11 +304,13 @@ int newline(Project *pr, int sect, char *line)
if (ruledata(pr) > 0) if (ruledata(pr) > 0)
{ {
ruleerrmsg(pr); ruleerrmsg(pr);
deleterule(pr, pr->network.Nrules);
return 200; return 200;
} }
else return 0; else return 0;
case _SOURCES: return (sourcedata(pr)); case _SOURCES: return (sourcedata(pr));
case _EMITTERS: return (emitterdata(pr)); case _EMITTERS: return (emitterdata(pr));
case _LEAKAGE: return (leakagedata(pr));
case _QUALITY: return (qualdata(pr)); case _QUALITY: return (qualdata(pr));
case _STATUS: return (statusdata(pr)); case _STATUS: return (statusdata(pr));
case _ROUGHNESS: return (0); case _ROUGHNESS: return (0);
@@ -329,139 +320,18 @@ int newline(Project *pr, int sect, char *line)
case _REPORT: return (reportdata(pr)); case _REPORT: return (reportdata(pr));
case _TIMES: return (timedata(pr)); case _TIMES: return (timedata(pr));
case _OPTIONS: return (optiondata(pr)); case _OPTIONS: return (optiondata(pr));
case _TAGS: return (tagdata(pr));
case _COORDS: return (coordata(pr)); case _COORDS: return (coordata(pr));
case _VERTICES: return (vertexdata(pr)); case _VERTICES: return (vertexdata(pr));
// Data in these sections are not used for any computations // Data in these sections are not used for any computations
case _LABELS: case _LABELS:
case _TAGS:
case _BACKDROP: case _BACKDROP:
return (0); return (0);
} }
return 201; 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) int addnodeID(Network *net, int n, char *id)
/* /*
**------------------------------------------------------------- **-------------------------------------------------------------
@@ -572,52 +442,49 @@ int addcurve(Network *network, char *id)
return 0; return 0;
} }
int unlinked(Project *pr) int getunitsoption(Project *pr, char *units)
/* /*
**-------------------------------------------------------------- **-------------------------------------------------------------
** Input: none ** Input: units = name of flow units to be used
** Output: returns error code if any unlinked junctions found ** Output: returns 1 if successful, 0 if not
** Purpose: checks for unlinked junctions in network ** Purpose: sets the flows units to be used by a project.
**
** NOTE: unlinked tanks have no effect on computations.
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
Network *net = &pr->network; Parser *parser = &pr->parser;
int *marked; if (match(units, w_CFS)) parser->Flowflag = CFS;
int i, err, errcode; 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; int getheadlossoption(Project *pr, char *formula)
err = 0; /*
**-------------------------------------------------------------
// Create an array to record number of links incident on each node ** Input: formula = name of head loss formula to be used
marked = (int *)calloc(net->Nnodes + 1, sizeof(int)); ** Output: returns 1 if successful, 0 if not
ERRCODE(MEMCHECK(marked)); ** Purpose: sets the head loss formula to be used by a project.
if (errcode) return errcode; **--------------------------------------------------------------
memset(marked, 0, (net->Nnodes + 1) * sizeof(int)); */
{
// Mark end nodes of each link Hydraul *hyd = &pr->hydraul;
for (i = 1; i <= net->Nlinks; i++) if (match(formula, w_HW)) hyd->Formflag = HW;
{ else if (match(formula, w_DW)) hyd->Formflag = DW;
marked[net->Link[i].N1]++; else if (match(formula, w_CM)) hyd->Formflag = CM;
marked[net->Link[i].N2]++; else return 0;
} return 1;
// 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 findmatch(char *line, char *keyword[]) int findmatch(char *line, char *keyword[])
@@ -686,7 +553,7 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment)
*/ */
{ {
int n; int n;
size_t len, m; int len, m;
char *c, *c2; char *c, *c2;
// clear comment // clear comment
@@ -704,10 +571,10 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment)
if (c2) if (c2)
{ {
// there is a comment here, after the semi-colon. // there is a comment here, after the semi-colon.
len = strlen(c2); len = (int)strlen(c2);
if (len > 0) if (len > 0)
{ {
len = strcspn(c2, "\n\r"); len = (int)strcspn(c2, "\n\r");
len = MIN(len, MAXMSG); len = MIN(len, MAXMSG);
strncpy(comment, c2, len); strncpy(comment, c2, len);
comment[MIN(len,MAXMSG)] = '\0'; comment[MIN(len,MAXMSG)] = '\0';
@@ -855,6 +722,10 @@ void inperrmsg(Project *pr, int err, int sect, char *line)
else strcpy(tok, ""); else strcpy(tok, "");
// write error message to report file // write error message to report file
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:", sprintf(pr->Msg, "Error %d: %s %s in %s section:",
err, geterrmsg(err, errStr), tok, SectTxt[sect]); err, geterrmsg(err, errStr), tok, SectTxt[sect]);
writeline(pr, pr->Msg); writeline(pr, pr->Msg);

File diff suppressed because it is too large Load Diff

527
src/leakage.c Normal file
View 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);
}

View File

@@ -1,15 +1,15 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: mempool.c Module: mempool.c
Description: a simple fast poooled memory allocation package Description: a simple fast poooled memory allocation package
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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 David Kirk (ed.), Academic Press, Boston, MA, 1992
****************************************************************************** ******************************************************************************
*/ */
@@ -72,7 +72,11 @@ struct Mempool * mempool_create()
if (mempool == NULL) return NULL; if (mempool == NULL) return NULL;
mempool->first = createMemBlock(); mempool->first = createMemBlock();
mempool->current = mempool->first; mempool->current = mempool->first;
if (mempool->first == NULL) return NULL; if (mempool->first == NULL)
{
free(mempool);
return NULL;
}
return mempool; return mempool;
} }

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: mempool.h Module: mempool.h
Description: header for a simple pooled memory allocator Description: header for a simple pooled memory allocator
Authors: see AUTHORS Authors: see AUTHORS

View File

@@ -33,7 +33,8 @@ typedef enum {
ENR_LPM = 6, ENR_LPM = 6,
ENR_MLD = 7, ENR_MLD = 7,
ENR_CMH = 8, ENR_CMH = 8,
ENR_CMD = 9 ENR_CMD = 9,
ENR_CMS = 10
} ENR_FlowUnits; } ENR_FlowUnits;
typedef enum { typedef enum {

View File

@@ -3,7 +3,8 @@
// epanet_output.c -- API for reading results from EPANET binary output file // epanet_output.c -- API for reading results from EPANET binary output file
// //
// Version: 0.40 // Version: 0.40
// Date 04/02/2019 // Date 08/02/2023
// 04/02/2019
// 09/06/2017 // 09/06/2017
// 06/17/2016 // 06/17/2016
// 08/05/2014 // 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 ** 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 ** and nullify pointer to ENR_Handle struct
** **
** NOTE: ENR_close must be called before program end ** 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 ** Returns: warning / error code
** Purpose: Opens the output binary file and reads prologue and epilogue ** 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 errorcode = 0;
int* temp = newIntArray(NELEMENTTYPES); int* temp;
data_t* p_data; data_t* p_data;
p_data = (data_t*)p_handle; p_data = (data_t*)p_handle;
if (p_data == NULL) return -1; if (p_data == NULL) return -1;
// Check memory for count values
else if MEMCHECK(temp = newIntArray(NELEMENTTYPES)) errorcode = 411;
else else
{ {
temp[0] = p_data->nodeCount; 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 ** 7 = megaliters/day
** 8 = cubic meters/hour ** 8 = cubic meters/hour
** 9 = cubic meters/day ** 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; *name = temp;
*length = MAXID_P1; *length = MAXID_P1;
} }
else free(temp);
} }
return set_error(p_data->error_handle, errorcode); return set_error(p_data->error_handle, errorcode);

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: output.c Module: output.c
Description: binary file read/write routines Description: binary file read/write routines
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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: case FCV:
x[i] = (REAL4)(setting * pr->Ucf[FLOW]); break; x[i] = (REAL4)(setting * pr->Ucf[FLOW]); break;
case TCV: case TCV:
case PCV:
x[i] = (REAL4)setting; break; x[i] = (REAL4)setting; break;
default: x[i] = 0.0f; default: x[i] = 0.0f;
} }
@@ -587,8 +588,8 @@ int linkoutput(Project *pr, int j, REAL4 *x, double ucf)
case FRICTION: // Friction factor case FRICTION: // Friction factor
// f = 2ghd/(Lu^2) where f = friction factor // f = 2ghd/(Lu^2) where f = friction factor
// u = velocity, g = grav. accel., h = head loss // u = velocity, g = grav. accel., h = head
//loss, d = diam., & L = pipe length // loss, d = diam., & L = pipe length
for (i = 1; i <= net->Nlinks; i++) for (i = 1; i <= net->Nlinks; i++)
{ {
if (net->Link[i].Type <= PIPE && ABS(hyd->LinkFlow[i]) > TINY) if (net->Link[i].Type <= PIPE && ABS(hyd->LinkFlow[i]) > TINY)

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: project.c Module: project.c
Description: project data management routines Description: project data management routines
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 11/15/2019 Last Updated: 04/23/2025
****************************************************************************** ******************************************************************************
*/ */
@@ -24,6 +24,81 @@
#include "types.h" #include "types.h"
#include "funcs.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) int openfiles(Project *pr, const char *f1, const char *f2, const char *f3)
/*---------------------------------------------------------------- /*----------------------------------------------------------------
@@ -93,10 +168,9 @@ int openhydfile(Project *pr)
INT4 version; INT4 version;
int errcode = 0; 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.HydFile != NULL)
{ {
if (pr->outfile.Hydflag == SCRATCH) return 0;
fclose(pr->outfile.HydFile); fclose(pr->outfile.HydFile);
pr->outfile.HydFile = NULL; pr->outfile.HydFile = NULL;
} }
@@ -253,6 +327,11 @@ void initpointers(Project *pr)
pr->hydraul.P = NULL; pr->hydraul.P = NULL;
pr->hydraul.Y = NULL; pr->hydraul.Y = NULL;
pr->hydraul.Xflow = 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.NodeQual = NULL;
pr->quality.PipeRateCoeff = NULL; pr->quality.PipeRateCoeff = NULL;
@@ -279,6 +358,8 @@ void initpointers(Project *pr)
pr->hydraul.smatrix.NZSUB = NULL; pr->hydraul.smatrix.NZSUB = NULL;
pr->hydraul.smatrix.LNZ = NULL; pr->hydraul.smatrix.LNZ = NULL;
pr->report.reportCallback = NULL;
initrules(pr); initrules(pr);
} }
@@ -313,10 +394,18 @@ int allocdata(Project *pr)
pr->hydraul.NodeDemand = (double *)calloc(n, sizeof(double)); pr->hydraul.NodeDemand = (double *)calloc(n, sizeof(double));
pr->hydraul.NodeHead = (double *)calloc(n, sizeof(double)); pr->hydraul.NodeHead = (double *)calloc(n, sizeof(double));
pr->quality.NodeQual = (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->network.Node));
ERRCODE(MEMCHECK(pr->hydraul.NodeDemand)); ERRCODE(MEMCHECK(pr->hydraul.NodeDemand));
ERRCODE(MEMCHECK(pr->hydraul.NodeHead)); ERRCODE(MEMCHECK(pr->hydraul.NodeHead));
ERRCODE(MEMCHECK(pr->quality.NodeQual)); 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 // 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].D = NULL; // node demand
pr->network.Node[n].S = NULL; // node source pr->network.Node[n].S = NULL; // node source
pr->network.Node[n].Comment = NULL; pr->network.Node[n].Comment = NULL;
pr->network.Node[n].Tag = NULL;
} }
for (n = 0; n <= pr->parser.MaxLinks; n++) for (n = 0; n <= pr->parser.MaxLinks; n++)
{ {
pr->network.Link[n].Vertices = NULL; pr->network.Link[n].Vertices = NULL;
pr->network.Link[n].Comment = 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.LinkFlow);
free(pr->hydraul.LinkSetting); free(pr->hydraul.LinkSetting);
free(pr->hydraul.LinkStatus); 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(pr->quality.NodeQual);
// Free memory used for nodal adjacency lists // Free memory used for nodal adjacency lists
@@ -402,6 +497,7 @@ void freedata(Project *pr)
freedemands(&(pr->network.Node[j])); freedemands(&(pr->network.Node[j]));
free(pr->network.Node[j].S); free(pr->network.Node[j].S);
free(pr->network.Node[j].Comment); free(pr->network.Node[j].Comment);
free(pr->network.Node[j].Tag);
} }
free(pr->network.Node); free(pr->network.Node);
} }
@@ -413,6 +509,7 @@ void freedata(Project *pr)
{ {
freelinkvertices(&pr->network.Link[j]); freelinkvertices(&pr->network.Link[j]);
free(pr->network.Link[j].Comment); free(pr->network.Link[j].Comment);
free(pr->network.Link[j].Tag);
} }
} }
free(pr->network.Link); free(pr->network.Link);
@@ -482,7 +579,7 @@ Pdemand finddemand(Pdemand d, int index)
return d; 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 ** Input: node = a network junction node
** dbase = base demand value ** dbase = base demand value
@@ -550,26 +647,36 @@ int addlinkvertex(Slink *link, double x, double y)
*/ */
{ {
static int CHUNKSIZE = 5; static int CHUNKSIZE = 5;
int n; int n, newCapacity;
Pvertices vertices; Pvertices vertices;
if (link->Vertices == NULL) double *newX, *newY;
vertices = link->Vertices;
if (vertices == NULL)
{ {
vertices = (struct Svertices *) malloc(sizeof(struct Svertices)); vertices = (struct Svertices *) malloc(sizeof(struct Svertices));
if (vertices == NULL) return 101; if (vertices == NULL) return 101;
vertices->Npts = 0; vertices->Npts = 0;
vertices->Capacity = CHUNKSIZE; vertices->Capacity = 0;
vertices->X = (double *) calloc(vertices->Capacity, sizeof(double)); vertices->X = NULL;
vertices->Y = (double *) calloc(vertices->Capacity, sizeof(double)); vertices->Y = NULL;
link->Vertices = vertices; link->Vertices = vertices;
} }
vertices = link->Vertices;
if (vertices->Npts >= vertices->Capacity) if (vertices->Npts >= vertices->Capacity)
{ {
vertices->Capacity += CHUNKSIZE; newCapacity = vertices->Capacity + CHUNKSIZE;
vertices->X = realloc(vertices->X, vertices->Capacity * sizeof(double)); newX = realloc(vertices->X, newCapacity * sizeof(double));
vertices->Y = realloc(vertices->Y, vertices->Capacity * 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; n = vertices->Npts;
vertices->X[n] = x; vertices->X[n] = x;
vertices->Y[n] = y; vertices->Y[n] = y;
@@ -647,7 +754,6 @@ int buildadjlists(Network *net)
return errcode; return errcode;
} }
void freeadjlists(Network *net) void freeadjlists(Network *net)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
@@ -734,6 +840,66 @@ int incontrols(Project *pr, int objType, int index)
return 0; 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) 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; 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 ** Input: id = node ID
** Output: none ** Output: none
@@ -807,7 +1002,7 @@ int findnode(Network *network, char *id)
return (hashtable_find(network->NodeHashTable, id)); return (hashtable_find(network->NodeHashTable, id));
} }
int findlink(Network *network, char *id) int findlink(Network *network, const char *id)
/*---------------------------------------------------------------- /*----------------------------------------------------------------
** Input: id = link ID ** Input: id = link ID
** Output: none ** Output: none
@@ -823,7 +1018,7 @@ int findtank(Network *network, int index)
/*---------------------------------------------------------------- /*----------------------------------------------------------------
** Input: index = node index ** Input: index = node index
** Output: none ** 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 ** Purpose: for use in the deletenode function
**---------------------------------------------------------------- **----------------------------------------------------------------
*/ */
@@ -840,7 +1035,7 @@ int findpump(Network *network, int index)
/*---------------------------------------------------------------- /*----------------------------------------------------------------
** Input: index = link ID ** Input: index = link ID
** Output: none ** 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 ** Purpose: for use in the deletelink function
**---------------------------------------------------------------- **----------------------------------------------------------------
*/ */
@@ -857,7 +1052,7 @@ int findvalve(Network *network, int index)
/*---------------------------------------------------------------- /*----------------------------------------------------------------
** Input: index = link ID ** Input: index = link ID
** Output: none ** 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 ** Purpose: for use in the deletelink function
**---------------------------------------------------------------- **----------------------------------------------------------------
*/ */
@@ -870,7 +1065,7 @@ int findvalve(Network *network, int index)
return NOTFOUND; return NOTFOUND;
} }
int findpattern(Network *network, char *id) int findpattern(Network *network, const char *id)
/*---------------------------------------------------------------- /*----------------------------------------------------------------
** Input: id = time pattern ID ** Input: id = time pattern ID
** Output: none ** Output: none
@@ -889,7 +1084,7 @@ int findpattern(Network *network, char *id)
return -1; return -1;
} }
int findcurve(Network *network, char *id) int findcurve(Network *network, const char *id)
/*---------------------------------------------------------------- /*----------------------------------------------------------------
** Input: id = data curve ID ** Input: id = data curve ID
** Output: none ** Output: none
@@ -973,7 +1168,7 @@ void adjustcurves(Network *network, int index)
**---------------------------------------------------------------- **----------------------------------------------------------------
*/ */
{ {
int j, k, setting; int j, k, curve;
// Adjust tank volume curves // Adjust tank volume curves
for (j = 1; j <= network->Ntanks; j++) for (j = 1; j <= network->Ntanks; j++)
@@ -988,60 +1183,29 @@ void adjustcurves(Network *network, int index)
adjustcurve(&network->Pump[j].Ecurve, index); adjustcurve(&network->Pump[j].Ecurve, index);
} }
// Adjust GPV curves // Adjust PCV & GPV curves
for (j = 1; j <= network->Nvalves; j++) for (j = 1; j <= network->Nvalves; j++)
{ {
k = network->Valve[j].Link; 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) if (network->Link[k].Type == GPV)
{ {
setting = INT(network->Link[k].Kc); curve = INT(network->Link[k].Kc);
adjustcurve(&setting, index); adjustcurve(&curve, index);
network->Link[k].Kc = setting; 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) int resizecurve(Scurve *curve, int size)
/*---------------------------------------------------------------- /*----------------------------------------------------------------
@@ -1072,6 +1236,112 @@ int resizecurve(Scurve *curve, int size)
return 0; 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) int getcomment(Network *network, int object, int index, char *comment)
//---------------------------------------------------------------- //----------------------------------------------------------------
// Input: object = a type of network object // 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) int namevalid(const char *name)
//---------------------------------------------------------------- //----------------------------------------------------------------
// Input: name = name used to ID an object // 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., // s1 points to a valid memory location or is NULL. E.g.,
// the following code will likely cause a segment fault: // the following code will likely cause a segment fault:
// char *s; // char *s;
// s = xstrcpy(s, "Some text"); // s = xstrcpy(&s, "Some text");
// while this would work correctly: // while this would work correctly:
// char *s = NULL; // char *s = NULL;
// s = xstrcpy(s, "Some text"); // s = xstrcpy(&s, "Some text");
//---------------------------------------------------------------- //----------------------------------------------------------------
{ {
size_t n1 = 0, n2 = 0; 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)); if (n2 > n1) *s1 = realloc(*s1, (n2 + 1) * sizeof(char));
// Copy the source string into the destination string // Copy the source string into the destination string
strncpy(*s1, s2, n2+1); if (*s1) strncpy(*s1, s2, n2+1);
return *s1; return *s1;
} }
@@ -1283,6 +1614,7 @@ double interp(int n, double x[], double y[], double xx)
int k, m; int k, m;
double dx, dy; double dx, dy;
if (n == 0) return 0.0;
m = n - 1; // Highest data index m = n - 1; // Highest data index
if (xx <= x[0]) return (y[0]); // xx off low end of curve if (xx <= x[0]) return (y[0]); // xx off low end of curve
for (k = 1; k <= m; k++) // Bracket xx on curve for (k = 1; k <= m; k++) // Bracket xx on curve

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: quality.c Module: quality.c
Description: implements EPANET's water quality engine Description: implements EPANET's water quality engine
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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 // Build nodal adjacency lists if they don't already exist
if (net->Adjlist == NULL) 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); errcode = buildadjlists(net);
if (errcode ) return errcode; if (errcode ) return errcode;
// Check for unconnected nodes
if (errcode = unlinked(pr)) return errcode;
} }
// Create a memory pool for water quality segments // Create a memory pool for water quality segments
@@ -175,6 +183,7 @@ int initqual(Project *pr)
qual->MassBalance.reacted = 0.0; qual->MassBalance.reacted = 0.0;
qual->MassBalance.final = 0.0; qual->MassBalance.final = 0.0;
qual->MassBalance.ratio = 0.0; qual->MassBalance.ratio = 0.0;
qual->MassBalance.segCount = 0;
return errcode; return errcode;
} }
@@ -402,6 +411,7 @@ int closequal(Project *pr)
FREE(qual->FlowDir); FREE(qual->FlowDir);
FREE(qual->SortedNodes); FREE(qual->SortedNodes);
} }
freeadjlists(&pr->network);
return errcode; return errcode;
} }

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: qualreact.c Module: qualreact.c
Description: computes water quality reactions within pipes and tanks Description: computes water quality reactions within pipes and tanks
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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. // 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]; q = (hyd->LinkStatus[k] <= CLOSED) ? 0.0 : hyd->LinkFlow[k];
a = PI * d * d / 4.0; // pipe area a = PI * d * d / 4.0; // pipe area
u = fabs(q) / a; // flow velocity 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 += vnet;
seg->v = MAX(0.0, seg->v); seg->v = MAX(0.0, seg->v);
tank->C = seg->c; 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; int k;
double vt, // Transferred volume double vt, // Transferred volume
vmz; // Full mixing zone volume vmz, // Full mixing zone volume
vsz; // Full stagnant zone volume
Pseg mixzone, // Mixing zone segment Pseg mixzone, // Mixing zone segment
stagzone; // Stagnant zone segment stagzone; // Stagnant zone segment
Stank *tank = &pr->network.Tank[i]; 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; if (mixzone == NULL || stagzone == NULL) return;
// Full mixing zone volume // Full mixing zone volume
vmz = tank->V1max; vmz = tank->V1frac * tank->Vmax;
// Tank is filling // Tank is filling
vt = 0.0; vt = 0.0;
@@ -557,17 +565,32 @@ void tankmix2(Project *pr, int i, double vin, double win, double vnet)
// Update segment volumes // Update segment volumes
if (vt > 0.0) if (vt > 0.0)
{
if (vnet > 0.0)
{ {
mixzone->v = vmz; mixzone->v = vmz;
if (vnet > 0.0) stagzone->v += vt; stagzone->v += vt;
else stagzone->v = MAX(0.0, ((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 else
{ {
mixzone->v += vnet; mixzone->v += vnet;
mixzone->v = MIN(mixzone->v, vmz); mixzone->v = MIN(mixzone->v, vmz);
mixzone->v = MAX(0.0, mixzone->v); 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 // 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); 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; vsum = 0.0;
wsum = 0.0; wsum = 0.0;
vout = vin - vnet;
while (vout > 0.0) while (vout > 0.0)
{ {
seg = qual->FirstSeg[k]; 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; if (vsum > 0.0) tank->C = wsum / vsum;
else if (qual->FirstSeg[k] == NULL) tank->C = 0.0; else if (qual->FirstSeg[k] == NULL) tank->C = 0.0;
else tank->C = qual->FirstSeg[k]->c; 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; k = net->Nlinks + i;
if (qual->LastSeg[k] == NULL || qual->FirstSeg[k] == NULL) return; if (qual->LastSeg[k] == NULL || qual->FirstSeg[k] == NULL) return;
// Find inflows & outflows // Find inflow concentration
if (vin > 0.0) cin = win / vin; if (vin > 0.0) cin = win / vin;
else cin = 0.0; else cin = 0.0;
@@ -687,6 +717,33 @@ void tankmix4(Project *pr, int i, double vin, double win, double vnet)
// Update reported tank quality // Update reported tank quality
tank->C = qual->LastSeg[k]->c; 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 // 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; vsum += vseg;
wsum += (seg->c) * vseg; wsum += (seg->c) * vseg;
// ... update remiaing volume to remove // ... update remaining volume to remove
vnet -= vseg; vnet -= vseg;
// ... if no more volume left in current segment // ... if no more volume left in current segment

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: qualroute.c Module: qualroute.c
Description: computes water quality transport over a single time step Description: computes water quality transport over a single time step
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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 // ... recycle the used up segment
seg->prev = qual->FreeSeg; seg->prev = qual->FreeSeg;
qual->FreeSeg = seg; qual->FreeSeg = seg;
qual->MassBalance.segCount--;
} }
// ... otherwise just reduce this segment's volume // ... otherwise just reduce this segment's volume
@@ -246,7 +247,7 @@ double findnodequal(Project *pr, int n, double volin,
return qual->NodeQual[n]; 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); else qual->SourceQual = findsourcequal(pr, n, volout, tstep);
if (qual->SourceQual == 0.0) return qual->NodeQual[n]; if (qual->SourceQual == 0.0) return qual->NodeQual[n];
@@ -609,10 +610,10 @@ void initsegs(Project *pr)
addseg(pr, k, v, c); addseg(pr, k, v, c);
// Create a 2nd segment for the 2-compartment tank model // 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 // ... 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; qual->FirstSeg[k]->v = v1;
// ... stagnant zone segment // ... 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->FirstSeg[k] == NULL) qual->FirstSeg[k] = seg;
if (qual->LastSeg[k] != NULL) qual->LastSeg[k]->prev = seg; if (qual->LastSeg[k] != NULL) qual->LastSeg[k]->prev = seg;
qual->LastSeg[k] = seg; qual->LastSeg[k] = seg;
qual->MassBalance.segCount++;
} }

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: report.c Module: report.c
Description: procedures for writing formatted text to a report file Description: procedures for writing formatted text to a report file
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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 writeresults(Project *);
static int disconnected(Project *); static int disconnected(Project *);
static void marknodes(Project *, int, int *, char *); 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 void writelimits(Project *, int, int);
static int checklimits(Report *, double *, int, int); static int checklimits(Report *, double *, int, int);
static char *fillstr(char *, char, int); static char *fillstr(char *, char, int);
@@ -67,7 +67,7 @@ int clearreport(Project *pr)
return 0; return 0;
} }
int copyreport(Project* pr, char *filename) int copyreport(Project* pr, const char *filename)
/* /*
**------------------------------------------------------ **------------------------------------------------------
** Input: filename = name of file to copy to ** 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); 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 == CHEM) sprintf(s, FMT30, qual->ChemName);
else if (qual->Qualflag == TRACE) sprintf(s, FMT31, net->Node[qual->TraceNode].ID); 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); writeline(pr, s);
if (qual->Qualflag != NONE && time->Dur > 0) if (qual->Qualflag != NONE && time->Dur > 0)
{ {
@@ -422,13 +422,51 @@ void writehydstat(Project *pr, int iter, double relerr)
writeline(pr, " "); 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) void writemassbalance(Project *pr)
/* /*
**------------------------------------------------------------- **-------------------------------------------------------------
** Input: none ** Input: none
** Output: none ** Output: none
** Purpose: writes water quality mass balance ratio ** Purpose: writes water quality mass balance ratio
** (Outflow + Final Storage) / Inflow + Initial Storage) ** (Outflow + Final Storage) / Inflow + Initial Storage
** to report file. ** to report file.
**------------------------------------------------------------- **-------------------------------------------------------------
*/ */
@@ -463,6 +501,8 @@ void writemassbalance(Project *pr)
writeline(pr, s1); writeline(pr, s1);
snprintf(s1, MAXMSG, "Mass Ratio: %-.5f", qual->MassBalance.ratio); snprintf(s1, MAXMSG, "Mass Ratio: %-.5f", qual->MassBalance.ratio);
writeline(pr, s1); writeline(pr, s1);
snprintf(s1, MAXMSG, "Total Segments: %d", qual->MassBalance.segCount);
writeline(pr, s1);
snprintf(s1, MAXMSG, "================================\n"); snprintf(s1, MAXMSG, "================================\n");
writeline(pr, s1); 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 ** Input: *s = text string
@@ -887,6 +927,12 @@ void writeline(Project *pr, char *s)
{ {
Report *rpt = &pr->report; 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->RptFile == NULL) return;
if (rpt->Rptflag) if (rpt->Rptflag)
{ {
@@ -1281,7 +1327,7 @@ int disconnected(Project *pr)
clocktime(rpt->Atime, time->Htime)); clocktime(rpt->Atime, time->Htime));
writeline(pr, pr->Msg); writeline(pr, pr->Msg);
} }
getclosedlink(pr, j, marked); getclosedlink(pr, j, marked, nodelist);
} }
// Free allocated memory // 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 ** Input: i = junction index
** marked[] = marks nodes already examined ** marked[] = marks nodes already examined
** stack[] = stack to hold nodes to examine
** Output: None. ** Output: None.
** Purpose: Determines if a closed link connects to junction i. ** 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; int j, k;
Padjlist alink; Padjlist alink;
int top = 0;
// Mark the current junction as examined and push onto stack
marked[i] = 2; marked[i] = 2;
for (alink = net->Adjlist[i]; alink != NULL; alink = alink->next) 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; k = alink->link;
j = alink->node; j = alink->node;
if (marked[j] == 2) continue;
if (marked[j] == 1) // 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); sprintf(pr->Msg, WARN03c, net->Link[k].ID);
writeline(pr, pr->Msg); writeline(pr, pr->Msg);
return; return;
} }
else getclosedlink(pr, j, marked);
// Mark the node as examined and push it onto the stack
marked[j] = 2;
stack[++top] = j;
alink = alink->next;
} }
}
} }
void writelimits(Project *pr, int j1, int j2) void writelimits(Project *pr, int j1, int j2)

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: rules.c Module: rules.c
Description: implements rule-based controls Description: implements rule-based controls
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 05/15/2019 Last Updated: 02/11/2025
****************************************************************************** ******************************************************************************
*/ */
@@ -32,10 +32,11 @@ enum Rulewords {
r_THEN, r_THEN,
r_ELSE, r_ELSE,
r_PRIORITY, r_PRIORITY,
r_DISABLED,
r_ERROR r_ERROR
}; };
char *Ruleword[] = {w_RULE, w_IF, w_AND, w_OR, 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 { enum Varwords {
r_DEMAND, r_DEMAND,
@@ -273,6 +274,16 @@ int ruledata(Project *pr)
err = newpriority(pr); err = newpriority(pr);
break; 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: default:
err = 201; 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. // Adjusts tank indices in rule premises.
//----------------------------------------------------------- //-----------------------------------------------------------
@@ -420,7 +431,8 @@ void adjusttankrules(Project *pr)
p = net->Rule[i].Premises; p = net->Rule[i].Premises;
while (p != NULL) 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; p = p->next;
} }
} }
@@ -527,6 +539,11 @@ int checkrules(Project *pr, long dt)
rules->ActionList = NULL; rules->ActionList = NULL;
for (i = 1; i <= net->Nrules; i++) 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 premises true, add THEN clauses to action list
if (evalpremises(pr, i) == TRUE) if (evalpremises(pr, i) == TRUE)
{ {
@@ -549,6 +566,126 @@ int checkrules(Project *pr, long dt)
return actionCount; 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) void newrule(Project *pr)
//---------------------------------------------------------- //----------------------------------------------------------
// Adds a new rule to the project // Adds a new rule to the project
@@ -564,6 +701,7 @@ void newrule(Project *pr)
rule->ThenActions = NULL; rule->ThenActions = NULL;
rule->ElseActions = NULL; rule->ElseActions = NULL;
rule->priority = 0.0; rule->priority = 0.0;
rule->isEnabled = TRUE;
pr->rules.LastPremise = NULL; pr->rules.LastPremise = NULL;
pr->rules.LastThenAction = NULL; pr->rules.LastThenAction = NULL;
pr->rules.LastElseAction = NULL; pr->rules.LastElseAction = NULL;

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: smatrix.c Module: smatrix.c
Description: solves a sparse set of linear equations Description: solves a sparse set of linear equations
Authors: see AUTHORS Authors: see AUTHORS
@@ -48,8 +48,8 @@ static int paralink(Network *, Smatrix *, int, int, int k);
static void xparalinks(Network *); static void xparalinks(Network *);
static int reordernodes(Project *); static int reordernodes(Project *);
static int factorize(Project *); static int factorize(Project *);
static int growlist(Project *, int); static int growlist(Project *, int, int *);
static int newlink(Project *, Padjlist); static int newlink(Project *, Padjlist, int *);
static int linked(Network *, int, int); static int linked(Network *, int, int);
static int addlink(Network *, int, int, int); static int addlink(Network *, int, int, int);
static int storesparse(Project *, int); static int storesparse(Project *, int);
@@ -443,8 +443,8 @@ int factorize(Project *pr)
Padjlist alink; Padjlist alink;
// Find degree of each junction node // Find degree of each junction node
sm->Degree = (int *)calloc(net->Nnodes + 1, sizeof(int)); int *degree = (int *)calloc(net->Nnodes + 1, sizeof(int));
if (sm->Degree == NULL) return 101; if (degree == NULL) return 101;
// NOTE: For purposes of node re-ordering, Tanks (nodes with // NOTE: For purposes of node re-ordering, Tanks (nodes with
// indexes above Njuncs) have zero degree of adjacency. // 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) 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 for (k = 1; k <= net->Njuncs; k++) // Examine each junction
{ {
knode = sm->Order[k]; // Re-ordered index knode = sm->Order[k]; // Re-ordered index
if (!growlist(pr, knode)) // Augment adjacency list if (!growlist(pr, knode, degree)) // Augment adjacency list
{ {
errcode = 101; errcode = 101;
break; break;
} }
sm->Degree[knode] = 0; // In-activate node degree[knode] = 0; // In-activate node
} }
free(sm->Degree); free(degree);
return errcode; return errcode;
} }
int growlist(Project *pr, int knode) int growlist(Project *pr, int knode, int *degree)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: knode = node index ** Input: knode = node index
@@ -496,10 +496,10 @@ int growlist(Project *pr, int knode)
for (alink = net->Adjlist[knode]; alink != NULL; alink = alink -> next) for (alink = net->Adjlist[knode]; alink != NULL; alink = alink -> next)
{ {
node = alink->node; // End node of connecting link 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 degree[node]--; // Reduce degree of adjacency
if (!newlink(pr, alink)) // Add to adjacency list if (!newlink(pr, alink, degree)) // Add to adjacency list
{ {
return 0; 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 ** 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, // If jnode still active, and inode not connected to jnode,
// then add a new connection between inode and 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 if (!linked(net, inode, jnode)) // inode not linked to jnode
{ {
@@ -545,8 +545,8 @@ int newlink(Project *pr, Padjlist alink)
// reflect the new connection. // reflect the new connection.
if (!addlink(net, inode, jnode, sm->Ncoeffs)) return 0; if (!addlink(net, inode, jnode, sm->Ncoeffs)) return 0;
if (!addlink(net, jnode, inode, sm->Ncoeffs)) return 0; if (!addlink(net, jnode, inode, sm->Ncoeffs)) return 0;
sm->Degree[inode]++; degree[inode]++;
sm->Degree[jnode]++; degree[jnode]++;
} }
} }
} }
@@ -651,7 +651,7 @@ int sortsparse(Smatrix *sm, int n)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: n = number of rows in solution matrix ** 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 ** Purpose: puts row indexes in ascending order in NZSUB
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
@@ -834,7 +834,7 @@ int linsolve(Smatrix *sm, int n)
} }
} // next j } // next j
// Foward substitution // Forward substitution
for (j = 1; j <= n; j++) for (j = 1; j <= n; j++)
{ {
bj = B[j]/Aii[j]; bj = B[j]/Aii[j];

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: text.h Module: text.h
Description: string constants used throughout EPANET Description: string constants used throughout EPANET
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 07/15/2019 Last Updated: 03/10/2025
****************************************************************************** ******************************************************************************
*/ */
@@ -40,6 +40,7 @@
#define w_FCV "FCV" #define w_FCV "FCV"
#define w_TCV "TCV" #define w_TCV "TCV"
#define w_GPV "GPV" #define w_GPV "GPV"
#define w_PCV "PCV"
#define w_OPEN "OPEN" #define w_OPEN "OPEN"
#define w_CLOSED "CLOSED" #define w_CLOSED "CLOSED"
@@ -51,9 +52,6 @@
#define w_IS "IS" #define w_IS "IS"
#define w_NOT "NOT" #define w_NOT "NOT"
#define w_ADD "ADD"
#define w_MULTIPLY "MULT"
#define w_LIMITING "LIMIT" #define w_LIMITING "LIMIT"
#define w_ORDER "ORDER" #define w_ORDER "ORDER"
#define w_GLOBAL "GLOB" #define w_GLOBAL "GLOB"
@@ -86,11 +84,14 @@
#define w_MLD "MLD" #define w_MLD "MLD"
#define w_CMH "CMH" #define w_CMH "CMH"
#define w_CMD "CMD" #define w_CMD "CMD"
#define w_CMS "CMS"
#define w_SI "SI" #define w_SI "SI"
#define w_PSI "PSI" #define w_PSI "PSI"
#define w_KPA "KPA" #define w_KPA "KPA"
#define w_METERS "METERS" #define w_METERS "METERS"
#define w_BAR "BAR"
#define w_FEET "FEET"
#define w_ELEV "ELEV" #define w_ELEV "ELEV"
#define w_DEMAND "DEMAND" #define w_DEMAND "DEMAND"
@@ -130,6 +131,8 @@
#define w_SEGMENTS "SEGM" #define w_SEGMENTS "SEGM"
#define w_TOLERANCE "TOLER" #define w_TOLERANCE "TOLER"
#define w_EMITTER "EMIT" #define w_EMITTER "EMIT"
#define w_BACKFLOW "BACK"
#define w_ALLOWED "ALLOW"
#define w_PRICE "PRICE" #define w_PRICE "PRICE"
#define w_DMNDCHARGE "DEMAN" #define w_DMNDCHARGE "DEMAN"
@@ -150,6 +153,9 @@
#define w_REQUIRED "REQ" #define w_REQUIRED "REQ"
#define w_EXPONENT "EXP" #define w_EXPONENT "EXP"
#define w_AREA "AREA"
#define w_EXPAN "EXPAN"
#define w_SECONDS "SEC" #define w_SECONDS "SEC"
#define w_MINUTES "MIN" #define w_MINUTES "MIN"
#define w_HOURS "HOU" #define w_HOURS "HOU"
@@ -192,6 +198,7 @@
#define w_THEN "THEN" #define w_THEN "THEN"
#define w_ELSE "ELSE" #define w_ELSE "ELSE"
#define w_PRIORITY "PRIO" #define w_PRIORITY "PRIO"
#define w_DISABLED "DISABLED"
// ------ Input File Section Names ------------------------ // ------ Input File Section Names ------------------------
@@ -207,6 +214,7 @@
#define s_DEMANDS "[DEMANDS]" #define s_DEMANDS "[DEMANDS]"
#define s_SOURCES "[SOURCES]" #define s_SOURCES "[SOURCES]"
#define s_EMITTERS "[EMITTERS]" #define s_EMITTERS "[EMITTERS]"
#define s_LEAKAGE "[LEAKAGE]"
#define s_PATTERNS "[PATTERNS]" #define s_PATTERNS "[PATTERNS]"
#define s_CURVES "[CURVES]" #define s_CURVES "[CURVES]"
#define s_QUALITY "[QUALITY]" #define s_QUALITY "[QUALITY]"
@@ -234,6 +242,7 @@
#define u_IMGD "Imgd" #define u_IMGD "Imgd"
#define u_LPS "L/s" #define u_LPS "L/s"
#define u_LPM "Lpm" #define u_LPM "Lpm"
#define u_CMS "m3/s"
#define u_CMH "m3/h" #define u_CMH "m3/h"
#define u_CMD "m3/d" #define u_CMD "m3/d"
#define u_MLD "ML/d" #define u_MLD "ML/d"
@@ -263,6 +272,8 @@
#define c_PUMP "PUMP" #define c_PUMP "PUMP"
#define c_EFFIC "EFFIC" #define c_EFFIC "EFFIC"
#define c_VOLUME "VOLUME" #define c_VOLUME "VOLUME"
#define c_VALVE "VALVE"
#define c_GENERIC "GENERIC"
//------- Text Phrases ------------------------------------ //------- Text Phrases ------------------------------------

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: types.h Module: types.h
Description: symbolic constants and data types used throughout EPANET Description: symbolic constants and data types used throughout EPANET
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 10/29/2019 Last Updated: 04/19/2025
****************************************************************************** ******************************************************************************
*/ */
@@ -31,7 +31,7 @@ typedef int INT4;
Various constants Various constants
---------------------------------------------- ----------------------------------------------
*/ */
#define CODEVERSION 20200 #define CODEVERSION 20300
#define MAGICNUMBER 516114521 #define MAGICNUMBER 516114521
#define ENGINE_VERSION 201 // Used for binary hydraulics file #define ENGINE_VERSION 201 // Used for binary hydraulics file
#define EOFMARK 0x1A // Use 0x04 for UNIX systems #define EOFMARK 0x1A // Use 0x04 for UNIX systems
@@ -48,6 +48,9 @@ typedef int INT4;
#define BIG 1.E10 #define BIG 1.E10
#define TINY 1.E-6 #define TINY 1.E-6
#define MISSING -1.E10 // Missing value indicator #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 #define DIFFUS 1.3E-8 // Diffusivity of chlorine
// @ 20 deg C (sq ft/sec) // @ 20 deg C (sq ft/sec)
#define VISCOS 1.1E-5 // Kinematic viscosity of water #define VISCOS 1.1E-5 // Kinematic viscosity of water
@@ -71,6 +74,7 @@ typedef int INT4;
#define IMGDperCFS 0.5382 #define IMGDperCFS 0.5382
#define LPSperCFS 28.317 #define LPSperCFS 28.317
#define LPMperCFS 1699.0 #define LPMperCFS 1699.0
#define CMSperCFS 0.028317
#define CMHperCFS 101.94 #define CMHperCFS 101.94
#define CMDperCFS 2446.6 #define CMDperCFS 2446.6
#define MLDperCFS 2.4466 #define MLDperCFS 2.4466
@@ -79,6 +83,7 @@ typedef int INT4;
#define MperFT 0.3048 #define MperFT 0.3048
#define PSIperFT 0.4333 #define PSIperFT 0.4333
#define KPAperPSI 6.895 #define KPAperPSI 6.895
#define BARperPSI 0.068948
#define KWperHP 0.7457 #define KWperHP 0.7457
#define SECperDAY 86400 #define SECperDAY 86400
@@ -145,7 +150,8 @@ typedef enum {
PBV, // pressure breaker valve PBV, // pressure breaker valve
FCV, // flow control valve FCV, // flow control valve
TCV, // throttle control valve TCV, // throttle control valve
GPV // general purpose valve GPV, // general purpose valve
PCV // positional control valve
} LinkType; } LinkType;
typedef enum { typedef enum {
@@ -166,7 +172,8 @@ typedef enum {
PUMP_CURVE, // pump curve PUMP_CURVE, // pump curve
EFFIC_CURVE, // efficiency curve EFFIC_CURVE, // efficiency curve
HLOSS_CURVE, // head loss curve HLOSS_CURVE, // head loss curve
GENERIC_CURVE // generic curve GENERIC_CURVE, // generic curve
VALVE_CURVE // positional valve loss curve
} CurveType; } CurveType;
typedef enum { typedef enum {
@@ -225,13 +232,17 @@ typedef enum {
LPM, // liters per minute LPM, // liters per minute
MLD, // megaliters per day MLD, // megaliters per day
CMH, // cubic meters per hour CMH, // cubic meters per hour
CMD // cubic meters per day CMD, // cubic meters per day
CMS // cubic meters per second
} FlowUnitsType; } FlowUnitsType;
typedef enum { typedef enum {
PSI, // pounds per square inch PSI, // pounds per square inch
KPA, // kiloPascals KPA, // kiloPascals
METERS // meters METERS, // meters
BAR, // bar
FEET, // feet
DEFAULTUNIT // default based on unit system (SI or US)
} PressureUnitsType; } PressureUnitsType;
typedef enum { typedef enum {
@@ -287,7 +298,7 @@ typedef enum {
_VALVES, _CONTROLS, _RULES, _DEMANDS, _SOURCES, _EMITTERS, _VALVES, _CONTROLS, _RULES, _DEMANDS, _SOURCES, _EMITTERS,
_PATTERNS, _CURVES, _QUALITY, _STATUS, _ROUGHNESS, _ENERGY, _PATTERNS, _CURVES, _QUALITY, _STATUS, _ROUGHNESS, _ENERGY,
_REACTIONS, _MIXING, _REPORT, _TIMES, _OPTIONS, _REACTIONS, _MIXING, _REPORT, _TIMES, _OPTIONS,
_COORDS, _VERTICES, _LABELS, _BACKDROP, _TAGS, _END _COORDS, _VERTICES, _LABELS, _BACKDROP, _TAGS, _LEAKAGE, _END
} SectionType; } SectionType;
typedef enum { typedef enum {
@@ -355,6 +366,8 @@ typedef struct // Energy Usage Object
double KwHrs; // total kw-hrs consumed double KwHrs; // total kw-hrs consumed
double MaxKwatts; // max. kw consumed double MaxKwatts; // max. kw consumed
double TotalCost; // total pumping cost double TotalCost; // total pumping cost
double CurrentPower; // current pump power (kw)
double CurrentEffic; // current pump efficiency
} Senergy; } Senergy;
struct Ssource // Water Quality Source Object struct Ssource // Water Quality Source Object
@@ -389,6 +402,7 @@ typedef struct // Node Object
int ResultIndex; // saved result index int ResultIndex; // saved result index
NodeType Type; // node type NodeType Type; // node type
char *Comment; // node comment char *Comment; // node comment
char *Tag; // optional category tag
} Snode; } Snode;
typedef struct // Link Object typedef struct // Link Object
@@ -398,18 +412,22 @@ typedef struct // Link Object
int N2; // end node index int N2; // end node index
double Diam; // diameter double Diam; // diameter
double Len; // length double Len; // length
double Kc; // roughness double Kc; // pipe roughness, pump speed, valve setting
double Km; // minor loss coeff. double Km; // minor loss coeff.
double Kb; // bulk react. coeff. double Kb; // bulk react. coeff.
double Kw; // wall react. coef. double Kw; // wall react. coef.
double R; // flow resistance double R; // flow resistance
double Rc; // reaction coeff. 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 LinkType Type; // link type
StatusType Status; // initial status StatusType InitStatus; // initial status
double InitSetting; // initial setting
Pvertices Vertices; // internal vertex coordinates Pvertices Vertices; // internal vertex coordinates
int Rpt; // reporting flag int Rpt; // reporting flag
int ResultIndex; // saved result index int ResultIndex; // saved result index
char *Comment; // link comment char *Comment; // link comment
char *Tag; // optional category tag
} Slink; } Slink;
typedef struct // Tank Object typedef struct // Tank Object
@@ -428,7 +446,7 @@ typedef struct // Tank Object
int Pat; // fixed grade time pattern int Pat; // fixed grade time pattern
int Vcurve; // volume v. elev. curve index int Vcurve; // volume v. elev. curve index
MixType MixModel; // type of mixing model MixType MixModel; // type of mixing model
double V1max; // mixing compartment size double V1frac; // mixing compartment fraction
int CanOverflow; // tank can overflow or not int CanOverflow; // tank can overflow or not
} Stank; } Stank;
@@ -453,6 +471,7 @@ typedef struct // Pump Object
typedef struct // Valve Object typedef struct // Valve Object
{ {
int Link; // link index of valve int Link; // link index of valve
int Curve; // positional loss coeff. curve
} Svalve; } Svalve;
typedef struct // Control Statement typedef struct // Control Statement
@@ -464,6 +483,7 @@ typedef struct // Control Statement
double Setting; // new link setting double Setting; // new link setting
StatusType Status; // new link status StatusType Status; // new link status
ControlType Type; // control type ControlType Type; // control type
int isEnabled; // control enabled?
} Scontrol; } Scontrol;
typedef struct // Field Object of Report Table typedef struct // Field Object of Report Table
@@ -515,6 +535,7 @@ typedef struct // Control Rule Structure
{ {
char label[MAXID+1]; // rule label char label[MAXID+1]; // rule label
double priority; // priority level double priority; // priority level
int isEnabled; // is the rule enabled?
Spremise *Premises; // list of premises Spremise *Premises; // list of premises
Saction *ThenActions; // list of THEN actions Saction *ThenActions; // list of THEN actions
Saction *ElseActions; // list of ELSE actions Saction *ElseActions; // list of ELSE actions
@@ -535,8 +556,29 @@ typedef struct // Mass Balance Components
double reacted; // mass reacted in system double reacted; // mass reacted in system
double final; // final mass in system double final; // final mass in system
double ratio; // ratio of mass added to mass lost double ratio; // ratio of mass added to mass lost
int segCount; // total number of pipe segments used
} SmassBalance; } 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 Wrapper Data Structures
@@ -571,8 +613,7 @@ typedef struct {
ErrTok, // Index of error-producing token ErrTok, // Index of error-producing token
Unitsflag, // Unit system flag Unitsflag, // Unit system flag
Flowflag, // Flow units flag Flowflag, // Flow units flag
Pressflag, // Pressure units flag Pressflag; // Pressure units flag
DefPat; // Default demand pattern
Spattern *PrevPat; // Previous pattern processed Spattern *PrevPat; // Previous pattern processed
Scurve *PrevCurve; // Previous curve processed Scurve *PrevCurve; // Previous curve processed
@@ -630,6 +671,9 @@ typedef struct {
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; } Report;
// Output File Wrapper // Output File Wrapper
@@ -688,7 +732,6 @@ typedef struct {
*XLNZ, // Start position of each column in NZSUB *XLNZ, // Start position of each column in NZSUB
*NZSUB, // Row index of each coeff. in each column *NZSUB, // Row index of each coeff. in each column
*LNZ, // Position of each coeff. in Aij array *LNZ, // Position of each coeff. in Aij array
*Degree, // Number of links adjacent to each node
*link, // Array used by linear eqn. solver *link, // Array used by linear eqn. solver
*first; // Array used by linear eqn. solver *first; // Array used by linear eqn. solver
@@ -699,9 +742,11 @@ typedef struct {
double double
*NodeHead, // Node hydraulic heads *NodeHead, // Node hydraulic heads
*NodeDemand, // Node demand + emitter flows *NodeDemand, // Node total demand (consumer + emitter + leakage)
*DemandFlow, // Work array of demand flows *FullDemand, // Required consumer demand
*EmitterFlow, // Emitter outflows *DemandFlow, // Demand flow from nodes
*EmitterFlow, // Emitter flow from nodes
*LeakageFlow, // Leakage flow from nodes
*LinkFlow, // Link flows *LinkFlow, // Link flows
*LinkSetting, // Link settings *LinkSetting, // Link settings
Htol, // Hydraulic head tolerance Htol, // Hydraulic head tolerance
@@ -728,15 +773,18 @@ typedef struct {
MaxHeadError, // Max. error for link head loss MaxHeadError, // Max. error for link head loss
MaxFlowChange, // Max. change in link flow MaxFlowChange, // Max. change in link flow
DemandReduction, // % demand reduction at pressure deficient nodes DemandReduction, // % demand reduction at pressure deficient nodes
LeakageLoss, // % system leakage loss
RelaxFactor, // Relaxation factor for flow updating RelaxFactor, // Relaxation factor for flow updating
*P, // Inverse of head loss derivatives *P, // Inverse of head loss derivatives
*Y, // Flow correction factors *Y, // Flow correction factors
*Xflow; // Inflow - outflow at each node *Xflow; // Inflow - outflow at each node
int int
DefPat, // Default demand pattern
Epat, // Energy cost time pattern Epat, // Energy cost time pattern
DemandModel, // Fixed or pressure dependent DemandModel, // Fixed or pressure dependent
Formflag, // Head loss formula flag Formflag, // Head loss formula flag
EmitBackFlag, // Emitter backflow flag
Iterations, // Number of hydraulic trials taken Iterations, // Number of hydraulic trials taken
MaxIter, // Max. hydraulic trials allowed MaxIter, // Max. hydraulic trials allowed
ExtraIter, // Extra hydraulic trials ExtraIter, // Extra hydraulic trials
@@ -744,12 +792,18 @@ typedef struct {
MaxCheck, // Hydraulic trials limit on status checks MaxCheck, // Hydraulic trials limit on status checks
OpenHflag, // Hydraulic system opened flag OpenHflag, // Hydraulic system opened flag
Haltflag, // Flag to halt simulation 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 StatusType
*LinkStatus, // Link status *LinkStatus, // Link status
*OldStatus; // Previous link/tank status *OldStatus; // Previous link/tank status
SflowBalance
FlowBalance; // Flow balance components
Smatrix smatrix; // Sparse matrix storage Smatrix smatrix; // Sparse matrix storage
} Hydraul; } Hydraul;

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: util/cstr_helper.c Module: util/cstr_helper.c
Description: Provides C string helper functions Description: Provides C string helper functions
Authors: see AUTHORS Authors: see AUTHORS

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: util/cstr_helper.h Module: util/cstr_helper.h
Description: Provides C string helper functions Description: Provides C string helper functions
Authors: see AUTHORS Authors: see AUTHORS

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: util/errormanager.c Module: util/errormanager.c
Description: Provides a simple interface for managing errors Description: Provides a simple interface for managing errors
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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_t *error_handle;
error_handle = (error_handle_t*)calloc(1, sizeof(error_handle_t)); 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; error_handle->p_msg_lookup = p_error_message;

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: util/errormanager.h Module: util/errormanager.h
Description: Provides a simple interface for managing errors Description: Provides a simple interface for managing errors
Authors: see AUTHORS Authors: see AUTHORS

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: util/filemanager.c Module: util/filemanager.c
Description: Provides a simple interface for managing files Description: Provides a simple interface for managing files
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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_t *file_handle;
file_handle = (file_handle_t *)calloc(1, sizeof(file_handle_t)); file_handle = (file_handle_t *)calloc(1, sizeof(file_handle_t));
if (file_handle == NULL) return NULL;
file_handle->filename = NULL; file_handle->filename = NULL;
file_handle->file = NULL; file_handle->file = NULL;

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: util/filemanager.h Module: util/filemanager.h
Description: Provides a simple interface for managing files Description: Provides a simple interface for managing files
Authors: see AUTHORS Authors: see AUTHORS

408
src/validate.c Normal file
View 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);
}
}

View File

@@ -39,6 +39,9 @@ set(toolkit_test_srcs
test_control.cpp test_control.cpp
test_overflow.cpp test_overflow.cpp
test_pda.cpp test_pda.cpp
test_valve.cpp
test_units.cpp
test_leakage.cpp
) )
add_executable(test_toolkit ${toolkit_test_srcs}) add_executable(test_toolkit ${toolkit_test_srcs})

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_analysis.cpp Module: test_analysis.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS
@@ -23,11 +23,11 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose)
{ {
int i; int i;
std::vector<double> test(23); std::vector<double> test(26);
double *array = test.data(); 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, 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); error = EN_solveH(ph);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
@@ -36,7 +36,7 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose)
BOOST_REQUIRE(error == 0); 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++); error = EN_getoption(ph, i, array++);
BOOST_REQUIRE(error == 0); 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()); BOOST_CHECK_EQUAL_COLLECTIONS(ref.begin(), ref.end(), test.begin(), test.end());
double temp; double temp;
error = EN_getoption(ph, 25, &temp); error = EN_getoption(ph, 27, &temp);
BOOST_CHECK(error == 251); BOOST_CHECK(error == 251);
} }

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_control.cpp Module: test_control.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_curve.cpp Module: test_curve.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_demand.cpp Module: test_demand.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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; EN_Project ph = NULL;
error = EN_createproject(&ph); error = EN_createproject(&ph);
BOOST_REQUIRE(error == 0);
error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT); error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT);
BOOST_REQUIRE(error == 0);
error = EN_getnodeindex(ph, (char *)"12", &Nindex); error = EN_getnodeindex(ph, (char *)"12", &Nindex);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
@@ -122,5 +124,31 @@ BOOST_FIXTURE_TEST_CASE(test_adddemand, FixtureSingleNode)
BOOST_CHECK(nD1 - nD2 == 1); 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() BOOST_AUTO_TEST_SUITE_END()

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_hydraulics.cpp Module: test_hydraulics.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS

93
tests/test_leakage.cpp Normal file
View 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()

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_link.cpp Module: test_link.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_net_builder.cpp Module: test_net_builder.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_node.cpp Module: test_node.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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(); double *value = test.data();
error = EN_getnodeindex(ph, (char *)"11", &index); 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 // Ranged for loop iterates over property set
@@ -255,17 +255,22 @@ BOOST_FIXTURE_TEST_CASE(test_node_comments, FixtureOpenClose)
{ {
int index; int index;
char comment[EN_MAXMSG + 1]; char comment[EN_MAXMSG + 1];
char tag[EN_MAXMSG + 1];
// Add comments to selected objects // Add comments to selected objects
error = EN_getnodeindex(ph, (char *)"11", &index); error = EN_getnodeindex(ph, (char *)"11", &index);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
error = EN_setcomment(ph, EN_NODE, index, (char *)"J11"); error = EN_setcomment(ph, EN_NODE, index, (char *)"J11");
BOOST_REQUIRE(error == 0); 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); error = EN_getnodeindex(ph, (char *)"23", &index);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
error = EN_setcomment(ph, EN_NODE, index, (char *)"Junc23"); error = EN_setcomment(ph, EN_NODE, index, (char *)"Junc23");
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
error = EN_settag(ph, EN_NODE, index, (char *)"Junc23_Tag");
BOOST_REQUIRE(error == 0);
// Check comments // Check comments
error = EN_getnodeindex(ph, (char *)"11", &index); 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); error = EN_getcomment(ph, EN_NODE, index, comment);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
BOOST_CHECK(check_string(comment, (char *)"J11")); 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); error = EN_getnodeindex(ph, (char *)"23", &index);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
error = EN_getcomment(ph, EN_NODE, index, comment); error = EN_getcomment(ph, EN_NODE, index, comment);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
BOOST_CHECK(check_string(comment, (char *)"Junc23")); 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) BOOST_FIXTURE_TEST_CASE(test_replace_comment, FixtureOpenClose)
{ {
int index; int index;
char comment[EN_MAXMSG + 1]; char comment[EN_MAXMSG + 1];
char tag[EN_MAXMSG + 1];
// Replace short comment with longer one and vice versa // Replace short comment with longer one and vice versa
error = EN_getnodeindex(ph, (char *)"11", &index); error = EN_getnodeindex(ph, (char *)"11", &index);
@@ -295,11 +307,23 @@ BOOST_FIXTURE_TEST_CASE(test_replace_comment, FixtureOpenClose)
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
BOOST_CHECK(check_string(comment, (char *)"Junction11")); 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"); error = EN_setcomment(ph, EN_NODE, index, (char *)"J11");
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
error = EN_getcomment(ph, EN_NODE, index, comment); error = EN_getcomment(ph, EN_NODE, index, comment);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
BOOST_CHECK(check_string(comment, (char *)"J11")); 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) BOOST_FIXTURE_TEST_CASE(test_save_comment, FixtureOpenClose)
@@ -311,11 +335,15 @@ BOOST_FIXTURE_TEST_CASE(test_save_comment, FixtureOpenClose)
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
error = EN_setcomment(ph, EN_NODE, index, (char *)"J11"); error = EN_setcomment(ph, EN_NODE, index, (char *)"J11");
BOOST_REQUIRE(error == 0); 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); error = EN_getnodeindex(ph, (char *)"23", &index);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
error = EN_setcomment(ph, EN_NODE, index, (char *)"Junc23"); error = EN_setcomment(ph, EN_NODE, index, (char *)"Junc23");
BOOST_REQUIRE(error == 0); 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); error = EN_saveinpfile(ph, DATA_PATH_TMP);
BOOST_REQUIRE(error == 0); 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; int error, index;
char comment[EN_MAXMSG + 1]; char comment[EN_MAXMSG + 1];
char tag[EN_MAXMSG + 1];
// Create & load a project // Create & load a project
EN_Project ph = NULL; 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); error = EN_getcomment(ph, EN_NODE, index, comment);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
BOOST_CHECK(check_string(comment, (char *)"J11")); 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); error = EN_getnodeindex(ph, (char *)"23", &index);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
error = EN_getcomment(ph, EN_NODE, index, comment); error = EN_getcomment(ph, EN_NODE, index, comment);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
BOOST_CHECK(check_string(comment, (char *)"Junc23")); 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 // Close project
EN_close(ph); EN_close(ph);

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_overflow.cpp Module: test_overflow.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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; EN_Project ph = NULL;
error = EN_createproject(&ph); error = EN_createproject(&ph);
BOOST_REQUIRE(error == 0);
error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, ""); error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, "");
BOOST_REQUIRE(error == 0);
// Get index of the tank and its inlet/outlet pipe // Get index of the tank and its inlet/outlet pipe
error = EN_getnodeindex(ph, (char *)"2", &Nindex); error = EN_getnodeindex(ph, (char *)"2", &Nindex);

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_pattern.cpp Module: test_pattern.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS

View File

@@ -1,13 +1,13 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_pda.cpp Module: test_pda.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE 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; EN_Project ph = NULL;
error = EN_createproject(&ph); error = EN_createproject(&ph);
BOOST_REQUIRE(error == 0);
error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, ""); error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, "");
BOOST_REQUIRE(error == 0);
// Set Demand Multiplier to 10 to cause negative pressures // Set Demand Multiplier to 10 to cause negative pressures
error = EN_setoption(ph, EN_DEMANDMULT, 10); error = EN_setoption(ph, EN_DEMANDMULT, 10);

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_project.cpp Module: test_project.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS
@@ -118,7 +118,6 @@ BOOST_AUTO_TEST_CASE(test_run)
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE(test_proj_fixture) BOOST_AUTO_TEST_SUITE(test_proj_fixture)
BOOST_FIXTURE_TEST_CASE(test_title, FixtureOpenClose) BOOST_FIXTURE_TEST_CASE(test_title, FixtureOpenClose)

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_quality.cpp Module: test_quality.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_reent.cpp Module: test_reent.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_report.cpp Module: test_report.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_toolkit.cpp Module: test_toolkit.cpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS

View File

@@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
Project: OWA EPANET Project: OWA EPANET
Version: 2.2 Version: 2.3
Module: test_toolkit.hpp Module: test_toolkit.hpp
Description: Tests EPANET toolkit api functions Description: Tests EPANET toolkit api functions
Authors: see AUTHORS Authors: see AUTHORS

460
tests/test_units.cpp Normal file
View 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
View 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