From 8a84668f6390b404f2670eab1c7c57ed32f9e18e Mon Sep 17 00:00:00 2001 From: Elad Salomons Date: Thu, 14 Sep 2023 13:35:05 +0300 Subject: [PATCH 1/2] Updated header files following #751 Updated header files following #751 --- include/epanet2.bas | 30 +++++++++++++++++++----------- include/epanet2.cs | 17 +++++++++++++++-- include/epanet2.def | 6 +++++- include/epanet2.pas | 10 +++++++++- include/epanet2.vb | 9 ++++++++- 5 files changed, 56 insertions(+), 16 deletions(-) diff --git a/include/epanet2.bas b/include/epanet2.bas index 663c7325..fd57d96b 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 07/18/2023 +'Last updated on 09/14/2023 ' These are codes used by the DLL functions Public Const EN_ELEVATION = 0 ' Node parameters @@ -35,7 +35,7 @@ Public Const EN_TANK_KBULK = 23 Public Const EN_TANKVOLUME = 24 Public Const EN_MAXVOLUME = 25 Public Const EN_CANOVERFLOW = 26 -Public Const EN_DEMANDDEFICIT = 27 +Public Const EN_DEMANDDEFICIT = 27 Public Const EN_NODE_INCONTROL = 28 Public Const EN_EMITTERFLOW = 29 @@ -64,7 +64,7 @@ Public Const EN_PUMP_ECOST = 21 Public Const EN_PUMP_EPAT = 22 Public Const EN_LINK_INCONTROL = 23 Public Const EN_GPV_CURVE = 24 -Public Const EN_PCV_CURVE= 25 +Public Const EN_PCV_CURVE = 25 Public Const EN_DURATION = 0 ' Time parameters Public Const EN_HYDSTEP = 1 @@ -96,7 +96,7 @@ Public Const EN_LINK = 1 Public Const EN_TIMEPAT = 2 Public Const EN_CURVE = 3 Public Const EN_CONTROL = 4 -Public Const EN_RULE = 5 +Public Const EN_RULE = 5 Public Const EN_NODECOUNT = 0 ' Component counts Public Const EN_TANKCOUNT = 1 @@ -122,7 +122,7 @@ Public Const EN_GPV = 8 Public Const EN_PCV = 9 Public Const EN_CLOSED = 0 ' Link status types -Public Const EN_OPEN = 1 +Public Const EN_OPEN = 1 Public Const EN_PUMP_XHEAD = 0 ' Pump state types Public Const EN_PUMP_CLOSED = 2 @@ -175,7 +175,7 @@ Public Const EN_GLOBALPRICE = 9 Public Const EN_GLOBALPATTERN = 10 Public Const EN_DEMANDCHARGE = 11 Public Const EN_SP_GRAVITY = 12 -Public Const EN_SP_VISCOS = 13 +Public Const EN_SP_VISCOS = 13 Public Const EN_UNBALANCED = 14 Public Const EN_CHECKFREQ = 15 Public Const EN_MAXCHECK = 16 @@ -269,9 +269,12 @@ Public Const EN_STEP_WQ = 2 Public Const EN_STEP_TANKEVENT = 3 Public Const EN_STEP_CONTROLEVENT = 4 -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_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 @@ -355,7 +358,7 @@ Public Const EN_SET_OPEN As Double = 1.0E10 Declare Function ENgetdemandindex Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandName As String, demandIndex As Long) As Long Declare Function ENgetnumdemands Lib "epanet2.dll" (ByVal nodeIndex As Long, numDemands As Long) As Long Declare Function ENgetbasedemand Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandIndex As Long, value As Single) As Long - Declare Function ENsetbasedemand Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandIndex As Long, ByVal BaseDemand As Single) As Long + Declare Function ENsetbasedemand Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandIndex As Long, ByVal baseDemand As Single) As Long Declare Function ENgetdemandpattern Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandIndex As Long, patIndex As Long) As Long Declare Function ENsetdemandpattern Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandIndex As Long, ByVal patIndex As Long) As Long Declare Function ENgetdemandname Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandIndex As Long, ByVal demandName As String) As Long @@ -415,7 +418,9 @@ Public Const EN_SET_OPEN As Double = 1.0E10 Declare Function ENdeletecontrol Lib "epanet2.dll" (ByVal index As Long) As Long Declare Function ENgetcontrol Lib "epanet2.dll" (ByVal index As Long, type_ As Long, linkIndex As Long, setting As Single, nodeIndex As Long, level As Single) As Long Declare Function ENsetcontrol Lib "epanet2.dll" (ByVal index As Long, ByVal type_ As Long, ByVal linkIndex As Long, ByVal setting As Single, ByVal nodeIndex As Long, ByVal level As Single) As Long - + Declare Function ENgetcontrolenabled Lib "epanet2.dll" (ByVal index As Long, out_enabled As Long) As Long + Declare Function ENsetcontrolenabled Lib "epanet2.dll" (ByVal index As Long, ByVal enabled As Long) As Long + 'Rule-Based Control Functions Declare Function ENaddrule Lib "epanet2.dll" (ByVal rule As String) As Long Declare Function ENdeleterule Lib "epanet2.dll" (ByVal index As Long) As Long @@ -431,3 +436,6 @@ Public Const EN_SET_OPEN As Double = 1.0E10 Declare Function ENsetthenaction Lib "epanet2.dll" (ByVal ruleIndex As Long, ByVal actionIndex As Long, ByVal linkIndex As Long, ByVal status As Long, ByVal setting As Single) As Long Declare Function ENgetelseaction Lib "epanet2.dll" (ByVal ruleIndex As Long, ByVal actionIndex As Long, linkIndex As Long, status As Long, setting As Single) As Long Declare Function ENsetelseaction Lib "epanet2.dll" (ByVal ruleIndex As Long, ByVal actionIndex As Long, ByVal linkIndex As Long, ByVal status As Long, ByVal setting As Single) As Long + Declare Function ENgetruleenabled Lib "epanet2.dll" (ByVal index As Long, out_enabled As Long) As Long + Declare Function ENsetruleenabled Lib "epanet2.dll" (ByVal index As Long, ByVal enabled As Long) As Long + diff --git a/include/epanet2.cs b/include/epanet2.cs index 0a6fedc8..95c99d4d 100644 --- a/include/epanet2.cs +++ b/include/epanet2.cs @@ -3,7 +3,7 @@ using System.Runtime.InteropServices; //epanet2.cs[By Oscar Vegas] -//Last updated on 07/18/2023 +//Last updated on 09/14/2023 //Declarations of functions in the EPANET PROGRAMMERs TOOLKIT //(EPANET2.DLL) for use with C# @@ -269,7 +269,9 @@ public static class Epanet 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 @@ -629,6 +631,12 @@ public static class Epanet [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, int out_enabled); + + [DllImport(EPANETDLL, EntryPoint = "ENsetcontrolenabled")] + public static extern int ENsetcontrolenabled(int index, int enabled); + //Rule-Based Control Functions [DllImport(EPANETDLL, EntryPoint = "ENaddrule")] @@ -673,6 +681,11 @@ public static class Epanet [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, int out_enabled); + + [DllImport(EPANETDLL, EntryPoint = "ENsetruleenabled")] + public static extern int ENsetruleenabled(int index, int enabled); #endregion } diff --git a/include/epanet2.def b/include/epanet2.def index d72da8ea..a2e94138 100644 --- a/include/epanet2.def +++ b/include/epanet2.def @@ -131,4 +131,8 @@ EXPORTS ENstepQ = _ENstepQ@4 ENusehydfile = _ENusehydfile@4 ENwriteline = _ENwriteline@4 - ENtimetonextevent = _ENtimetonextevent@12 \ No newline at end of file + ENtimetonextevent = _ENtimetonextevent@12 + ENgetcontrolenabled = _ENgetcontrolenabled@8 + ENsetcontrolenabled = _ENsetcontrolenabled@8 + ENgetruleenabled = _ENgetruleenabled@8 + ENsetruleenabled = _ENsetruleenabled@8 \ No newline at end of file diff --git a/include/epanet2.pas b/include/epanet2.pas index 3ae75ad9..6a1aaf80 100644 --- a/include/epanet2.pas +++ b/include/epanet2.pas @@ -3,7 +3,7 @@ { Declarations of imported procedures from the EPANET PROGRAMMERs TOOLKIT } { (EPANET2.DLL) } -{Last updated on 09/11/2023} +{Last updated on 09/14/2023} interface @@ -270,6 +270,10 @@ interface EN_R_IS_OPEN = 1; { Rule-based control link status } EN_R_IS_CLOSED = 2; EN_R_IS_ACTIVE = 3; + + EN_FALSE = 0; { boolean false } + EN_TRUE = 1; { boolean true } + {$ifdef MSWINDOWS} EpanetLib = 'epanet2.dll'; @@ -416,6 +420,8 @@ interface function ENdeletecontrol(Index: Integer): Integer; stdcall; external EpanetLib; function ENgetcontrol(Index: Integer; var Ctype: Integer; var Link: Integer; var Setting: Single; var Node: Integer; var Level: Single): Integer; stdcall; external EpanetLib; function ENsetcontrol(Index: Integer; Ctype: Integer; Link: Integer; Setting: Single; Node: Integer; Level: Single): Integer; stdcall; external EpanetLib; + function ENgetcontrolenabled(Index: Integer; out_enabled: Integer): Integer; stdcall; external EpanetLib; + function ENsetcontrolenabled(Index: Integer; var enabled: Integer): Integer; stdcall; external EpanetLib; {Rule-Based Control Functions} function ENaddrule(Rule: PAnsiChar): Integer; stdcall; external EpanetLib; @@ -440,6 +446,8 @@ interface var Status: Integer; var Setting: Single): Integer; stdcall; external EpanetLib; function ENsetelseaction(RuleIndex: Integer; ActionIndex: Integer; LinkIndex: Integer; Status: Integer; Setting: Single): Integer; stdcall; external EpanetLib; + function ENgetruleenabled(Index: Integer; out_enabled: Integer): Integer; stdcall; external EpanetLib; + function ENsetruleenabled(Index: Integer; var enabled: Integer): Integer; stdcall; external EpanetLib; implementation diff --git a/include/epanet2.vb b/include/epanet2.vb index 1a6bf114..fe36c343 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 07/18/2023 +'Last updated on 09/14/2023 Imports System.Runtime.InteropServices Imports System.Text @@ -261,6 +261,9 @@ 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 'Project Functions @@ -399,6 +402,8 @@ Public Const EN_SET_OPEN As Double = 1.0E10 Declare Function ENdeletecontrol Lib "epanet2.dll" (ByVal index As Int32) As Int32 Declare Function ENgetcontrol Lib "epanet2.dll" (ByVal index As Int32, type_ As Int32, linkIndex As Int32, setting As Single, nodeIndex As Int32, level As Single) As Int32 Declare Function ENsetcontrol Lib "epanet2.dll" (ByVal index As Int32, ByVal type_ As Int32, ByVal linkIndex As Int32, ByVal setting As Single, ByVal nodeIndex As Int32, ByVal level As Single) As Int32 + Declare Function ENgetcontrolenabled Lib "epanet2.dll" (ByVal index As Int32, out_enabled As Int32) As Int32 + Declare Function ENsetcontrolenabled Lib "epanet2.dll" (ByVal index As Int32, ByVal enabled As Int32) As Int32 'Rule-Based Control Functions Declare Function ENaddrule Lib "epanet2.dll" (ByVal rule As String) As Int32 @@ -415,5 +420,7 @@ Public Const EN_SET_OPEN As Double = 1.0E10 Declare Function ENsetthenaction Lib "epanet2.dll" (ByVal ruleIndex As Int32, ByVal actionIndex As Int32, ByVal linkIndex As Int32, ByVal status As Int32, ByVal setting As Single) As Int32 Declare Function ENgetelseaction Lib "epanet2.dll" (ByVal ruleIndex As Int32, ByVal actionIndex As Int32, linkIndex As Int32, status As Int32, setting As Single) As Int32 Declare Function ENsetelseaction Lib "epanet2.dll" (ByVal ruleIndex As Int32, ByVal actionIndex As Int32, ByVal linkIndex As Int32, ByVal status As Int32, ByVal setting As Single) As Int32 + Declare Function ENgetruleenabled Lib "epanet2.dll" (ByVal index As Int32, out_enabled As Int32) As Int32 + Declare Function ENsetruleenabled Lib "epanet2.dll" (ByVal index As Int32, ByVal enabled As Int32) As Int32 End Module From cfc06321a67ee60f0905c57cf62e589aec6219ac Mon Sep 17 00:00:00 2001 From: Luke Butler Date: Thu, 14 Sep 2023 16:00:34 -0400 Subject: [PATCH 2/2] Remove recursion in getclosedlink MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function getclosedlink in report.c uses recursion to find closed links when reporting on disconnections. In very large networks, it’s possible for the recursion to exhaust the memory on the call stack which then causes EPANET to crash. If a loop is used instead of recursion, EPANET will not crash with very large disconnections --- ReleaseNotes2_3.md | 1 + src/report.c | 50 +++++++++++++++++++++++++++++++++------------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/ReleaseNotes2_3.md b/ReleaseNotes2_3.md index cb8f1515..2cf6f877 100644 --- a/ReleaseNotes2_3.md +++ b/ReleaseNotes2_3.md @@ -47,4 +47,5 @@ This document describes the changes and updates that have been made in version 2 - `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`). - A possible parser error that could result in a Trace Node ID in an input file not being recognized was fixed. - Additional API functions for enabling/disabling controls and rules were added. + - 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. \ No newline at end of file diff --git a/src/report.c b/src/report.c index 14f55cfb..31e0649e 100644 --- a/src/report.c +++ b/src/report.c @@ -45,7 +45,7 @@ static void writeenergy(Project *); static int writeresults(Project *); static int disconnected(Project *); static void marknodes(Project *, int, int *, char *); -static void getclosedlink(Project *, int, char *); +static void getclosedlink(Project *, int, char *, int *); static void writelimits(Project *, int, int); static int checklimits(Report *, double *, int, int); static char *fillstr(char *, char, int); @@ -1287,7 +1287,7 @@ int disconnected(Project *pr) clocktime(rpt->Atime, time->Htime)); writeline(pr, pr->Msg); } - getclosedlink(pr, j, marked); + getclosedlink(pr, j, marked, nodelist); } // Free allocated memory @@ -1350,11 +1350,12 @@ void marknodes(Project *pr, int m, int *nodelist, char *marked) } } -void getclosedlink(Project *pr, int i, char *marked) +void getclosedlink(Project *pr, int i, char *marked, int *stack) /* **---------------------------------------------------------------- ** Input: i = junction index ** marked[] = marks nodes already examined +** stack[] = stack to hold nodes to examine ** Output: None. ** Purpose: Determines if a closed link connects to junction i. **---------------------------------------------------------------- @@ -1365,20 +1366,41 @@ void getclosedlink(Project *pr, int i, char *marked) int j, k; Padjlist alink; + int top = 0; + + // Mark the current junction as examined and push onto stack marked[i] = 2; - for (alink = net->Adjlist[i]; alink != NULL; alink = alink->next) - { - k = alink->link; - j = alink->node; - if (marked[j] == 2) continue; - if (marked[j] == 1) - { - sprintf(pr->Msg, WARN03c, net->Link[k].ID); - writeline(pr, pr->Msg); - return; + stack[top] = i; + + while (top >= 0) { + i = stack[top--]; + alink = net->Adjlist[i]; + + // Iterate through each link adjacent to the current node + while (alink != NULL) { + k = alink->link; + j = alink->node; + + // Skip nodes that have already been examined + if (marked[j] == 2) { + alink = alink->next; + continue; + } + + // If a closed link is found, return and display a warning message + if (marked[j] == 1) { + sprintf(pr->Msg, WARN03c, net->Link[k].ID); + writeline(pr, pr->Msg); + return; + } + + // Mark the node as examined and push it onto the stack + marked[j] = 2; + stack[++top] = j; + alink = alink->next; } - else getclosedlink(pr, j, marked); } + } void writelimits(Project *pr, int j1, int j2)