Rewrite of EN_setlinktype function (#305)

- Complete rewrite of EN_setlinktype with link index argument passed by reference
- New unit test of EN_setlinktype added
- New function EN_setlinknodes added
This commit is contained in:
Lew Rossman
2018-10-28 16:58:43 -04:00
parent 7d021d8b82
commit 8514929622
6 changed files with 211 additions and 16 deletions

View File

@@ -29,7 +29,7 @@ int runEpanet(char *finp, char *frpt)
if (!err) err = EN_solveH(ph); if (!err) err = EN_solveH(ph);
if (!err) err = EN_report(ph); if (!err) err = EN_report(ph);
EN_close(ph); EN_close(ph);
EN_deleteproject(ph); EN_deleteproject(&ph);
return err; return err;
} }
``` ```
@@ -149,6 +149,7 @@ Both network files are available [here](https://doi.org/10.23719/1375314).
|`ENgetruleID`|| |`ENgetruleID`||
|`ENinit`|| |`ENinit`||
|`ENsetheadcurveindex`|| |`ENsetheadcurveindex`||
|`ENsetlinknodes`||
|`ENsetlinktype`|| |`ENsetlinktype`||
|`ENaddnode`|| |`ENaddnode`||
|`ENaddlink`|| |`ENaddlink`||

View File

@@ -288,7 +288,8 @@ Public Const EN_G_CURVE = 4 ' General\default curve
Declare Function ENinit Lib "epanet2.dll" (ByVal rptFile As String, ByVal binOutFile As String, ByVal UnitsType As Long, ByVal HeadlossFormula As Long) As Long Declare Function ENinit Lib "epanet2.dll" (ByVal rptFile As String, ByVal binOutFile As String, ByVal UnitsType As Long, ByVal HeadlossFormula As Long) As Long
Declare Function ENsetheadcurveindex Lib "epanet2.dll" (ByVal pumpIndex As Long, ByVal curveIndex As Long) As Long Declare Function ENsetheadcurveindex Lib "epanet2.dll" (ByVal pumpIndex As Long, ByVal curveIndex As Long) As Long
Declare Function ENsetlinktype Lib "epanet2.dll" (ByVal index As Long, ByVal code As Long) As Long Declare Function ENsetlinknodes Lib "epanet2.dll" (ByVal index As Long, ByVal node1 As Long, ByVal node2 As Long) As Long
Declare Function ENsetlinktype Lib "epanet2.dll" (index As Long, ByVal code As Long) As Long
Declare Function ENaddnode Lib "epanet2.dll" (ByVal id As String, ByVal nodeType As Long) As Long Declare Function ENaddnode Lib "epanet2.dll" (ByVal id As String, ByVal nodeType As Long) As Long
Declare Function ENaddlink Lib "epanet2.dll" (ByVal id As String, ByVal linkType As Long, ByVal fromNode As String, ByVal toNode As String) As Long Declare Function ENaddlink Lib "epanet2.dll" (ByVal id As String, ByVal linkType As Long, ByVal fromNode As String, ByVal toNode As String) As Long
Declare Function ENdeletelink Lib "epanet2.dll" (ByVal nodeIndex As Long) As Long Declare Function ENdeletelink Lib "epanet2.dll" (ByVal nodeIndex As Long) As Long

View File

@@ -743,12 +743,12 @@ extern "C" {
/** /**
@brief Set the link type code for a specified link @brief Set the link type code for a specified link
@param id The id of a link @param[in,out] index The index of a link before [in] and after [out] the type change.
@param type The type code of the link. @param code The new type code of the link.
@return Error code @return Error code
@see EN_LinkType @see EN_LinkType
*/ */
int DLLEXPORT ENsetlinktype(char *id, EN_LinkType type); int DLLEXPORT ENsetlinktype(int *index, EN_LinkType code);
/** /**
@brief Get the indexes of a link's start- and end-nodes. @brief Get the indexes of a link's start- and end-nodes.
@@ -872,6 +872,16 @@ extern "C" {
*/ */
int DLLEXPORT ENsetlinkid(int index, char *newid); int DLLEXPORT ENsetlinkid(int index, char *newid);
/**
@brief Set the indexes of a link's start- and end-nodes.
@param index The index of a link (first link is index 1)
@param node1 The index of the link's start node (first node is index 1).
@param node2 The index of the link's end node (first node is index 1).
@return Error code
@see ENsetnodeid, ENsetlinkid
*/
int DLLEXPORT ENsetlinknodes(int index, int node1, int node2);
/** /**
@brief Set a property value for a link. @brief Set a property value for a link.
@param index The index of a link. First link is index 1. @param index The index of a link. First link is index 1.
@@ -1064,7 +1074,6 @@ extern "C" {
@see ENgetcurveindex ENsetcurve @see ENgetcurveindex ENsetcurve
*/ */
int DLLEXPORT ENaddcurve(char *id); int DLLEXPORT ENaddcurve(char *id);
/** /**
@brief Gets the number of premises, true actions, and false actions and the priority of an existing rule-based control. @brief Gets the number of premises, true actions, and false actions and the priority of an existing rule-based control.
@@ -1303,7 +1312,6 @@ extern "C" {
int DLLEXPORT EN_getlinkindex(EN_ProjectHandle ph, char *id, int *index); int DLLEXPORT EN_getlinkindex(EN_ProjectHandle ph, char *id, int *index);
int DLLEXPORT EN_getlinkid(EN_ProjectHandle ph, int index, char *id); int DLLEXPORT EN_getlinkid(EN_ProjectHandle ph, int index, char *id);
int DLLEXPORT EN_getlinktype(EN_ProjectHandle ph, int index, EN_LinkType *code); int DLLEXPORT EN_getlinktype(EN_ProjectHandle ph, int index, EN_LinkType *code);
int DLLEXPORT EN_setlinktype(EN_ProjectHandle ph, char *id, EN_LinkType type);
int DLLEXPORT EN_getlinknodes(EN_ProjectHandle ph, int index, int *node1, int *node2); int DLLEXPORT EN_getlinknodes(EN_ProjectHandle ph, int index, int *node1, int *node2);
int DLLEXPORT EN_getlinkvalue(EN_ProjectHandle ph, int index, EN_LinkProperty code, EN_API_FLOAT_TYPE *value); int DLLEXPORT EN_getlinkvalue(EN_ProjectHandle ph, int index, EN_LinkProperty code, EN_API_FLOAT_TYPE *value);
int DLLEXPORT EN_getcurve(EN_ProjectHandle ph, int curveIndex, char* id, int *nValues, EN_API_FLOAT_TYPE **xValues, EN_API_FLOAT_TYPE **yValues); int DLLEXPORT EN_getcurve(EN_ProjectHandle ph, int curveIndex, char* id, int *nValues, EN_API_FLOAT_TYPE **xValues, EN_API_FLOAT_TYPE **yValues);
@@ -1319,6 +1327,8 @@ extern "C" {
int DLLEXPORT EN_setnodeid(EN_ProjectHandle ph, int index, char *newid); int DLLEXPORT EN_setnodeid(EN_ProjectHandle ph, int index, char *newid);
int DLLEXPORT EN_setnodevalue(EN_ProjectHandle ph, int index, int code, EN_API_FLOAT_TYPE v); int DLLEXPORT EN_setnodevalue(EN_ProjectHandle ph, int index, int code, EN_API_FLOAT_TYPE v);
int DLLEXPORT EN_setlinkid(EN_ProjectHandle ph, int index, char *newid); int DLLEXPORT EN_setlinkid(EN_ProjectHandle ph, int index, char *newid);
int DLLEXPORT EN_setlinknodes(EN_ProjectHandle ph, int index, int node1, int node2);
int DLLEXPORT EN_setlinktype(EN_ProjectHandle ph, int *index, EN_LinkType code);
int DLLEXPORT EN_setlinkvalue(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);
int DLLEXPORT EN_addpattern(EN_ProjectHandle ph, char *id); int DLLEXPORT EN_addpattern(EN_ProjectHandle ph, char *id);
int DLLEXPORT EN_setpattern(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE *f, int len); int DLLEXPORT EN_setpattern(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE *f, int len);

View File

@@ -230,6 +230,8 @@ Public Const EN_CUSTOM = 2 ' user-defined custom curve
Declare Function ENsetnodeid Lib "epanet2.dll" (ByVal index As Int32, ByVal newid As String) As Int32 Declare Function ENsetnodeid Lib "epanet2.dll" (ByVal index As Int32, ByVal newid As String) As Int32
Declare Function ENsetnodevalue Lib "epanet2.dll" (ByVal Index As Int32, ByVal Code As Int32, ByVal Value As Single) As Int32 Declare Function ENsetnodevalue Lib "epanet2.dll" (ByVal Index As Int32, ByVal Code As Int32, ByVal Value As Single) As Int32
Declare Function ENsetlinkid Lib "epanet2.dll" (ByVal index As Int32, ByVal newid As String) As Int32 Declare Function ENsetlinkid Lib "epanet2.dll" (ByVal index As Int32, ByVal newid As String) As Int32
Declare Function ENsetlinknodes Lib "epanet2.dll" (ByVal index As Int32, ByVal node1 As Int32, ByVal node2 As Int32) As Int32
Declare Function ENsetlinktype Lib "epanet2.dll" (ByRef index As Int32, ByVal code As Int32) As Int32
Declare Function ENsetlinkvalue Lib "epanet2.dll" (ByVal Index As Int32, ByVal Code As Int32, ByVal Value As Single) As Int32 Declare Function ENsetlinkvalue Lib "epanet2.dll" (ByVal Index As Int32, ByVal Code As Int32, ByVal Value As Single) As Int32
Declare Function ENsetpattern Lib "epanet2.dll" (ByVal Index as Int32, ByRef F as Single, ByVal N as Int32) as Int32 Declare Function ENsetpattern Lib "epanet2.dll" (ByVal Index as Int32, ByRef F as Single, ByVal N as Int32) as Int32
Declare Function ENsetpatternvalue Lib "epanet2.dll" (ByVal Index As Int32, ByVal Period As Int32, ByVal Value As Single) As Int32 Declare Function ENsetpatternvalue Lib "epanet2.dll" (ByVal Index As Int32, ByVal Period As Int32, ByVal Value As Single) As Int32

View File

@@ -415,6 +415,14 @@ int DLLEXPORT ENsetlinkid(int index, char *newid) {
return EN_setlinkid(_defaultModel, index, newid); return EN_setlinkid(_defaultModel, index, newid);
} }
int DLLEXPORT ENsetlinknodes(int index, int node1, int node2) {
return EN_setlinknodes(_defaultModel, index, node1, node2);
}
int DLLEXPORT ENsetlinktype(int *index, EN_LinkType type) {
return EN_setlinktype(_defaultModel, index, type);
}
int DLLEXPORT ENsetlinkvalue(int index, int code, EN_API_FLOAT_TYPE v) { int DLLEXPORT ENsetlinkvalue(int index, int code, EN_API_FLOAT_TYPE v) {
return EN_setlinkvalue(_defaultModel, index, code, v); return EN_setlinkvalue(_defaultModel, index, code, v);
} }
@@ -567,10 +575,6 @@ int DLLEXPORT ENgetruleID(int indexRule, char* id){
return EN_getruleID(_defaultModel, indexRule, id); return EN_getruleID(_defaultModel, indexRule, id);
} }
int DLLEXPORT ENsetlinktype(char *id, EN_LinkType toType) {
return EN_setlinktype(_defaultModel, id, toType);
}
int DLLEXPORT ENaddnode(char *id, EN_NodeType nodeType) { int DLLEXPORT ENaddnode(char *id, EN_NodeType nodeType) {
return EN_addnode(_defaultModel, id, nodeType); return EN_addnode(_defaultModel, id, nodeType);
} }
@@ -3160,6 +3164,37 @@ int DLLEXPORT EN_setlinkid(EN_ProjectHandle ph, int index, char *newid)
return set_error(p->error_handle, 0); return set_error(p->error_handle, 0);
} }
int DLLEXPORT EN_setlinknodes(EN_ProjectHandle ph, int index, int node1, int node2)
{
int type;
EN_Project *p = (EN_Project*)ph;
EN_Network *net = &p->network;
// Check that nodes exist
if (node1 < 0 || node1 > net->Nnodes) return set_error(p->error_handle, 203);
if (node2 < 0 || node2 > net->Nnodes) return set_error(p->error_handle, 203);
// Check for illegal valve connection
type = net->Link[index].Type;
if (type == EN_PRV || type == EN_PSV || type == EN_FCV)
{
// Can't be connected to a fixed grade node
if (node1 > net->Njuncs ||
node2 > net->Njuncs) return set_error(p->error_handle, 219);
// Can't be connected to another pressure/flow control valve
if (!valvecheck(p, type, node1, node2))
{
return set_error(p->error_handle, 220);
}
}
// Assign new end nodes to link
net->Link[index].N1 = node1;
net->Link[index].N2 = node2;
return set_error(p->error_handle, 0);
}
int DLLEXPORT EN_setlinkvalue(EN_ProjectHandle ph, int index, int code, int DLLEXPORT EN_setlinkvalue(EN_ProjectHandle ph, int index, int code,
EN_API_FLOAT_TYPE v) EN_API_FLOAT_TYPE v)
@@ -4809,7 +4844,7 @@ int DLLEXPORT EN_setdemandname(EN_ProjectHandle ph, int nodeIndex, int demandIdx
} }
int DLLEXPORT EN_setdemandpattern(EN_ProjectHandle ph, int nodeIndex, int demandIdx, int patIndex) { int DLLEXPORT EN_setdemandpattern(EN_ProjectHandle ph, int nodeIndex, int demandIdx, int patIndex) {
EN_Project *pr = (EN_Project*)ph; EN_Project *pr = (EN_Project*)ph;
EN_Network *net = &pr->network; EN_Network *net = &pr->network;
@@ -4884,7 +4919,52 @@ int DLLEXPORT EN_getaveragepatternvalue(EN_ProjectHandle ph, int index, EN_API_F
return set_error(p->error_handle, 0); return set_error(p->error_handle, 0);
} }
int DLLEXPORT EN_setlinktype(EN_ProjectHandle ph, char *id, EN_LinkType toType) { int DLLEXPORT EN_setlinktype(EN_ProjectHandle ph, int *index, EN_LinkType type) {
int i = *index, n1, n2;
char id[MAXID+1];
char id1[MAXID+1];
char id2[MAXID+1];
int errcode;
EN_LinkType oldtype;
EN_Project *p = (EN_Project*)ph;
EN_Network *net = &p->network;
if (!p->Openflag) return set_error(p->error_handle, 102);
if (type < 0 || type > EN_GPV) return set_error(p->error_handle, 211);
// Check if a link with the id exists
if (i <= 0 || i > net->Nlinks) return set_error(p->error_handle, 204);
// Get the current type of the link
EN_getlinktype(p, i, &oldtype);
if (oldtype == type) return set_error(p->error_handle, 0);
// Pipe changing from or to having a check valve
if (oldtype <= EN_PIPE && type <= EN_PIPE)
{
net->Link[i].Type = type;
if (type == EN_CVPIPE) net->Link[i].Stat = OPEN;
return set_error(p->error_handle, 0);
}
// Get ID's of link & its end nodes
EN_getlinkid(ph, i, id);
EN_getlinknodes(ph, i, &n1, &n2);
EN_getnodeid(ph, n1, id1);
EN_getnodeid(ph, n2, id2);
// Delete the original link
EN_deletelink(ph, i);
// Create a new link of new type and old id
errcode = EN_addlink(ph, id, type, id1, id2);
// Find the index of this new link
EN_getlinkindex(ph, id, index);
return set_error(p->error_handle, errcode);
/***********************************************
int i; int i;
EN_LinkType fromType; EN_LinkType fromType;
@@ -4895,16 +4975,16 @@ int DLLEXPORT EN_setlinktype(EN_ProjectHandle ph, char *id, EN_LinkType toType)
if (!p->Openflag) if (!p->Openflag)
return set_error(p->error_handle, 102); return set_error(p->error_handle, 102);
/* Check if a link with the id exists */ // Check if a link with the id exists
if (EN_getlinkindex(p, id, &i) != 0) if (EN_getlinkindex(p, id, &i) != 0)
return set_error(p->error_handle, 215); return set_error(p->error_handle, 215);
/* Get the current type of the link */ // Get the current type of the link
EN_getlinktype(p, i, &fromType); EN_getlinktype(p, i, &fromType);
if (fromType == toType) if (fromType == toType)
return set_error(p->error_handle, 0); return set_error(p->error_handle, 0);
/* Change link from Pipe */ // Change link from Pipe
if (toType <= EN_PIPE) { if (toType <= EN_PIPE) {
net->Npipes++; net->Npipes++;
} else if (toType == EN_PUMP) { } else if (toType == EN_PUMP) {
@@ -4921,6 +5001,7 @@ int DLLEXPORT EN_setlinktype(EN_ProjectHandle ph, char *id, EN_LinkType toType)
net->Npumps--; net->Npumps--;
} }
return set_error(p->error_handle, 0); return set_error(p->error_handle, 0);
**********************************************/
} }
int DLLEXPORT EN_addnode(EN_ProjectHandle ph, char *id, EN_NodeType nodeType) { int DLLEXPORT EN_addnode(EN_ProjectHandle ph, char *id, EN_NodeType nodeType) {

100
tests/test_setlinktype.cpp Normal file
View File

@@ -0,0 +1,100 @@
// Test of ENsetlinktype EPANET API Function
#define _CRT_SECURE_NO_DEPRECATE
/*
This is a test for the API function that changes a link's type.
Two links in Net1.inp are changed: Pipe 113 is reversed with a CV added
and Pipe 121 is changed to a 100 psi PRV. After running the revised model,
at hour 0 the flow in Pipe 113 should be zero and the pressure at node 31
of the PRV 121 should be 100.
*/
#define BOOST_TEST_MODULE "toolkit"
#include <boost/test/included/unit_test.hpp>
#include <string>
#include "epanet2.h"
#define DATA_PATH_INP "./net1.inp"
#define DATA_PATH_RPT "./test.rpt"
#define DATA_PATH_OUT "./test.out"
using namespace std;
BOOST_AUTO_TEST_SUITE (test_toolkit)
BOOST_AUTO_TEST_CASE(test_setlinktype)
{
int error = 0;
int p113, n31, p121, n113_1, n113_2;
float q113 = 0.0f, p31 = 0.0f, diam;
EN_ProjectHandle ph = NULL;
EN_createproject(&ph);
std::string path_inp = std::string(DATA_PATH_INP);
std::string path_rpt = std::string(DATA_PATH_RPT);
std::string path_out = std::string(DATA_PATH_OUT);
error = EN_open(ph, path_inp.c_str(), path_rpt.c_str(), "");
BOOST_REQUIRE(error == 0);
// Change duration to 0
error = EN_settimeparam(ph, EN_DURATION, 0);
BOOST_REQUIRE(error == 0);
// Get indexes of pipe 113 and node 31
error = EN_getlinkindex(ph, (char *)"113", &p113);
BOOST_REQUIRE(error == 0);
error = EN_getnodeindex(ph, (char *)"31", &n31);
BOOST_REQUIRE(error == 0);
// Reverse pipe 113 and give it a check valve
error = EN_getlinknodes(ph, p113, &n113_1, &n113_2);
BOOST_REQUIRE(error == 0);
error = EN_setlinknodes(ph, p113, n113_2, n113_1);
BOOST_REQUIRE(error == 0);
error = EN_setlinktype(ph, &p113, EN_CVPIPE);
BOOST_REQUIRE(error == 0);
// Get index & diameter of pipe 121 connected to node 31
error = EN_getlinkindex(ph, (char *)"121", &p121);
BOOST_REQUIRE(error == 0);
error = EN_getlinkvalue(ph, p121, EN_DIAMETER, &diam);
BOOST_REQUIRE(error == 0);
// Replace it with a PRV
error = EN_setlinktype(ph, &p121, EN_PRV);
BOOST_REQUIRE(error == 0);
// Set diameter & setting of new PRV
error = EN_setlinkvalue(ph, p121, EN_INITSETTING, 100);
BOOST_REQUIRE(error == 0);
error = EN_setlinkvalue(ph, p121, EN_DIAMETER, diam);
BOOST_REQUIRE(error == 0);
// Solve for hydraulics
error = EN_solveH(ph);
BOOST_REQUIRE(error == 0);
// Get flow in link 113 and pressure at node 31
error = EN_getlinkvalue(ph, p113, EN_FLOW, &q113);
BOOST_REQUIRE(error == 0);
error = EN_getnodevalue(ph, n31, EN_PRESSURE, &p31);
BOOST_REQUIRE(error == 0);
// Require that link 113 flow be 0
q113 = fabs(q113);
BOOST_REQUIRE(q113 < 0.001);
// Require that node 31 pressure be 100
p31 = fabs(p31 - 100.0f);
BOOST_REQUIRE(p31 < 0.001);
// Close and delete project
error = EN_close(ph);
BOOST_REQUIRE(error == 0);
EN_deleteproject(&ph);
}
BOOST_AUTO_TEST_SUITE_END()