diff --git a/ReleaseNotes2_3.md b/ReleaseNotes2_3.md index 9b8ab16..f0bae05 100644 --- a/ReleaseNotes2_3.md +++ b/ReleaseNotes2_3.md @@ -26,6 +26,8 @@ This document describes the changes and updates that have been made in version 2 - `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. @@ -80,7 +82,7 @@ This document describes the changes and updates that have been made in version 2 - 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_getlinkvalue` will now return `EN_MISSING` for a valve whose initial status is fixed to `EN_OPEN` or `EN_CLOSED`. + - 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. diff --git a/doc/toolkit-topics.dox b/doc/toolkit-topics.dox index 9b5adf3..5e20e5d 100644 --- a/doc/toolkit-topics.dox +++ b/doc/toolkit-topics.dox @@ -383,6 +383,7 @@ These are the toolkit's enumerated types whose members are used as function argu | 261 | Function call attempts to delete a node or link contained in a control | | 262 | Function call attempts to modify network structure while a solver is open | | 263 | Function call refers to node that is not a tank | +| 264 | Function call refers to a link that is not a valve | | 299 | An invalid section keyword was detected in an input file | | || | 301 | Identical file names used for different types of files | diff --git a/include/epanet2.bas b/include/epanet2.bas index 2f4eb5f..32ab028 100644 --- a/include/epanet2.bas +++ b/include/epanet2.bas @@ -5,7 +5,7 @@ Attribute VB_Name = "Module1" 'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT '(EPANET2.DLL) -'Last updated on 02/14/2025 +'Last updated on 04/23/2025 ' These are codes used by the DLL functions Public Const EN_ELEVATION = 0 ' Node parameters @@ -71,6 +71,7 @@ Public Const EN_PCV_CURVE = 25 Public Const EN_LEAK_AREA = 26 Public Const EN_LEAK_EXPAN = 27 Public Const EN_LINK_LEAKAGE = 28 +Public Const EN_VALVE_TYPE = 29 Public Const EN_DURATION = 0 ' Time parameters Public Const EN_HYDSTEP = 1 diff --git a/include/epanet2.cs b/include/epanet2.cs index 7d1a12d..bb82d0b 100644 --- a/include/epanet2.cs +++ b/include/epanet2.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; //epanet2.cs[By Oscar Vegas] -//Last updated on 02/14/2025 +//Last updated on 04/23/2025 //Declarations of functions in the EPANET PROGRAMMERs TOOLKIT //(EPANET2.DLL) for use with C# @@ -84,6 +84,7 @@ namespace EpanetCSharpLibrary 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; @@ -664,7 +665,7 @@ namespace EpanetCSharpLibrary 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, int out_enabled); + public static extern int ENgetcontrolenabled(int index, ref int out_enabled); [DllImport(EPANETDLL, EntryPoint = "ENsetcontrolenabled")] public static extern int ENsetcontrolenabled(int index, int enabled); @@ -714,7 +715,7 @@ namespace EpanetCSharpLibrary 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, int out_enabled); + public static extern int ENgetruleenabled(int index, ref int out_enabled); [DllImport(EPANETDLL, EntryPoint = "ENsetruleenabled")] public static extern int ENsetruleenabled(int index, int enabled); diff --git a/include/epanet2.pas b/include/epanet2.pas index a66a0bd..3f5d09c 100644 --- a/include/epanet2.pas +++ b/include/epanet2.pas @@ -3,7 +3,7 @@ unit epanet2; { Declarations of imported procedures from the EPANET PROGRAMMERs TOOLKIT } { (EPANET2.DLL) } -{Last updated on 02/14/2025} +{Last updated on 04/23/2025} interface @@ -79,6 +79,7 @@ const EN_LEAK_AREA = 26; EN_LEAK_EXPAN = 27; EN_LINK_LEAKAGE = 28; + EN_VALVE_TYPE = 29; EN_DURATION = 0; { Time parameters } EN_HYDSTEP = 1; @@ -449,8 +450,8 @@ const function ENdeletecontrol(Index: Integer): Integer; cdecl; external EpanetLib; function ENgetcontrol(Index: Integer; var Ctype: Integer; var Link: Integer; var Setting: Single; var Node: Integer; var Level: Single): Integer; cdecl; external EpanetLib; function ENsetcontrol(Index: Integer; Ctype: Integer; Link: Integer; Setting: Single; Node: Integer; Level: Single): Integer; cdecl; external EpanetLib; - function ENgetcontrolenabled(Index: Integer; out_enabled: Integer): Integer; cdecl; external EpanetLib; - function ENsetcontrolenabled(Index: Integer; var enabled: Integer): Integer; cdecl; external EpanetLib; + function ENgetcontrolenabled(Index: Integer; var out_enabled: Integer): Integer; cdecl; external EpanetLib; + function ENsetcontrolenabled(Index: Integer; enabled: Integer): Integer; cdecl; external EpanetLib; {Rule-Based Control Functions} function ENaddrule(Rule: PAnsiChar): Integer; cdecl; external EpanetLib; @@ -475,7 +476,7 @@ const var Status: Integer; var Setting: Single): Integer; cdecl; external EpanetLib; function ENsetelseaction(RuleIndex: Integer; ActionIndex: Integer; LinkIndex: Integer; Status: Integer; Setting: Single): Integer; cdecl; external EpanetLib; - function ENgetruleenabled(Index: Integer; var enabled: Integer): 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 diff --git a/include/epanet2.vb b/include/epanet2.vb index a73f28c..72770b9 100644 --- a/include/epanet2.vb +++ b/include/epanet2.vb @@ -4,7 +4,7 @@ 'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT '(EPANET2.DLL) for use with VB.Net. -'Last updated on 02/14/2025 +'Last updated on 04/23/2025 Imports System.Runtime.InteropServices Imports System.Text @@ -75,6 +75,7 @@ Public Const EN_PCV_CURVE = 25 Public Const EN_LEAK_AREA = 26 Public Const EN_LEAK_EXPAN = 27 Public Const EN_LINK_LEAKAGE = 28 +Public Const EN_VALVE_TYPE = 29 Public Const EN_DURATION = 0 ' Time parameters Public Const EN_HYDSTEP = 1 diff --git a/include/epanet2_2.h b/include/epanet2_2.h index 2dcfc28..b527b98 100644 --- a/include/epanet2_2.h +++ b/include/epanet2_2.h @@ -11,7 +11,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 02/14/2025 + Last Updated: 04/25/2025 ****************************************************************************** */ @@ -1263,6 +1263,8 @@ typedef struct Project *EN_Project; contain the link are deleted when the link's type is changed. If set to `EN_CONDITIONAL` then the type change is cancelled if the link appears in any control and error 261 is returned. + + To only change a valve's type (such as from PRV to PSV) use ::EN_setlinkvalue with property `EN_VALVE_TYPE` whose value is selected from the valves in @ref EN_LinkType. */ int DLLEXPORT EN_setlinktype(EN_Project ph, int *inout_index, int linkType, int actionCode); diff --git a/include/epanet2_enums.h b/include/epanet2_enums.h index f0c8864..a48171f 100644 --- a/include/epanet2_enums.h +++ b/include/epanet2_enums.h @@ -9,7 +9,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 03/22/2025 + Last Updated: 04/23/2025 ****************************************************************************** */ @@ -103,7 +103,8 @@ typedef enum { EN_PCV_CURVE = 25, //!< PCV loss coeff. 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_LINK_LEAKAGE = 28, //!< Current leakage rate (read only) + EN_VALVE_TYPE = 29 //!< Type of valve (see @ref EN_LinkType) } EN_LinkProperty; /// Time parameters diff --git a/src/epanet.c b/src/epanet.c index c1bfbfe..1e8cc8f 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 04/19/2025 + Last Updated: 04/23/2025 ****************************************************************************** */ @@ -4015,6 +4015,10 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val case EN_LINK_LEAKAGE: v = findlinkleakage(p, index) * Ucf[FLOW]; break; + + case EN_VALVE_TYPE: + if (Link[index].Type > PUMP) v = Link[index].Type; + break; default: return 251; @@ -4060,7 +4064,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu double *Ucf = p->Ucf; char s; double r; - int pumpIndex, patIndex, curveIndex; + int pumpIndex, patIndex, curveIndex, valveType; if (!p->Openflag) return 102; if (index <= 0 || index > net->Nlinks) return 204; @@ -4268,6 +4272,14 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu if (value < 0.0) return 211; Link[index].LeakExpan = value / Ucf[LENGTH]; break; + + case EN_VALVE_TYPE: + if (hyd->OpenHflag || qual->OpenQflag) return 262; //Solver is running + if (Link[index].Type <= PUMP) return 264; //Link not a valve + valveType = ROUND(value); + if (valveType < PRV || valveType > PCV) return 213; //Invalid valve type + if (valveType == Link[index].Type) return 0; //No type change + return changevalvetype(p, index, valveType); //See project.c default: return 251; diff --git a/src/errors.dat b/src/errors.dat index 35ecf7b..65b9519 100644 --- a/src/errors.dat +++ b/src/errors.dat @@ -65,6 +65,7 @@ DAT(260,"attempt to delete node assigned as a Trace Node") DAT(261,"attempt to delete a node or link contained in a control") DAT(262,"attempt to modify network structure while solver is active") DAT(263,"node is not a tank") +DAT(264,"link is not a valve") // File errors DAT(301,"identical file names") diff --git a/src/funcs.h b/src/funcs.h index 2fae94b..987534c 100755 --- a/src/funcs.h +++ b/src/funcs.h @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 02/14/2025 + Last Updated: 04/23/2025 ****************************************************************************** */ #ifndef FUNCS_H @@ -29,6 +29,7 @@ int buildadjlists(Network *); void freeadjlists(Network *); int incontrols(Project *, int, int); +int changevalvetype(Project *, int, int); int valvecheck(Project *, int, int, int, int); int unlinked(Project *); diff --git a/src/project.c b/src/project.c index b1c7261..1b50df4 100644 --- a/src/project.c +++ b/src/project.c @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 02/19/2025 + Last Updated: 04/23/2025 ****************************************************************************** */ @@ -754,7 +754,6 @@ int buildadjlists(Network *net) return errcode; } - void freeadjlists(Network *net) /* **-------------------------------------------------------------- @@ -841,6 +840,66 @@ int incontrols(Project *pr, int objType, int index) return 0; } +int changevalvetype(Project *pr, int index, int type) +/* +**-------------------------------------------------------------- +** Input: index = link index +** type = new valve type +** Output: returns an error code +** Purpose: changes a valve's type +**-------------------------------------------------------------- +*/ +{ + Network *net = &pr->network; + Slink *link; + int errcode; + double setting; + + // Check that new valve type has legal connections + link = &net->Link[index]; + if (link->Type <= PUMP) return 264; + errcode = valvecheck(pr, index, type, link->N1, link->N2); + if (errcode) return errcode; + + // Preserve new type's setting in solver units + setting = link->InitSetting; + switch (link->Type) + { + case FCV: + setting *= pr->Ucf[FLOW]; + break; + case PRV: + case PSV: + case PBV: + setting *= pr->Ucf[PRESSURE]; + break; + case GPV: + setting = 0.0; + break; + } + switch (type) + { + case FCV: + setting /= pr->Ucf[FLOW]; + break; + case PRV: + case PSV: + case PBV: + setting /= pr->Ucf[PRESSURE]; + break; + } + + // Save setting + if (type == GPV) setting = 0.0; + if (type == PCV) setting = MIN(setting, 100.0); + link->Kc = setting; + link->InitSetting = setting; + + // Change valve link's type + link->Type = type; + return 0; +} + int valvecheck(Project *pr, int index, int type, int j1, int j2) /* **-------------------------------------------------------------- @@ -1365,7 +1424,6 @@ 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