Allow simple controls to set valves OPEN/CLOSED
This commit is contained in:
@@ -3,7 +3,7 @@ using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
//epanet2.cs[By Oscar Vegas]
|
||||
//Last updated on 17/09/2020
|
||||
//Last updated on 05/13/2023
|
||||
|
||||
//Declarations of functions in the EPANET PROGRAMMERs TOOLKIT
|
||||
//(EPANET2.DLL) for use with C#
|
||||
@@ -264,6 +264,8 @@ namespace EpanetCSharpLibrary
|
||||
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
|
||||
|
||||
|
||||
#region Epanet Imports
|
||||
|
||||
@@ -5,7 +5,7 @@ Attribute VB_Name = "Module1"
|
||||
'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT
|
||||
'(EPANET2.DLL)
|
||||
|
||||
'Last updated on 07/28/2022
|
||||
'Last updated on 05/13/2023
|
||||
|
||||
' These are codes used by the DLL functions
|
||||
Public Const EN_ELEVATION = 0 ' Node parameters
|
||||
@@ -268,6 +268,8 @@ 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
|
||||
|
||||
'These are the external functions that comprise the DLL
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ unit epanet2;
|
||||
{ Declarations of imported procedures from the EPANET PROGRAMMERs TOOLKIT }
|
||||
{ (EPANET2.DLL) }
|
||||
|
||||
{Last updated on 07/28/2022}
|
||||
{Last updated on 05/13/2023}
|
||||
|
||||
interface
|
||||
|
||||
@@ -13,6 +13,8 @@ const
|
||||
EN_MAXID = 31; { Max. # characters in ID name }
|
||||
EN_MAXMSG = 255; { Max. # characters in strings }
|
||||
EN_MISSING = -1.E10;
|
||||
EN_SET_CLOSED = -1.E10;
|
||||
EN_SET_OPEN = 1.E10;
|
||||
|
||||
EN_ELEVATION = 0; { Node parameters }
|
||||
EN_BASEDEMAND = 1;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT
|
||||
'(EPANET2.DLL) for use with VB.Net.
|
||||
|
||||
'Last updated on 07/28/2022
|
||||
'Last updated on 05/13/2023
|
||||
|
||||
Imports System.Runtime.InteropServices
|
||||
Imports System.Text
|
||||
@@ -256,6 +256,8 @@ Public Const EN_R_IS_CLOSED = 2
|
||||
Public Const EN_R_IS_ACTIVE = 3
|
||||
|
||||
Public Const EN_MISSING As Double = -1.0E10
|
||||
Public Const EN_SET_CLOSED As Double = -1.0E10
|
||||
Public Const EN_SET_OPEN As Double = 1.0E10
|
||||
|
||||
'These are the external functions that comprise the DLL
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 02/05/2023
|
||||
Last Updated: 04/28/2023
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -499,5 +499,7 @@ typedef enum {
|
||||
} EN_RuleStatus;
|
||||
|
||||
#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
|
||||
|
||||
#endif //EPANET2_ENUMS_H
|
||||
|
||||
146
src/epanet.c
146
src/epanet.c
@@ -7,7 +7,7 @@
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 02/05/2023
|
||||
Last Updated: 04/29/2023
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -5069,15 +5069,9 @@ int DLLEXPORT EN_addcontrol(EN_Project p, int type, int linkIndex, double settin
|
||||
*/
|
||||
{
|
||||
Network *net = &p->network;
|
||||
Parser *parser = &p->parser;
|
||||
|
||||
char status = ACTIVE;
|
||||
int n;
|
||||
long t = 0;
|
||||
double s = setting, lvl = level;
|
||||
double *Ucf = p->Ucf;
|
||||
Scontrol *control;
|
||||
|
||||
int err, n;
|
||||
Scontrol ctrl;
|
||||
|
||||
// Check that project exists
|
||||
if (!p->Openflag) return 102;
|
||||
@@ -5085,68 +5079,20 @@ int DLLEXPORT EN_addcontrol(EN_Project p, int type, int linkIndex, double settin
|
||||
// Check that controlled link exists
|
||||
if (linkIndex <= 0 || linkIndex > net->Nlinks) return 204;
|
||||
|
||||
// Cannot control check valve
|
||||
if (net->Link[linkIndex].Type == CVPIPE) return 207;
|
||||
|
||||
// Check for valid parameters
|
||||
if (type < 0 || type > EN_TIMEOFDAY) return 251;
|
||||
if (type == EN_LOWLEVEL || type == EN_HILEVEL)
|
||||
{
|
||||
if (nodeIndex < 1 || nodeIndex > net->Nnodes) return 203;
|
||||
}
|
||||
else nodeIndex = 0;
|
||||
if (s < 0.0 || lvl < 0.0) return 202;
|
||||
|
||||
// Adjust units of control parameters
|
||||
switch (net->Link[linkIndex].Type)
|
||||
{
|
||||
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;
|
||||
case PIPE:
|
||||
case PUMP:
|
||||
status = OPEN;
|
||||
if (s == 0.0) status = CLOSED;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
if (type == TIMER) t = (long)ROUND(lvl);
|
||||
if (type == TIMEOFDAY) t = (long)ROUND(lvl) % SECperDAY;
|
||||
// Insert control properties into a temporary struct
|
||||
err = setcontrol(p, type, linkIndex, setting, nodeIndex, level, &ctrl);
|
||||
if (err > 0) return err;
|
||||
|
||||
// Expand project's array of controls
|
||||
n = net->Ncontrols + 1;
|
||||
net->Control = (Scontrol *)realloc(net->Control, (n + 1) * sizeof(Scontrol));
|
||||
|
||||
// Set properties of the new control
|
||||
control = &net->Control[n];
|
||||
control->Type = (char)type;
|
||||
control->Link = linkIndex;
|
||||
control->Node = nodeIndex;
|
||||
control->Status = status;
|
||||
control->Setting = s;
|
||||
control->Grade = lvl;
|
||||
control->Time = t;
|
||||
net->Control[n] = ctrl;
|
||||
|
||||
// Update number of controls
|
||||
net->Ncontrols = n;
|
||||
parser->MaxControls = n;
|
||||
p->parser.MaxControls = n;
|
||||
|
||||
// Replace the control's index
|
||||
*index = n;
|
||||
@@ -5229,8 +5175,8 @@ int DLLEXPORT EN_getcontrol(EN_Project p, int index, int *type, int *linkIndex,
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (control->Status == OPEN) s = 1.0;
|
||||
else s = 0.0;
|
||||
else if (control->Status == OPEN) s = SET_OPEN;
|
||||
else s = SET_CLOSED;
|
||||
|
||||
// Retrieve level value for a node level control
|
||||
*nodeIndex = control->Node;
|
||||
@@ -5252,8 +5198,8 @@ int DLLEXPORT EN_getcontrol(EN_Project p, int index, int *type, int *linkIndex,
|
||||
{
|
||||
lvl = (double)control->Time;
|
||||
}
|
||||
*setting = (double)s;
|
||||
*level = (double)lvl;
|
||||
*setting = s;
|
||||
*level = lvl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5275,81 +5221,27 @@ int DLLEXPORT EN_setcontrol(EN_Project p, int index, int type, int linkIndex,
|
||||
{
|
||||
Network *net = &p->network;
|
||||
|
||||
char status = ACTIVE;
|
||||
long t = 0;
|
||||
double s = setting, lvl = level;
|
||||
double *Ucf = p->Ucf;
|
||||
Slink *link;
|
||||
Scontrol *control;
|
||||
int err;
|
||||
Scontrol ctrl;
|
||||
|
||||
// Check that project exists
|
||||
if (!p->Openflag) return 102;
|
||||
|
||||
// Check that control exists
|
||||
if (index <= 0 || index > net->Ncontrols) return 241;
|
||||
control = &net->Control[index];
|
||||
|
||||
// Check that controlled link exists (0 index de-activates the control)
|
||||
if (linkIndex == 0)
|
||||
{
|
||||
control->Link = 0;
|
||||
net->Control[index].Link = 0;
|
||||
return 0;
|
||||
}
|
||||
if (linkIndex < 0 || linkIndex > net->Nlinks) return 204;
|
||||
|
||||
// Cannot control check valve
|
||||
if (net->Link[linkIndex].Type == CVPIPE) return 207;
|
||||
|
||||
// Check for valid control properties
|
||||
if (type < 0 || type > EN_TIMEOFDAY) return 251;
|
||||
if (type == EN_LOWLEVEL || type == EN_HILEVEL)
|
||||
{
|
||||
if (nodeIndex < 1 || nodeIndex > net->Nnodes) return 203;
|
||||
}
|
||||
else nodeIndex = 0;
|
||||
if (s < 0.0 || lvl < 0.0) return 202;
|
||||
|
||||
// Adjust units of control's properties
|
||||
link = &net->Link[linkIndex];
|
||||
switch (link->Type)
|
||||
{
|
||||
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 = link->Kc;
|
||||
break;
|
||||
case PIPE:
|
||||
case PUMP:
|
||||
status = OPEN;
|
||||
if (s == 0.0) status = CLOSED;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
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];
|
||||
}
|
||||
if (type == TIMER) t = (long)ROUND(lvl);
|
||||
if (type == TIMEOFDAY) t = (long)ROUND(lvl) % SECperDAY;
|
||||
|
||||
/* Reset control's parameters */
|
||||
control->Type = (char)type;
|
||||
control->Link = linkIndex;
|
||||
control->Node = nodeIndex;
|
||||
control->Status = status;
|
||||
control->Setting = s;
|
||||
control->Grade = lvl;
|
||||
control->Time = t;
|
||||
// Assign new set of properties to control
|
||||
err = setcontrol(p, type, linkIndex, setting, nodeIndex, level, &ctrl);
|
||||
if (err > 0) return err;
|
||||
net->Control[index] = ctrl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 08/13/2022
|
||||
Last Updated: 04/29/2023
|
||||
******************************************************************************
|
||||
*/
|
||||
#ifndef FUNCS_H
|
||||
@@ -50,6 +50,7 @@ void adjustpatterns(Network *, int);
|
||||
void adjustcurves(Network *, int);
|
||||
int adjustpumpparams(Project *, int);
|
||||
int resizecurve(Scurve *, int);
|
||||
int setcontrol(Project *, int, int, double, int, double, Scontrol *);
|
||||
|
||||
int getcomment(Network *, int, int, char *);
|
||||
int setcomment(Network *, int, int, const char *);
|
||||
|
||||
@@ -7,7 +7,7 @@ Description: saves network data to an EPANET formatted text file
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 02/05/2023
|
||||
Last Updated: 04/30/2023
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -432,7 +432,12 @@ int saveinpfile(Project *pr, const char *fname)
|
||||
link = &net->Link[j];
|
||||
|
||||
// Get text of control's link status/setting
|
||||
if (control->Setting == MISSING || link->Type == GPV)
|
||||
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]);
|
||||
}
|
||||
|
||||
107
src/project.c
107
src/project.c
@@ -7,7 +7,7 @@
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 08/13/2022
|
||||
Last Updated: 04/29/2023
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -1121,6 +1121,111 @@ int resizecurve(Scurve *curve, int size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int setcontrol(EN_Project p, int type, int linkIndex, double setting,
|
||||
int nodeIndex, double level, Scontrol *control)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: type = type of control (see EN_ControlType)
|
||||
** linkIndex = index of link being controlled
|
||||
** setting = link control setting (e.g., pump speed)
|
||||
** nodeIndex = index of node controlling a link (for level controls)
|
||||
** level = control activation level (pressure for junction nodes,
|
||||
** water level for tank nodes or time value for time-based
|
||||
** control)
|
||||
** Output: control = control struct whose properties are being set
|
||||
** Returns: error code
|
||||
** Purpose: assigns properties to a control struct.
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &p->network;
|
||||
Parser *parser = &p->parser;
|
||||
|
||||
long t = 0;
|
||||
double lvl = 0.0, s = MISSING;
|
||||
double *Ucf = p->Ucf;
|
||||
LinkType linktype;
|
||||
StatusType status = ACTIVE;
|
||||
|
||||
// Cannot control check valve
|
||||
linktype = net->Link[linkIndex].Type;
|
||||
if (linktype == CVPIPE) return 207;
|
||||
|
||||
// Check for valid control type and node index
|
||||
if (type < 0 || type > TIMEOFDAY) return 251;
|
||||
if (type == LOWLEVEL || type == HILEVEL)
|
||||
{
|
||||
if (nodeIndex < 1 || nodeIndex > net->Nnodes) return 203;
|
||||
}
|
||||
else nodeIndex = 0;
|
||||
|
||||
// Check if control setting is a status level
|
||||
if (setting == SET_OPEN)
|
||||
{
|
||||
status = OPEN;
|
||||
if (linktype == PUMP) s = 1.0;
|
||||
if (linktype == GPV) s = net->Link[linkIndex].Kc;
|
||||
}
|
||||
else if (setting == SET_CLOSED)
|
||||
{
|
||||
status = CLOSED;
|
||||
if (linktype == PUMP) s = 0.0;
|
||||
if (linktype == GPV) s = net->Link[linkIndex].Kc;
|
||||
}
|
||||
|
||||
// Convert units of control setting
|
||||
else
|
||||
{
|
||||
s = setting;
|
||||
switch (linktype)
|
||||
{
|
||||
case PIPE:
|
||||
case PUMP:
|
||||
if (s < 0.0) return 202;
|
||||
else if (s == 0.0) status = CLOSED;
|
||||
else status = OPEN;
|
||||
break;
|
||||
case PRV:
|
||||
case PSV:
|
||||
case PBV:
|
||||
s /= Ucf[PRESSURE];
|
||||
break;
|
||||
case FCV:
|
||||
s /= Ucf[FLOW];
|
||||
break;
|
||||
case GPV:
|
||||
if (s == 0.0) status = CLOSED;
|
||||
else if (s == 1.0) status = OPEN;
|
||||
else return 202;
|
||||
s = net->Link[linkIndex].Kc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if control level is a pressure, tank level or time value
|
||||
if (type == LOWLEVEL || type == HILEVEL)
|
||||
{
|
||||
if (nodeIndex > net->Njuncs) lvl = net->Node[nodeIndex].El + level / Ucf[ELEV];
|
||||
else lvl = net->Node[nodeIndex].El + level / Ucf[PRESSURE];
|
||||
}
|
||||
else if (type == TIMER || type == TIMEOFDAY)
|
||||
{
|
||||
t = (long)level;
|
||||
if (t < 0) return 202;
|
||||
}
|
||||
|
||||
// Assign values to control struct
|
||||
control->Link = linkIndex;
|
||||
control->Node = nodeIndex;
|
||||
control->Type = type;
|
||||
control->Status = status;
|
||||
control->Setting = s;
|
||||
control->Time = t;
|
||||
control->Grade = lvl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int getcomment(Network *network, int object, int index, char *comment)
|
||||
//----------------------------------------------------------------
|
||||
// Input: object = a type of network object
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 02/05/2023
|
||||
Last Updated: 04/29/2023
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -48,6 +48,9 @@ typedef int INT4;
|
||||
#define BIG 1.E10
|
||||
#define TINY 1.E-6
|
||||
#define MISSING -1.E10 // Missing value indicator
|
||||
#define SET_CLOSED -1.E10 // Link set closed indicator
|
||||
#define SET_OPEN 1.E10 // Link set open indicator
|
||||
|
||||
#define DIFFUS 1.3E-8 // Diffusivity of chlorine
|
||||
// @ 20 deg C (sq ft/sec)
|
||||
#define VISCOS 1.1E-5 // Kinematic viscosity of water
|
||||
|
||||
Reference in New Issue
Block a user