Merge pull request #265 from eladsal/dev-control
Add EN_addcontrol function
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -815,6 +815,18 @@ extern "C" {
|
||||
*/
|
||||
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);
|
||||
|
||||
160
src/epanet.c
160
src/epanet.c
@@ -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) {
|
||||
@@ -2619,7 +2760,6 @@ int DLLEXPORT EN_setcontrol(EN_ProjectHandle ph, int cindex, int ctype, int lind
|
||||
if (cindex < 1 || cindex > p->network.Ncontrols)
|
||||
return set_error(p->error_handle, 241);
|
||||
|
||||
|
||||
net = &p->network;
|
||||
|
||||
Node = net->Node;
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user