Merge branch 'dev' into 683-request-better-logging-functionality

This commit is contained in:
Sam Hatchett
2023-01-19 09:01:43 -05:00
committed by GitHub
26 changed files with 437 additions and 42 deletions

View File

@@ -1,6 +1,10 @@
name: C/C++ CI name: linux
on: [push] on:
push:
pull_request:
schedule:
- cron: '0 0 1 * *'
jobs: jobs:
build: build:
@@ -17,3 +21,7 @@ jobs:
- name: make - name: make
working-directory: ./buildproducts working-directory: ./buildproducts
run: make run: make
- uses: actions/upload-artifact@v2
with:
name: libepanet-output
path: /home/runner/work/EPANET/EPANET/buildproducts/

26
.github/workflows/win32.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: epanet2-win32
on:
push:
pull_request:
schedule:
- cron: '0 0 1 * *'
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: setup_build_dir
run: mkdir buildproducts
- name: cmake
working-directory: ./buildproducts
run: cmake .. -A Win32 && cmake --build . --config Release
- uses: actions/upload-artifact@v2
with:
name: epanet2-win32
path: D:\a\EPANET\EPANET\buildproducts\bin\Release\

26
.github/workflows/win64.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: epanet2-win64
on:
push:
pull_request:
schedule:
- cron: '0 0 1 * *'
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: setup_build_dir
run: mkdir buildproducts
- name: cmake
working-directory: ./buildproducts
run: cmake .. -A x64 && cmake --build . --config Release
- uses: actions/upload-artifact@v2
with:
name: epanet2-win64
path: D:\a\EPANET\EPANET\buildproducts\bin\Release\

View File

@@ -3,10 +3,13 @@ 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)
[![codecov](https://codecov.io/gh/OpenWaterAnalytics/EPANET/branch/master/graph/badge.svg)](https://codecov.io/gh/OpenWaterAnalytics/EPANET) [![codecov](https://codecov.io/gh/OpenWaterAnalytics/EPANET/branch/master/graph/badge.svg)](https://codecov.io/gh/OpenWaterAnalytics/EPANET)
[![linux](https://github.com/OpenWaterAnalytics/EPANET/actions/workflows/ccpp.yml/badge.svg)](https://github.com/OpenWaterAnalytics/EPANET/actions/workflows/ccpp.yml)
[![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
**EPANET** is an industry-standard program for modeling the hydraulic and water quality behavior of water distribution system pipe networks. The EPANET Programmer's Toolkit is a library of functions (or API) written in C that allow programmers to customize the use of EPANET's solution engine for their own applications. Both EPANET and its toolkit were originally developed by the U.S. Environmental Protection Agency (USEPA). If you are interested in using/extending the EPANET engine and its API for academic, personal, or commercial use, then you've come to the right place. [Read more about EPANET on Wikipedia](https://en.wikipedia.org/wiki/EPANET). (Please note that this project covers only the EPANET hydraulic and water quality solver engine, not the graphical user interface.) **EPANET** is an industry-standard program for modeling the hydraulic and water quality behavior of water distribution system pipe networks. The EPANET Programmer's Toolkit is a library of functions (or API) written in C that allow programmers to customize the use of EPANET's solution engine for their own applications. Both EPANET and its toolkit were originally developed by the U.S. Environmental Protection Agency (USEPA). If you are interested in using/extending the EPANET engine and its API for academic, personal, or commercial use, then you've come to the right place. [Read more about EPANET on Wikipedia](https://en.wikipedia.org/wiki/EPANET). (Please note that this project covers only the EPANET hydraulic and water quality solver engine, not the graphical user interface.)

View File

@@ -22,6 +22,9 @@ This document describes the changes and updates that have been made in version 2
- changing the absolute tolerance used to compare the closeness of test results to benchmark values from 0 to 0.0001 - 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 "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. - dropping the check for identical status report content since it prevents accepting code changes that produce more accurate solutions in fewer iterations.
- 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.
- A new type of valve, a Positional Control Valve (PCV), was added that uses a valve characteristic curve to relate its loss coefficient to its fraction open setting.

45
conanfile.py Normal file
View File

@@ -0,0 +1,45 @@
from conans 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):
self.copy("lib/libepanet2.dylib", "lib", keep_path=False)
self.copy("lib/libepanet-output.dylib", "lib", keep_path=False)
self.copy("*.h", "include", "include", keep_path=False)
self.copy("types.h", "include", "src", keep_path=False)
self.copy("hash.h", "include", "src", keep_path=False)
def package_info(self):
self.cpp_info.libdirs = ["lib"]
self.cpp_info.libs = ["epanet2", "epanet-output"]
self.cpp_info.includedirs = ["include"]

View File

@@ -92,9 +92,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:__
``` ```
@@ -1028,7 +1029,8 @@ 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:
@@ -1038,9 +1040,14 @@ __Remarks:__
|<B>PSV</B> (pressure sustaining valve) | Pressure, psi (m) | |<B>PSV</B> (pressure sustaining valve) | Pressure, psi (m) |
|<B>PBV</B> (pressure breaker valve) | Pressure, psi (m) | |<B>PBV</B> (pressure breaker valve) | Pressure, psi (m) |
|<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) | Fraction open |
|<B>GPV</B> (general purpose valve) | ID of head loss curve | |<B>GPV</B> (general purpose valve) | ID of head loss curve |
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 fraction of fully open flow to the fraction 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.
*/ */
/** /**

View File

@@ -73,6 +73,9 @@ namespace EpanetCSharpLibrary
public const int EN_PUMP_ECURVE = 20; public const int EN_PUMP_ECURVE = 20;
public const int EN_PUMP_ECOST = 21; public const int EN_PUMP_ECOST = 21;
public const int EN_PUMP_EPAT = 22; 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_DURATION = 0; //Time parameters public const int EN_DURATION = 0; //Time parameters
public const int EN_HYDSTEP = 1; public const int EN_HYDSTEP = 1;
@@ -126,6 +129,7 @@ namespace EpanetCSharpLibrary
public const int EN_FCV = 6; public const int EN_FCV = 6;
public const int EN_TCV = 7; public const int EN_TCV = 7;
public const int EN_GPV = 8; 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_NONE = 0; //Quality analysis types
public const int EN_CHEM = 1; public const int EN_CHEM = 1;
@@ -209,6 +213,7 @@ namespace EpanetCSharpLibrary
public const int EN_EFFIC_CURVE = 2; //Efficiency curve public const int EN_EFFIC_CURVE = 2; //Efficiency curve
public const int EN_HLOSS_CURVE = 3; //Head loss curve public const int EN_HLOSS_CURVE = 3; //Head loss curve
public const int EN_GENERIC_CURVE = 4; //Generic 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_UNCONDITIONAL = 0; //Unconditional object deletion
public const int EN_CONDITIONAL = 1; //Conditional object deletion public const int EN_CONDITIONAL = 1; //Conditional object deletion

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 02/01/2020 'Last updated on 07/28/2022
' 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
@@ -63,6 +63,7 @@ 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_LINK_INCONTROL = 23
Public Const EN_GPV_CURVE = 24 Public Const EN_GPV_CURVE = 24
Public Const EN_PCV_CURVE= 25
Public Const EN_DURATION = 0 ' Time parameters Public Const EN_DURATION = 0 ' Time parameters
Public Const EN_HYDSTEP = 1 Public Const EN_HYDSTEP = 1
@@ -117,6 +118,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_CLOSED = 0 ' Link status types Public Const EN_CLOSED = 0 ' Link status types
Public Const EN_OPEN = 1 Public Const EN_OPEN = 1
@@ -209,6 +211,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

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 02/01/2020} {Last updated on 07/28/2022}
interface interface
@@ -69,6 +69,7 @@ const
EN_PUMP_EPAT = 22; EN_PUMP_EPAT = 22;
EN_LINK_INCONTROL = 23; EN_LINK_INCONTROL = 23;
EN_GPV_CURVE = 24; EN_GPV_CURVE = 24;
EN_PCV_CURVE = 25;
EN_DURATION = 0; { Time parameters } EN_DURATION = 0; { Time parameters }
EN_HYDSTEP = 1; EN_HYDSTEP = 1;
@@ -123,6 +124,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;
@@ -214,7 +216,8 @@ const
EN_PUMP_CURVE = 1; EN_PUMP_CURVE = 1;
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;

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 02/01/2020 'Last updated on 07/28/2022
Imports System.Runtime.InteropServices Imports System.Runtime.InteropServices
Imports System.Text Imports System.Text
@@ -67,6 +67,7 @@ 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_LINK_INCONTROL = 23
Public Const EN_GPV_CURVE = 24 Public Const EN_GPV_CURVE = 24
Public Const EN_PCV_CURVE = 25
Public Const EN_DURATION = 0 ' Time parameters Public Const EN_DURATION = 0 ' Time parameters
Public Const EN_HYDSTEP = 1 Public Const EN_HYDSTEP = 1
@@ -120,6 +121,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
@@ -203,6 +205,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

View File

@@ -9,7 +9,7 @@
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 02/01/2020 Last Updated: 08/13/2022
****************************************************************************** ******************************************************************************
*/ */
@@ -97,7 +97,8 @@ typedef enum {
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_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_GPV_CURVE = 24, //!< GPV head loss v. flow curve index
EN_PCV_CURVE = 25 //!< PCV loss coeff. curve index
} EN_LinkProperty; } EN_LinkProperty;
/// Time parameters /// Time parameters
@@ -191,7 +192,8 @@ 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
@@ -397,7 +399,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 //!< Valve loss coeff. v. frac. open
} EN_CurveType; } EN_CurveType;
/// Deletion action codes /// Deletion action codes

View File

@@ -7,7 +7,7 @@
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: 08/13/2022
****************************************************************************** ******************************************************************************
*/ */
@@ -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,

View File

@@ -7,7 +7,7 @@
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 11/08/2020 Last Updated: 08/13/2022
****************************************************************************** ******************************************************************************
*/ */
@@ -3162,7 +3162,7 @@ int DLLEXPORT EN_addlink(EN_Project p, char *id, int linkType,
if (EN_getlinkindex(p, id, &i) == 0) return 215; if (EN_getlinkindex(p, id, &i) == 0) return 215;
// Check for valid link type // Check for valid link type
if (linkType < CVPIPE || linkType > GPV) return 251; if (linkType < CVPIPE || linkType > PCV) return 251;
// Lookup the link's from and to nodes // Lookup the link's from and to nodes
n1 = hashtable_find(net->NodeHashTable, fromNode); n1 = hashtable_find(net->NodeHashTable, fromNode);
@@ -3222,6 +3222,7 @@ int DLLEXPORT EN_addlink(EN_Project p, char *id, int linkType,
size = (net->Nvalves + 1) * sizeof(Svalve); size = (net->Nvalves + 1) * sizeof(Svalve);
net->Valve = (Svalve *)realloc(net->Valve, size); net->Valve = (Svalve *)realloc(net->Valve, size);
net->Valve[net->Nvalves].Link = n; net->Valve[net->Nvalves].Link = n;
net->Valve[net->Nvalves].Curve = 0;
} }
link->Type = linkType; link->Type = linkType;
@@ -3481,7 +3482,7 @@ int DLLEXPORT EN_setlinktype(EN_Project p, int *index, int linkType, int actionC
if (p->hydraul.OpenHflag || p->quality.OpenQflag) return 262; if (p->hydraul.OpenHflag || p->quality.OpenQflag) return 262;
// Check for valid input parameters // Check for valid input parameters
if (linkType < 0 || linkType > GPV || actionCode < EN_UNCONDITIONAL || if (linkType < 0 || linkType > PCV || actionCode < EN_UNCONDITIONAL ||
actionCode > EN_CONDITIONAL) actionCode > EN_CONDITIONAL)
{ {
return 251; return 251;
@@ -3806,7 +3807,14 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val
v = (double)Pump[findpump(&p->network, index)].Epat; v = (double)Pump[findpump(&p->network, index)].Epat;
} }
break; break;
case EN_PCV_CURVE:
if (Link[index].Type == PCV)
{
v = net->Valve[findvalve(&p->network, index)].Curve;
}
break;
case EN_GPV_CURVE: case EN_GPV_CURVE:
if (Link[index].Type == GPV) if (Link[index].Type == GPV)
{ {
@@ -3929,6 +3937,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu
value /= Ucf[FLOW]; value /= Ucf[FLOW];
break; break;
case TCV: case TCV:
case PCV:
break; break;
case GPV: case GPV:
return 207; // Cannot modify setting for GPV return 207; // Cannot modify setting for GPV
@@ -4024,6 +4033,15 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu
net->Pump[pumpIndex].Epat = patIndex; net->Pump[pumpIndex].Epat = patIndex;
} }
break; break;
case EN_PCV_CURVE:
if (Link[index].Type == PCV)
{
curveIndex = ROUND(value);
if (curveIndex < 0 || curveIndex > net->Ncurves) return 206;
net->Valve[findvalve(&p->network, index)].Curve = curveIndex;
}
break;
case EN_GPV_CURVE: case EN_GPV_CURVE:
if (Link[index].Type == GPV) if (Link[index].Type == GPV)

View File

@@ -7,7 +7,7 @@
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 02/03/2020 Last Updated: 08/13/2022
****************************************************************************** ******************************************************************************
*/ */
#ifndef FUNCS_H #ifndef FUNCS_H
@@ -166,6 +166,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 --------------------

View File

@@ -7,7 +7,7 @@
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 03/30/2022 Last Updated: 08/13/2022
****************************************************************************** ******************************************************************************
*/ */
@@ -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,6 +60,7 @@ 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);
@@ -107,6 +109,10 @@ void resistcoeff(Project *pr, int k)
case PUMP: case PUMP:
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:
@@ -116,6 +122,86 @@ void resistcoeff(Project *pr, int k)
} }
double pcvlosscoeff(Project* pr, int k, double s)
/*
**--------------------------------------------------------------
** Input: k = link index
** s = valve fraction open setting
** Output: returns a valve loss coefficient
** Purpose: finds a Positional Control Valve's loss
** coefficient from its fraction 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. frac. 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 >= 1.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 = frac. open
y = curve->Y; // y = Kv / Kvo
// 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]);
}
}
// kvr can't be > 1 or <= 0
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 +234,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;
@@ -945,6 +1034,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)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
@@ -1035,6 +1154,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;
} }

View File

@@ -7,7 +7,7 @@
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 03/19/2022 Last Updated: 08/13/2022
****************************************************************************** ******************************************************************************
*/ */
@@ -450,6 +450,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;
} }
} }
@@ -605,6 +606,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++;
} }

View File

@@ -7,7 +7,7 @@ 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: 08/08/2022
****************************************************************************** ******************************************************************************
*/ */
@@ -394,6 +394,15 @@ 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;
} }

View File

@@ -7,7 +7,7 @@ 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: 08/13/2022
****************************************************************************** ******************************************************************************
*/ */
@@ -312,6 +312,11 @@ int saveinpfile(Project *pr, const char *fname)
{ {
sprintf(s1, "%-31s %12.4f", net->Curve[j].ID, km); sprintf(s1, "%-31s %12.4f", net->Curve[j].ID, km);
} }
// For PCV add loss curve if present
else if (link->Type == PCV && (j = net->Valve[i].Curve) > 0)
{
sprintf(s1, "%12.4f %12.4f %-31s", kc, km, net->Curve[j].ID);
}
else sprintf(s1, "%12.4f %12.4f", kc, km); else sprintf(s1, "%12.4f %12.4f", kc, km);
fprintf(f, "\n%s %s", s, s1); fprintf(f, "\n%s %s", s, s1);
if (link->Comment) fprintf(f, " ;%s", link->Comment); if (link->Comment) fprintf(f, " ;%s", link->Comment);

View File

@@ -7,7 +7,7 @@ Description: parses network data from a line of an EPANET input file
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 03/20/2022 Last Updated: 08/13/2022
****************************************************************************** ******************************************************************************
*/ */
@@ -471,7 +471,7 @@ int valvedata(Project *pr)
** Purpose: processes valve data ** Purpose: processes valve data
** Format: ** Format:
** [VALVE] ** [VALVE]
** id node1 node2 diam type setting (lcoeff) ** id node1 node2 diam type setting (lcoeff lcurve)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
@@ -488,7 +488,8 @@ int valvedata(Project *pr)
setting, // Valve setting setting, // Valve setting
lcoeff = 0.0; // Minor loss coeff. lcoeff = 0.0; // Minor loss coeff.
Slink *link; Slink *link;
int err = 0; int err = 0,
losscurve = 0; // Loss coeff. curve
// Add new valve to data base // Add new valve to data base
n = parser->Ntokens; n = parser->Ntokens;
@@ -521,6 +522,8 @@ int valvedata(Project *pr)
type = TCV; type = TCV;
else if (match(parser->Tok[4], w_GPV)) else if (match(parser->Tok[4], w_GPV))
type = GPV; type = GPV;
else if (match(parser->Tok[4], w_PCV))
type = PCV;
else else
return setError(parser, 4, 213); return setError(parser, 4, 213);
@@ -538,6 +541,16 @@ int valvedata(Project *pr)
} }
else if (!getfloat(parser->Tok[5], &setting)) return setError(parser, 5, 202); else if (!getfloat(parser->Tok[5], &setting)) return setError(parser, 5, 202);
if (n >= 7 && !getfloat(parser->Tok[6], &lcoeff)) return setError(parser, 6, 202); if (n >= 7 && !getfloat(parser->Tok[6], &lcoeff)) return setError(parser, 6, 202);
// Find loss coeff. curve for PCV
if (type == PCV && n >= 8)
{
c = findcurve(net, parser->Tok[7]);
if (c == 0) return setError(parser, 7, 206);
losscurve = c;
net->Curve[c].Type = VALVE_CURVE;
if (setting > 1.0) setting = 1.0;
}
// Check for illegal connections // Check for illegal connections
if (valvecheck(pr, net->Nlinks, type, j1, j2)) if (valvecheck(pr, net->Nlinks, type, j1, j2))
@@ -563,6 +576,7 @@ int valvedata(Project *pr)
link->ResultIndex = 0; link->ResultIndex = 0;
link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG); link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG);
net->Valve[net->Nvalves].Link = net->Nlinks; net->Valve[net->Nvalves].Link = net->Nlinks;
net->Valve[net->Nvalves].Curve = losscurve;
return 0; return 0;
} }

View File

@@ -7,7 +7,7 @@ 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;
} }

View File

@@ -7,7 +7,7 @@
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 02/03/2020 Last Updated: 08/13/2022
****************************************************************************** ******************************************************************************
*/ */
@@ -862,7 +862,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
**---------------------------------------------------------------- **----------------------------------------------------------------
*/ */
@@ -879,7 +879,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
**---------------------------------------------------------------- **----------------------------------------------------------------
*/ */
@@ -896,7 +896,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
**---------------------------------------------------------------- **----------------------------------------------------------------
*/ */
@@ -1012,7 +1012,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++)
@@ -1027,15 +1027,25 @@ 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;
} }
} }
} }

View File

@@ -7,7 +7,7 @@
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: 08/13/2022
****************************************************************************** ******************************************************************************
*/ */
@@ -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"

View File

@@ -7,7 +7,7 @@
Authors: see AUTHORS Authors: see AUTHORS
Copyright: see AUTHORS Copyright: see AUTHORS
License: see LICENSE License: see LICENSE
Last Updated: 07/11/2020 Last Updated: 08/13/2022
****************************************************************************** ******************************************************************************
*/ */
@@ -145,7 +145,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 +167,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 {
@@ -455,6 +457,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

View File

@@ -39,6 +39,7 @@ 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
) )
add_executable(test_toolkit ${toolkit_test_srcs}) add_executable(test_toolkit ${toolkit_test_srcs})

73
tests/test_valve.cpp Normal file
View File

@@ -0,0 +1,73 @@
/*
******************************************************************************
Project: OWA EPANET
Version: 2.2
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, 0.25, 0.5, 0.75, 1. };
double y[] = {0.0, 0.089, 0.184, 0.406, 1.0};
double v;
int linkIndex, curveIndex;
// 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);
// 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, 0.35);
BOOST_REQUIRE(error == 0);
// Solve for hydraulics
error = EN_solveH(ph);
BOOST_REQUIRE(error == 0);
// The PCV interpolated relative flow coeff. at 0.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()