Merge pull request #265 from eladsal/dev-control

Add EN_addcontrol function
This commit is contained in:
Elad Salomons
2018-09-05 07:42:02 +03:00
committed by GitHub
5 changed files with 230 additions and 15 deletions

View File

@@ -78,7 +78,7 @@ Public Const EN_NEXTEVENT = 14
Public Const EN_ITERATIONS = 0
Public Const EN_RELATIVEERROR = 1
Public Const EN_MAXHEADERROR = 2
Public Const EN_MAXHEADERROR = 2
Public Const EN_MAXFLOWCHANGE = 3
Public Const EN_NODECOUNT = 0 'Component counts
@@ -234,14 +234,15 @@ Public Const EN_G_CURVE = 4 ' General\default curve
Declare Function ENgetcurve Lib "epanet2.dll" (ByVal curveIndex As Long, ByVal CurveID As String, nValues As Long, xValues As Any, yValues As Any) As Long
Declare Function ENgetheadcurveindex Lib "epanet2.dll" (ByVal pumpIndex As Long, curveIndex As Long) As Long
Declare Function ENgetpumptype Lib "epanet2.dll" (ByVal index As Long, PumpType As Long) As Long
Declare Function ENgetcurvetype Lib "epanet2.dll" (ByVal curveindex As Long, CurveType As Long) As Long
Declare Function ENgetcurvetype Lib "epanet2.dll" (ByVal curveIndex As Long, CurveType As Long) As Long
Declare Function ENgetversion Lib "epanet2.dll" (value As Long) As Long
Declare Function ENgetdemandmodel Lib "epanet2.dll" (type as long, pmin as Single, preq as Single, pexp as Single) As Long
Declare Function ENsetdemandmodel Lib "epanet2.dll" (ByVal type as long, ByVal pmin as Single, ByVal preq as Single, ByVal pexp as Single) As Long
Declare Function ENgetdemandmodel Lib "epanet2.dll" (mtype As Long, pmin As Single, preq As Single, pexp As Single) As Long
Declare Function ENsetdemandmodel Lib "epanet2.dll" (ByVal mtype As Long, ByVal pmin As Single, ByVal preq As Single, ByVal pexp As Single) As Long
Declare Function ENsetflowunits Lib "epanet2.dll" (ByVal code As Long) As Long
Declare Function ENaddcontrol Lib "epanet2.dll" (Cindex As Long, ByVal Ctype As Long, ByVal Lindex As Long, ByVal setting As Single, ByVal Nindex As Long, ByVal Level As Single) As Long
Declare Function ENsetcontrol Lib "epanet2.dll" (ByVal Cindex As Long, ByVal Ctype As Long, ByVal Lindex As Long, ByVal setting As Single, ByVal Nindex As Long, ByVal Level As Single) As Long
Declare Function ENsetnodevalue Lib "epanet2.dll" (ByVal index As Long, ByVal code As Long, ByVal value As Single) As Long
Declare Function ENsetlinkvalue Lib "epanet2.dll" (ByVal index As Long, ByVal code As Long, ByVal value As Single) As Long
@@ -254,7 +255,7 @@ Public Const EN_G_CURVE = 4 ' General\default curve
Declare Function ENsetqualtype Lib "epanet2.dll" (ByVal QualCode As Long, ByVal ChemName As String, ByVal ChemUnits As String, ByVal TraceNode As String) As Long
Declare Function ENgetqualinfo Lib "epanet2.dll" (QualCode As Long, ByVal ChemName As String, ByVal ChemUnits As String, TraceNode As Long) As Long
Declare Function ENsetbasedemand Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal DemandIndex As Long, ByVal BaseDemand As Single) As Long
Declare Function ENsetdemandpattern Lib "epanet2.dll" (ByVal Index As Long, ByVal DemandIndex As Long, ByVal PatIndex As Long) As Long
Declare Function ENsetdemandpattern Lib "epanet2.dll" (ByVal index As Long, ByVal DemandIndex As Long, ByVal PatIndex As Long) As Long
Declare Function ENgetcurveindex Lib "epanet2.dll" (ByVal id As String, index As Long) As Long
Declare Function ENgetcurveid Lib "epanet2.dll" (ByVal index As Long, ByVal id As String) As Long

View File

@@ -814,7 +814,19 @@ extern "C" {
@return Error code.
*/
int DLLEXPORT ENgetversion(int *version);
/**
@brief Specify parameters to add a new simple control
@param[out] cindex The index of the new control. First control is index 1.
@param ctype The type code to set for this control.
@param lindex The index of a link to control.
@param setting The control setting applied to the link.
@param nindex The index of a node used to control the link, or 0 for TIMER / TIMEOFDAY control.
@param level control point (tank level, junction pressure, or time in seconds).
@return Error code.
*/
int DLLEXPORT ENaddcontrol(int *cindex, int ctype, int lindex, EN_API_FLOAT_TYPE setting, int nindex, EN_API_FLOAT_TYPE level);
/**
@brief Specify parameters to define a simple control
@param cindex The index of the control to edit. First control is index 1.
@@ -1259,6 +1271,7 @@ extern "C" {
int DLLEXPORT EN_getversion(int *version);
int DLLEXPORT EN_addcontrol(EN_ProjectHandle ph, int *cindex, int ctype, int lindex, EN_API_FLOAT_TYPE setting, int nindex, EN_API_FLOAT_TYPE level);
int DLLEXPORT EN_setcontrol(EN_ProjectHandle ph, int cindex, int ctype, int lindex, EN_API_FLOAT_TYPE setting, int nindex, EN_API_FLOAT_TYPE level);
int DLLEXPORT EN_setnodevalue(EN_ProjectHandle ph, int index, int code, EN_API_FLOAT_TYPE v);
int DLLEXPORT EN_setlinkvalue(EN_ProjectHandle ph, int index, int code, EN_API_FLOAT_TYPE v);

View File

@@ -403,6 +403,13 @@ int DLLEXPORT ENsetcontrol(int cindex, int ctype, int lindex,
level);
}
int DLLEXPORT ENaddcontrol(int *cindex, int ctype, int lindex,
EN_API_FLOAT_TYPE setting, int nindex,
EN_API_FLOAT_TYPE level) {
return EN_addcontrol(_defaultModel, cindex, ctype, lindex, setting, nindex,
level);
}
int DLLEXPORT ENsetnodevalue(int index, int code, EN_API_FLOAT_TYPE v) {
return EN_setnodevalue(_defaultModel, index, code, v);
}
@@ -2374,7 +2381,7 @@ int DLLEXPORT EN_getlinkvalue(EN_ProjectHandle ph, int index, EN_LinkProperty co
case EN_INITSETTING:
if (Link[index].Type == EN_PIPE || Link[index].Type == EN_CVPIPE)
return set_error(p->error_handle, ENgetlinkvalue(index, EN_ROUGHNESS, value));
return set_error(p->error_handle, EN_getlinkvalue(p, index, EN_ROUGHNESS, value));
v = Link[index].Kc;
switch (Link[index].Type) {
case EN_PRV:
@@ -2477,7 +2484,7 @@ int DLLEXPORT EN_getlinkvalue(EN_ProjectHandle ph, int index, EN_LinkProperty co
case EN_SETTING:
if (Link[index].Type == EN_PIPE || Link[index].Type == EN_CVPIPE) {
return set_error(p->error_handle, ENgetlinkvalue(index, EN_ROUGHNESS, value));
return set_error(p->error_handle, EN_getlinkvalue(p, index, EN_ROUGHNESS, value));
}
if (LinkSetting[index] == MISSING) {
v = 0.0;
@@ -2593,6 +2600,140 @@ int DLLEXPORT EN_getcurve(EN_ProjectHandle ph, int curveIndex, char *id, int *nV
----------------------------------------------------------------
*/
int DLLEXPORT EN_addcontrol(EN_ProjectHandle ph, int *cindex, int ctype, int lindex,
EN_API_FLOAT_TYPE setting, int nindex,
EN_API_FLOAT_TYPE level) {
char status = ACTIVE;
int i, n;
long t = 0, nControls;
double s = setting, lvl = level;
EN_Network *net;
Snode *Node;
Slink *Link;
Scontrol *Control;
Scontrol *tmpControl;
int Nnodes;
int Njuncs;
int Nlinks;
double *Ucf;
EN_Project *p = (EN_Project*)ph;
parser_data_t *par = &p->parser;
/* Check that input file opened */
if (!p->Openflag)
return set_error(p->error_handle, 102);
net = &p->network;
Node = net->Node;
Link = net->Link;
Control = net->Control;
Nnodes = net->Nnodes;
Njuncs = net->Njuncs;
Nlinks = net->Nlinks;
nControls = net->Ncontrols;
Ucf = p->Ucf;
/* Check that controlled link exists */
if (lindex < 0 || lindex > Nlinks)
return set_error(p->error_handle, 204);
/* Cannot control check valve. */
if (Link[lindex].Type == EN_CVPIPE)
return set_error(p->error_handle, 207);
/* Check for valid parameters */
if (ctype < 0 || ctype > EN_TIMEOFDAY)
return set_error(p->error_handle, 251);
if (ctype == EN_LOWLEVEL || ctype == EN_HILEVEL) {
if (nindex < 1 || nindex > Nnodes)
return set_error(p->error_handle, 203);
} else
nindex = 0;
if (s < 0.0 || lvl < 0.0)
return set_error(p->error_handle, 202);
/* Adjust units of control parameters */
switch (Link[lindex].Type) {
case EN_PRV:
case EN_PSV:
case EN_PBV:
s /= Ucf[PRESSURE];
break;
case EN_FCV:
s /= Ucf[FLOW];
break;
case EN_GPV:
if (s == 0.0)
status = CLOSED;
else if (s == 1.0)
status = OPEN;
else
return set_error(p->error_handle, 202);
s = Link[lindex].Kc;
break;
case EN_PIPE:
case EN_PUMP:
status = OPEN;
if (s == 0.0)
status = CLOSED;
default:
break;
}
if (ctype == LOWLEVEL || ctype == HILEVEL) {
if (nindex > Njuncs)
lvl = Node[nindex].El + level / Ucf[ELEV];
else
lvl = Node[nindex].El + level / Ucf[PRESSURE];
}
if (ctype == TIMER)
t = (long)ROUND(lvl);
if (ctype == TIMEOFDAY)
t = (long)ROUND(lvl) % SECperDAY;
//new control is good
/* Allocate memory for a new array of controls */
n = nControls + 1;
tmpControl = (Scontrol *)calloc(n + 1, sizeof(Scontrol));
if (tmpControl == NULL)
return set_error(p->error_handle, 101);
/* Copy contents of old controls array to new one */
for (i = 0; i <= nControls; i++) {
tmpControl[i].Type = Control[i].Type;
tmpControl[i].Link = Control[i].Link;
tmpControl[i].Node = Control[i].Node;
tmpControl[i].Status = Control[i].Status;
tmpControl[i].Setting = Control[i].Setting;
tmpControl[i].Grade = Control[i].Grade;
tmpControl[i].Time = Control[i].Time;
}
/* Add the new control to the new array of controls */
tmpControl[n].Type = (char)ctype;
tmpControl[n].Link = lindex;
tmpControl[n].Node = nindex;
tmpControl[n].Status = status;
tmpControl[n].Setting = s;
tmpControl[n].Grade = lvl;
tmpControl[n].Time = t;
// Replace old control array with new one
free(Control);
net->Control = tmpControl;
net->Ncontrols = n;
par->MaxControls = n;
// return the new control index
*cindex = n;
return set_error(p->error_handle, 0);
}
int DLLEXPORT EN_setcontrol(EN_ProjectHandle ph, int cindex, int ctype, int lindex,
EN_API_FLOAT_TYPE setting, int nindex,
EN_API_FLOAT_TYPE level) {
@@ -2618,7 +2759,6 @@ int DLLEXPORT EN_setcontrol(EN_ProjectHandle ph, int cindex, int ctype, int lind
/* Check that control exists */
if (cindex < 1 || cindex > p->network.Ncontrols)
return set_error(p->error_handle, 241);
net = &p->network;
@@ -3067,7 +3207,7 @@ int DLLEXPORT EN_setlinkvalue(EN_ProjectHandle ph, int index, int code,
if (value < 0.0)
return set_error(p->error_handle, 202);
if (Link[index].Type == EN_PIPE || Link[index].Type == EN_CVPIPE)
return set_error(p->error_handle, ENsetlinkvalue(index, EN_ROUGHNESS, v));
return set_error(p->error_handle, EN_setlinkvalue(p, index, EN_ROUGHNESS, v));
else {
switch (Link[index].Type) {
case EN_PUMP:
@@ -3261,7 +3401,7 @@ int DLLEXPORT EN_addcurve(EN_ProjectHandle ph, char *id) {
if (!p->Openflag)
return set_error(p->error_handle, 102);
if (ENgetcurveindex(id, &i) == 0)
if (EN_getcurveindex(p, id, &i) == 0)
return set_error(p->error_handle, 215);
/* Check that id name is not too long */
@@ -3537,7 +3677,7 @@ int DLLEXPORT EN_setoption(EN_ProjectHandle ph, int code, EN_API_FLOAT_TYPE v)
n = 1.0 / value;
ucf = pow(Ucf[FLOW], n) / Ucf[PRESSURE];
for (i = 1; i <= Njuncs; i++) {
j = ENgetnodevalue(i, EN_EMITTER, &v);
j = EN_getnodevalue(p, i, EN_EMITTER, &v);
Ke = v;
if (j == 0 && Ke > 0.0)
Node[i].Ke = ucf / pow(Ke, n);
@@ -4644,7 +4784,7 @@ int DLLEXPORT EN_setlinktype(EN_ProjectHandle ph, char *id, EN_LinkType toType)
return set_error(p->error_handle, 215);
/* Get the current type of the link */
ENgetlinktype(i, &fromType);
EN_getlinktype(p, i, &fromType);
if (fromType == toType)
return set_error(p->error_handle, 0);
@@ -4688,7 +4828,7 @@ int DLLEXPORT EN_addnode(EN_ProjectHandle ph, char *id, EN_NodeType nodeType) {
/* Check if a node with same id already exists */
if (!p->Openflag)
return set_error(p->error_handle, 102);
if (ENgetnodeindex(id, &i) == 0)
if (EN_getnodeindex(p, id, &i) == 0)
return set_error(p->error_handle, 215);
/* Check that id name is not too long */
@@ -4825,6 +4965,7 @@ int DLLEXPORT EN_addnode(EN_ProjectHandle ph, char *id, EN_NodeType nodeType) {
node->C0 = 0;
node->Ke = 0;
node->Rpt = 0;
strcpy(node->Comment, "");
coord->HaveCoords = FALSE;
coord->X = 0;
@@ -4850,7 +4991,7 @@ int DLLEXPORT EN_addlink(EN_ProjectHandle ph, char *id, EN_LinkType linkType, ch
/* Check if a link with same id already exists */
if (!p->Openflag)
return set_error(p->error_handle, 102);
if (ENgetlinkindex(id, &i) == 0)
if (EN_getlinkindex(p, id, &i) == 0)
return set_error(p->error_handle, 215);
/* Lookup the from and to nodes */
@@ -4935,6 +5076,7 @@ int DLLEXPORT EN_addlink(EN_ProjectHandle ph, char *id, EN_LinkType linkType, ch
link->R = 0;
link->Rc = 0;
link->Rpt = 0;
strcpy(link->Comment, "");
ENHashTableInsert(net->LinkHashTable, link->ID, n);
return set_error(p->error_handle, 0);

View File

@@ -260,4 +260,62 @@ BOOST_FIXTURE_TEST_CASE(test_addpattern, Fixture)
BOOST_REQUIRE(pat_index == n_patterns_2);
}
BOOST_FIXTURE_TEST_CASE(test_add_control, Fixture)
{
int flag = 00;
long t, tstep;
float h1, h2;
int Cindex;
// run with original controls
error = EN_openH(ph);
BOOST_REQUIRE(error == 0);
error = EN_initH(ph, flag);
BOOST_REQUIRE(error == 0);
do {
error = EN_runH(ph, &t);
BOOST_REQUIRE(error == 0);
error = EN_getnodevalue(ph, 11, EN_HEAD, &h1); // get the tank head
BOOST_REQUIRE(error == 0);
error = EN_nextH(ph, &tstep);
BOOST_REQUIRE(error == 0);
} while (tstep > 0);
error = EN_closeH(ph);
BOOST_REQUIRE(error == 0);
// disable current controls
error = EN_setcontrol(ph, 1, 0, 0, 0, 0, 0);
BOOST_REQUIRE(error == 0);
error = EN_setcontrol(ph, 2, 1, 0, 0, 0, 0);
BOOST_REQUIRE(error == 0);
// add new controls
error = EN_addcontrol(ph, &Cindex, 0, 13, 1, 11, 110);
BOOST_REQUIRE(error == 0);
BOOST_REQUIRE(Cindex == 3);
error = EN_addcontrol(ph, &Cindex, 1, 13, 0, 11, 140);
BOOST_REQUIRE(error == 0);
BOOST_REQUIRE(Cindex == 4);
// run with new controls
error = EN_openH(ph);
BOOST_REQUIRE(error == 0);
error = EN_initH(ph, flag);
BOOST_REQUIRE(error == 0);
do {
error = EN_runH(ph, &t);
BOOST_REQUIRE(error == 0);
error = EN_getnodevalue(ph, 11, EN_HEAD, &h2); // get the tank head
BOOST_REQUIRE(error == 0);
error = EN_nextH(ph, &tstep);
BOOST_REQUIRE(error == 0);
} while (tstep > 0);
error = EN_closeH(ph);
BOOST_REQUIRE(error == 0);
BOOST_REQUIRE(h1 == h2); // end head should be the same with new controls
}
BOOST_AUTO_TEST_SUITE_END()

View File

@@ -41,6 +41,7 @@ EXPORTS
ENsaveH = _ENsaveH@0
ENsavehydfile = _ENsavehydfile@4
ENsaveinpfile = _ENsaveinpfile@4
ENaddcontrol = _ENaddcontrol@24
ENsetcontrol = _ENsetcontrol@24
ENsetlinkvalue = _ENsetlinkvalue@12
ENsetnodevalue = _ENsetnodevalue@12