diff --git a/ReleaseNotes2_2.md b/ReleaseNotes2_2.md index 10ca70a..4c16e30 100644 --- a/ReleaseNotes2_2.md +++ b/ReleaseNotes2_2.md @@ -1,4 +1,3 @@ - Release Notes for EPANET 2.2 (Draft) ============================ @@ -29,7 +28,7 @@ int runEpanet(char *finp, char *frpt) if (!err) err = EN_solveH(ph); if (!err) err = EN_report(ph); EN_close(ph); - EN_deleteproject(ph); + EN_deleteproject(&ph); return err; } ``` diff --git a/include/epanet2.bas b/include/epanet2.bas index c4516f1..8d29b59 100644 --- a/include/epanet2.bas +++ b/include/epanet2.bas @@ -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 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 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 diff --git a/include/epanet2.h b/include/epanet2.h index 1593783..2601335 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -67,6 +67,9 @@ // --- Define the EPANET toolkit constants +#define EN_MAXID 31 /**< Max. # characters in ID name */ +#define EN_MAXMSG 255 /**< Max. # characters in message text */ + /// Node property codes typedef enum { EN_ELEVATION = 0, /**< Node Elevation */ @@ -740,12 +743,12 @@ extern "C" { /** @brief Set the link type code for a specified link - @param id The id of a link - @param type The type code of the link. + @param[in,out] index The index of a link before [in] and after [out] the type change. + @param code The new type code of the link. @return Error code @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. @@ -869,6 +872,16 @@ extern "C" { */ 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. @param index The index of a link. First link is index 1. @@ -1061,7 +1074,6 @@ extern "C" { @see ENgetcurveindex ENsetcurve */ 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. @@ -1300,7 +1312,6 @@ extern "C" { 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_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_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); @@ -1316,6 +1327,8 @@ extern "C" { 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_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_addpattern(EN_ProjectHandle ph, char *id); int DLLEXPORT EN_setpattern(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE *f, int len); diff --git a/include/epanet2.vb b/include/epanet2.vb index 5898dfd..2c6d5f3 100644 --- a/include/epanet2.vb +++ b/include/epanet2.vb @@ -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 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 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 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 diff --git a/src/epanet.c b/src/epanet.c index 00fe533..50618cc 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -144,43 +144,6 @@ void errorLookup(int errcode, char *errmsg, int len); *****************************************************************/ -int runconcurrent(EN_ProjectHandle ph, const char *inputfile, const char *reportfile, - const char *outputfile, void(*pviewprog)(char *)) -{ - long t, tstep_h, tstep_q; - int errcode = 0; - - EN_Project *p = NULL; - - - ERRCODE(EN_open(ph, inputfile, reportfile, outputfile)); - p = (EN_Project*)(ph); - p->viewprog = pviewprog; - - ERRCODE(EN_openH(ph)); - ERRCODE(EN_initH(ph, EN_SAVE)); - - ERRCODE(EN_openQ(ph)); - ERRCODE(EN_initQ(ph, EN_SAVE)); - - do { - ERRCODE(EN_runH(ph, &t)); - ERRCODE(EN_runQ(ph, &t)); - - ERRCODE(EN_nextH(ph, &tstep_h)); - ERRCODE(EN_nextQ(ph, &tstep_q)); - - } while (tstep_h > 0); - - ERRCODE(EN_closeH(ph)); - ERRCODE(EN_closeQ(ph)); - - ERRCODE(EN_report(ph)); - ERRCODE(EN_close(ph)); - - return errcode; -} - /*------------------------------------------------------------------------ ** Input: f1 = pointer to name of input file ** f2 = pointer to name of report file @@ -201,14 +164,17 @@ int runconcurrent(EN_ProjectHandle ph, const char *inputfile, const char *report int DLLEXPORT ENepanet(const char *f1, const char *f2, const char *f3, void (*pviewprog)(char *)) { int errcode = 0; + int warncode = 0; EN_Project *p = NULL; ERRCODE(EN_createproject(&_defaultModel)); ERRCODE(EN_runproject(_defaultModel, f1, f2, f3, pviewprog)); + if (errcode < 100) warncode = errcode; ERRCODE(EN_deleteproject(&_defaultModel)); + if (warncode) errcode = MAX(errcode, warncode); return (errcode); } @@ -449,6 +415,14 @@ int DLLEXPORT ENsetlinkid(int index, char *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) { return EN_setlinkvalue(_defaultModel, index, code, v); } @@ -601,10 +575,6 @@ int DLLEXPORT ENgetruleID(int indexRule, char* 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) { return EN_addnode(_defaultModel, id, nodeType); } @@ -682,7 +652,8 @@ int DLLEXPORT EN_runproject(EN_ProjectHandle ph, const char *f1, const char *f2, ERRCODE(EN_report(ph)); EN_close(ph); - + + if (p->Warnflag) errcode = MAX(errcode, p->Warnflag); return errcode; } @@ -792,7 +763,6 @@ int DLLEXPORT EN_open(EN_ProjectHandle ph, const char *f1, const char *f2, const writelogo(p); /* Find network size & allocate memory for data */ - writecon(FMT02); writewin(p->viewprog, FMT100); ERRCODE(netsize(p)); ERRCODE(allocdata(p)); @@ -920,19 +890,14 @@ int DLLEXPORT EN_solveH(EN_ProjectHandle ph) if (!errcode) { /* Initialize hydraulics */ errcode = EN_initH(ph, EN_SAVE); - writecon(FMT14); /* Analyze each hydraulic period */ if (!errcode) do { /* Display progress message */ - - /*** Updated 6/24/02 ***/ sprintf(p->Msg, "%-10s", clocktime(p->report.Atime, p->time_options.Htime)); - - writecon(p->Msg); sprintf(p->Msg, FMT101, p->report.Atime); writewin(p->viewprog, p->Msg); @@ -940,16 +905,10 @@ int DLLEXPORT EN_solveH(EN_ProjectHandle ph) tstep = 0; ERRCODE(EN_runH(ph, &t)); ERRCODE(EN_nextH(ph, &tstep)); - /*** Updated 6/24/02 ***/ - writecon("\b\b\b\b\b\b\b\b\b\b"); } while (tstep > 0); } /* Close hydraulics solver */ - - /*** Updated 6/24/02 ***/ - writecon("\b\b\b\b\b\b\b\b "); - EN_closeH(ph); errcode = MAX(errcode, p->Warnflag); @@ -1190,24 +1149,15 @@ int DLLEXPORT EN_solveQ(EN_ProjectHandle ph) { if (!errcode) { /* Initialize WQ */ errcode = EN_initQ(ph, EN_SAVE); - if (p->quality.Qualflag) - writecon(FMT15); - else { - writecon(FMT16); - writewin(p->viewprog, FMT103); - } + if (!p->quality.Qualflag) writewin(p->viewprog, FMT106); /* Analyze each hydraulic period */ if (!errcode) do { /* Display progress message */ - - /*** Updated 6/24/02 ***/ sprintf(p->Msg, "%-10s", clocktime(p->report.Atime, p->time_options.Htime)); - - writecon(p->Msg); if (p->quality.Qualflag) { sprintf(p->Msg, FMT102, p->report.Atime); writewin(p->viewprog, p->Msg); @@ -1217,17 +1167,10 @@ int DLLEXPORT EN_solveQ(EN_ProjectHandle ph) { tstep = 0; ERRCODE(EN_runQ(ph, &t)); ERRCODE(EN_nextQ(ph, &tstep)); - - /*** Updated 6/24/02 ***/ - writecon("\b\b\b\b\b\b\b\b\b\b"); - } while (tstep > 0); } /* Close WQ solver */ - - /*** Updated 6/24/02 ***/ - writecon("\b\b\b\b\b\b\b\b "); EN_closeQ(ph); return set_error(p->error_handle, errcode); } @@ -1355,6 +1298,7 @@ int DLLEXPORT EN_report(EN_ProjectHandle ph) { /* Check if results saved to binary output file */ if (!p->save_options.SaveQflag) return set_error(p->error_handle, 106); + writewin(p->viewprog, FMT103); errcode = writereport(p); if (errcode) errmsg(p, errcode); @@ -3220,6 +3164,37 @@ int DLLEXPORT EN_setlinkid(EN_ProjectHandle ph, int index, char *newid) 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, EN_API_FLOAT_TYPE v) @@ -3835,6 +3810,7 @@ int DLLEXPORT EN_setoption(EN_ProjectHandle ph, int code, EN_API_FLOAT_TYPE v) for (demand = node->D; demand != NULL; demand = demand->next) { if (demand->Pat == tmpPat) { demand->Pat = (int)value; + strcpy(demand->Name, ""); } } } @@ -3973,7 +3949,7 @@ int DLLEXPORT EN_setheadcurveindex(EN_ProjectHandle ph, int index, int curveinde pump->Ptype = NOCURVE; pump->Hcurve = curveindex; // update pump parameters - getpumpparams(p); + updatepumpparams(p, pIdx); // convert units if (pump->Ptype == POWER_FUNC) { pump->H0 /= Ucf[HEAD]; @@ -4063,20 +4039,16 @@ int openfiles(EN_Project *p, const char *f1, const char *f2, const char *f3) /* Check that file names are not identical */ if (strcomp(f1, f2) || strcomp(f1, f3) || (strcomp(f2, f3) && (strlen(f2) > 0 || strlen(f3) > 0))) { - writecon(FMT04); return 301; } /* Attempt to open input and report files */ if ((par->InFile = fopen(f1, "rt")) == NULL) { - writecon(FMT05); - writecon(f1); return 302; } if (strlen(f2) == 0) rep->RptFile = stdout; else if ((rep->RptFile = fopen(f2, "wt")) == NULL) { - writecon(FMT06); return 303; } @@ -4207,7 +4179,6 @@ int openoutfile(EN_Project *p) if (out->Outflag == SAVE) { if ((out->OutFile = fopen(out->OutFname, "w+b")) == NULL) { - writecon(FMT07); errcode = 304; } } @@ -4217,7 +4188,6 @@ int openoutfile(EN_Project *p) getTmpName(p, out->OutFname); if ((out->OutFile = fopen(out->OutFname, "w+b")) == NULL) { - writecon(FMT08); errcode = 304; } } @@ -4714,6 +4684,7 @@ char *geterrmsg(int errcode, char *msg) { switch (errcode) { /* Warnings */ #define DAT(code,enumer,string) case code: strcpy(msg, string); break; +//#define DAT(code,enumer,string) case code: sprintf(msg, "Error %d: %s", code, string); break; #include "errors.dat" #undef DAT default: @@ -4732,26 +4703,12 @@ void errmsg(EN_Project *p, int errcode) { if (errcode == 309) /* Report file write error - */ { /* Do not write msg to file. */ - writecon("\n "); - writecon(geterrmsg(errcode,p->Msg)); + } else if (p->report.RptFile != NULL && p->report.Messageflag) { writeline(p, geterrmsg(errcode,p->Msg)); } } -void writecon(const char *s) -/*---------------------------------------------------------------- -** Input: text string -** Output: none -** Purpose: writes string of characters to console -**---------------------------------------------------------------- -*/ -{ - - fprintf(stdout, "%s", s); - fflush(stdout); -} - void writewin(void (*vp)(char *), char *s) /*---------------------------------------------------------------- ** Input: text string @@ -4871,8 +4828,6 @@ int DLLEXPORT EN_setdemandname(EN_ProjectHandle ph, int nodeIndex, int demandIdx const int Nnodes = net->Nnodes; const int Njuncs = net->Njuncs; - double *Ucf = pr->Ucf; - Pdemand d; int n = 1; /* Check for valid arguments */ @@ -4889,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) { - + EN_Project *pr = (EN_Project*)ph; EN_Network *net = &pr->network; @@ -4964,43 +4919,50 @@ int DLLEXPORT EN_getaveragepatternvalue(EN_ProjectHandle ph, int index, EN_API_F return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setlinktype(EN_ProjectHandle ph, char *id, EN_LinkType toType) { - int i; - EN_LinkType fromType; - - EN_Project *p = (EN_Project*)ph; +int DLLEXPORT EN_setlinktype(EN_ProjectHandle ph, int *index, EN_LinkType type) { - EN_Network *net = &p->network; + 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 (!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 (EN_getlinkindex(p, id, &i) != 0) - return set_error(p->error_handle, 215); + // 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, &fromType); - if (fromType == toType) - return set_error(p->error_handle, 0); + // Get the current type of the link + EN_getlinktype(p, i, &oldtype); + if (oldtype == type) return set_error(p->error_handle, 0); - /* Change link from Pipe */ - if (toType <= EN_PIPE) { - net->Npipes++; - } else if (toType == EN_PUMP) { - net->Npumps++; - net->Pump[net->Npumps].Link = i; - } else { - net->Nvalves++; - net->Valve[net->Nvalves].Link = i; - } + // 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); + } - if (fromType <= EN_PIPE) { - net->Npipes--; - } else if (fromType == EN_PUMP) { - net->Npumps--; - } - 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 DLLEXPORT EN_addnode(EN_ProjectHandle ph, char *id, EN_NodeType nodeType) { @@ -5047,6 +5009,7 @@ int DLLEXPORT EN_addnode(EN_ProjectHandle ph, char *id, EN_NodeType nodeType) { demand = (struct Sdemand *)malloc(sizeof(struct Sdemand)); demand->Base = 0.0; demand->Pat = hyd->DefPat; // Use default pattern + strcpy(demand->Name, ""); demand->next = NULL; node->D = demand; diff --git a/src/funcs.h b/src/funcs.h index 8d267f9..bf1d913 100755 --- a/src/funcs.h +++ b/src/funcs.h @@ -52,7 +52,6 @@ int findvalve(EN_Network *n, int); /* Find valve index from node int findpump(EN_Network *n, int); /* Find pump index from node index */ // (AH) char *geterrmsg(int errcode, char *msg); /* Gets text of error message */ void errmsg(EN_Project *p, int); /* Reports program error */ -void writecon(const char *); /* Writes text to console */ void writewin(void (*vp)(char *), char *); /* Passes text to calling app */ /* ------- INPUT1.C --------------------*/ @@ -75,6 +74,7 @@ int addcurve(parser_data_t *par, char *); /* Adds curve to data base STmplist *findID(char *, STmplist *); /* Locates ID on linked list */ int unlinked(EN_Project *pr); /* Checks for unlinked nodes */ int getpumpparams(EN_Project *pr); /* Computes pump curve coeffs.*/ +int updatepumpparams(EN_Project *pr, int); // Updates pump curve coeffs. int getpatterns(EN_Project *pr); /* Gets pattern data from list*/ int getcurves(EN_Project *pr); /* Gets curve data from list */ int findmatch(char *, char *[]); /* Finds keyword in line */ diff --git a/src/input1.c b/src/input1.c index 1e59b80..89a4e1d 100644 --- a/src/input1.c +++ b/src/input1.c @@ -356,6 +356,7 @@ void adjustdata(EN_Project *pr) for (demand = node->D; demand != NULL; demand = demand->next) { if (demand->Pat == 0) { demand->Pat = hyd->DefPat; + strcpy(demand->Name, ""); } } } diff --git a/src/input2.c b/src/input2.c index d141d72..374ca87 100644 --- a/src/input2.c +++ b/src/input2.c @@ -40,10 +40,10 @@ The following utility functions are all called from INPUT3.C #define MAXERRS 10 /* Max. input errors reported */ - /* Defined in enumstxt.h in EPANET.C */ extern char *SectTxt[]; /* Input section keywords */ + int netsize(EN_Project *pr) /* **-------------------------------------------------------------- @@ -206,9 +206,10 @@ int readdata(EN_Project *pr) /* Check if max. length exceeded */ if (strlen(line) >= MAXLINE) { - char errMsg[MAXMSG+1]; - EN_geterror(214, errMsg, MAXMSG); - sprintf(pr->Msg, "%s section: %s", errMsg, SectTxt[sect]); +// char errMsg[MAXMSG+1]; +// EN_geterror(214, errMsg, MAXMSG); +// sprintf(pr->Msg, "%s section: %s", errMsg, SectTxt[sect]); + sprintf(pr->Msg, "%s section: %s", geterrmsg(214, pr->Msg), SectTxt[sect]); writeline(pr, pr->Msg); writeline(pr, line); errsum++; @@ -363,101 +364,121 @@ int getpumpparams(EN_Project *pr) **------------------------------------------------------------- ** Input: none ** Output: returns error code -** Purpose: computes & checks pump curve parameters +** Purpose: computes pump curve coefficients for all pumps **-------------------------------------------------------------- */ { - int i, j = 0, k, m, n = 0; - double a, b, c, h0 = 0.0, h1 = 0.0, h2 = 0.0, q1 = 0.0, q2 = 0.0; - char errMsg[MAXMSG+1]; - Spump *pump; - Slink *link; - Scurve *curve; - - EN_Network *net = &pr->network; - - for (i = 1; i <= net->Npumps; i++) { - pump = &net->Pump[i]; - k = pump->Link; - link = &net->Link[k]; - if (pump->Ptype == CONST_HP) { /* Constant Hp pump */ - pump->H0 = 0.0; - pump->R = -8.814 * link->Km; - pump->N = -1.0; - pump->Hmax = BIG; /* No head limit */ - pump->Qmax = BIG; /* No flow limit */ - pump->Q0 = 1.0; /* Init. flow = 1 cfs */ - continue; - } - else if (pump->Ptype == NOCURVE) { /* Pump curve specified */ - j = pump->Hcurve; /* Get index of head curve */ - if (j == 0) { /* Error: No head curve */ - EN_geterror(226, errMsg, MAXMSG); - sprintf(pr->Msg, "%s link: %s", errMsg, link->ID); - writeline(pr, pr->Msg); - return (200); - } - curve = &net->Curve[j]; - curve->Type = P_CURVE; - n = curve->Npts; - if (n == 1) { /* Only a single h-q point supplied so use generic */ - pump->Ptype = POWER_FUNC; /* power function curve. */ - q1 = curve->X[0]; - h1 = curve->Y[0]; - h0 = 1.33334 * h1; - q2 = 2.0 * q1; - h2 = 0.0; - } else if (n == 3 && curve->X[0] == 0.0) /* 3 h-q points supplied with */ - { /* shutoff head so use fitted */ - pump->Ptype = POWER_FUNC; /* power function curve. */ - h0 = curve->Y[0]; - q1 = curve->X[1]; - h1 = curve->Y[1]; - q2 = curve->X[2]; - h2 = curve->Y[2]; - } - else { // use a custom curve, referenced by ID - pump->Ptype = CUSTOM; /* Else use custom pump curve.*/ - // at this point, j is set to that curve's index. - } - - /* Compute shape factors & limits of power function pump curves */ - if (pump->Ptype == POWER_FUNC) { - if (!powercurve(h0, h1, h2, q1, q2, &a, &b, &c)) { /* Error: Invalid curve */ - EN_geterror(227, errMsg, MAXMSG); - sprintf(pr->Msg, "%s link: %s", errMsg, link->ID); - writeline(pr, pr->Msg); - return (200); - } else { - pump->H0 = -a; - pump->R = -b; - pump->N = c; - pump->Q0 = q1; - pump->Qmax = pow((-a / b), (1.0 / c)); - pump->Hmax = h0; + int i, k, errcode = 0; + EN_Network *net = &pr->network; + + for (i = 1; i <= net->Npumps; i++) + { + errcode = updatepumpparams(pr, i); + if (errcode) + { + k = net->Pump[i].Link; + sprintf(pr->Msg, "%s link: %s", geterrmsg(errcode, pr->Msg), + net->Link[k].ID); + writeline(pr, pr->Msg); + return 200; } - } + } + return 0; +} + +int updatepumpparams(EN_Project *pr, int pumpindex) +/* +**------------------------------------------------------------- +** Input: pumpindex = index of a pump +** Output: returns error code +** Purpose: computes & checks a pump's head curve coefficients +**-------------------------------------------------------------- +*/ +{ + int m; + int curveindex; + int npts = 0; + int errcode = 0; + double a, b, c, h0 = 0.0, h1 = 0.0, h2 = 0.0, q1 = 0.0, q2 = 0.0; + + EN_Network *net = &pr->network; + Spump *pump; + Scurve *curve; + + pump = &net->Pump[pumpindex]; + if (pump->Ptype == CONST_HP) // Constant Hp pump + { + pump->H0 = 0.0; + pump->R = -8.814 * net->Link[pump->Link].Km; + pump->N = -1.0; + pump->Hmax = BIG; // No head limit + pump->Qmax = BIG; // No flow limit + pump->Q0 = 1.0; // Init. flow = 1 cfs + return errcode; } - /* Assign limits to custom pump curves */ - if (pump->Ptype == CUSTOM) { - curve = &net->Curve[j]; - for (m = 1; m < n; m++) { - if (curve->Y[m] >= curve->Y[m - 1]) { /* Error: Invalid curve */ - EN_geterror(227, errMsg, MAXMSG); - sprintf(pr->Msg, "%s link: %s", errMsg, link->ID); - writeline(pr, pr->Msg); - return (200); + else if (pump->Ptype == NOCURVE) // Pump curve specified + { + curveindex = pump->Hcurve; + if (curveindex == 0) return 226; + curve = &net->Curve[curveindex]; + curve->Type = P_CURVE; + npts = curve->Npts; + + // Generic power function curve + if (npts == 1) + { + pump->Ptype = POWER_FUNC; + q1 = curve->X[0]; + h1 = curve->Y[0]; + h0 = 1.33334 * h1; + q2 = 2.0 * q1; + h2 = 0.0; + } + + // 3 point curve with shutoff head + else if (npts == 3 && curve->X[0] == 0.0) + { + pump->Ptype = POWER_FUNC; + h0 = curve->Y[0]; + q1 = curve->X[1]; + h1 = curve->Y[1]; + q2 = curve->X[2]; + h2 = curve->Y[2]; + } + + // Custom pump curve + else + { + pump->Ptype = CUSTOM; + for (m = 1; m < npts; m++) + { + if (curve->Y[m] >= curve->Y[m - 1]) return 227; + } + pump->Qmax = curve->X[npts - 1]; + pump->Q0 = (curve->X[0] + pump->Qmax) / 2.0; + pump->Hmax = curve->Y[0]; + } + + // Compute shape factors & limits of power function curves + if (pump->Ptype == POWER_FUNC) + { + if (!powercurve(h0, h1, h2, q1, q2, &a, &b, &c)) return 227; + else + { + pump->H0 = -a; + pump->R = -b; + pump->N = c; + pump->Q0 = q1; + pump->Qmax = pow((-a / b), (1.0 / c)); + pump->Hmax = h0; + } } - } - pump->Qmax = curve->X[n - 1]; - pump->Q0 = (curve->X[0] + pump->Qmax) / 2.0; - pump->Hmax = curve->Y[0]; } - } /* Next pump */ - return (0); + return 0; } + int addnodeID(EN_Network *net, int n, char *id) /* **------------------------------------------------------------- @@ -603,7 +624,6 @@ int unlinked(EN_Project *pr) EN_Network *net = &pr->network; int *marked; int i, err, errcode; - char errMsg[MAXMSG+1]; errcode = 0; err = 0; @@ -621,8 +641,7 @@ int unlinked(EN_Project *pr) if (marked[i] == 0) /* If not marked then error */ { err++; - EN_geterror(233, errMsg, MAXMSG); - sprintf(pr->Msg, "%s node: %s", errMsg, net->Node[i].ID); + sprintf(pr->Msg, "%s link: %s", geterrmsg(233, pr->Msg), net->Node[i].ID); writeline(pr, pr->Msg); } if (err >= MAXERRS) @@ -732,9 +751,7 @@ int getcurves(EN_Project *pr) /* Check that curve has data points */ if (curve->Npts <= 0) { - char errMsg[MAXMSG+1]; - EN_geterror(230, errMsg, MAXMSG); - sprintf(pr->Msg, "%s curve: %s", errMsg, curve->ID); + sprintf(pr->Msg, "%s link: %s", geterrmsg(230, pr->Msg), curve->ID); writeline(pr, pr->Msg); return (200); } @@ -754,9 +771,7 @@ int getcurves(EN_Project *pr) /* Check that x data is in ascending order */ if (fx->value >= x) { - char errMsg[MAXMSG+1]; - EN_geterror(230, errMsg, MAXMSG); - sprintf(pr->Msg, "%s node: %s", errMsg, curve->ID); + sprintf(pr->Msg, "%s link: %s", geterrmsg(230, pr->Msg), curve->ID); writeline(pr, pr->Msg); return (200); } @@ -1012,10 +1027,8 @@ void inperrmsg(EN_Project *pr, int err, int sect, char *line) char errStr[MAXMSG + 1]; char id[MAXMSG + 1]; - EN_geterror(err, errStr, MAXMSG); - /* get text for error message */ - sprintf(pr->Msg, "%s - section: %s", errStr, SectTxt[sect]); + sprintf(pr->Msg, "%s - section: %s", geterrmsg(err, errStr), SectTxt[sect]); // append ID? /* Retrieve ID label of object with input error */ diff --git a/src/report.c b/src/report.c index 058ab22..cbb0e11 100644 --- a/src/report.c +++ b/src/report.c @@ -82,8 +82,6 @@ int writereport(EN_Project *pr) /* write formatted output to primary report file. */ rep->Fprinterr = FALSE; if (rep->Rptflag && strlen(rep->Rpt2Fname) == 0 && rep->RptFile != NULL) { - writecon(FMT17); - writecon(rep->Rpt1Fname); if (rep->Energyflag) writeenergy(pr); errcode = writeresults(pr); @@ -95,8 +93,6 @@ int writereport(EN_Project *pr) /* If secondary report file has same name as either input */ /* or primary report file then use primary report file. */ if (strcomp(rep->Rpt2Fname, par->InpFname) || strcomp(rep->Rpt2Fname, rep->Rpt1Fname)) { - writecon(FMT17); - writecon(rep->Rpt1Fname); if (rep->Energyflag) writeenergy(pr); errcode = writeresults(pr); @@ -117,8 +113,6 @@ int writereport(EN_Project *pr) /* Write full formatted report to file */ else { rep->Rptflag = 1; - writecon(FMT17); - writecon(rep->Rpt2Fname); writelogo(pr); if (rep->Summaryflag) writesummary(pr); diff --git a/src/text.h b/src/text.h index 656b3c2..b428be1 100755 --- a/src/text.h +++ b/src/text.h @@ -449,19 +449,15 @@ AUTHOR: L. Rossman #define FMT82 "\n\f\n Page %-d %60.60s\n" /* ------------------- Progress Messages ---------------------- */ -#define FMT100 "Retrieving network data..." -#define FMT101 "Computing hydraulics at hour %s" -#define FMT102 "Computing water quality at hour %s" -#define FMT103 "Saving results to file..." +#define FMT100 " Retrieving network data ... " +#define FMT101 " Computing hydraulics at hour %-10s " +#define FMT102 " Computing water quality at hour %-10s " +#define FMT103 " Writing output report ... " +#define FMT106 " Transferring results to file ... " #define FMT104 "Analysis begun %s" #define FMT105 "Analysis ended %s" /*------------------- Error Messages --------------------*/ - - - - - #define R_ERR201 "Input Error 201: syntax error in following line of " #define R_ERR202 "Input Error 202: illegal numeric value in following line of " #define R_ERR203 "Input Error 203: undefined node in following line of " diff --git a/src/types.h b/src/types.h index 1984b28..58f5137 100755 --- a/src/types.h +++ b/src/types.h @@ -51,7 +51,7 @@ typedef int INT4; #define TITLELEN 79 // Max. # characters in a title line #define MAXID 31 /* Max. # characters in ID name */ #define MAXMSG 255 /* Max. # characters in message text */ -#define MAXLINE 255 /* Max. # characters read from input line */ +#define MAXLINE 1024 /* Max. # characters read from input line */ #define MAXFNAME 259 /* Max. # characters in file name */ #define MAXTOKS 40 /* Max. items per line of input */ #define TZERO 1.E-4 /* Zero time tolerance */ diff --git a/tests/test_setlinktype.cpp b/tests/test_setlinktype.cpp new file mode 100644 index 0000000..bf225fe --- /dev/null +++ b/tests/test_setlinktype.cpp @@ -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 + +#include +#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()