From ca0ea0e17c15411cf6103c311197514b6cd1f4e1 Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Wed, 3 Apr 2019 00:58:40 -0400 Subject: [PATCH 01/15] Fixes bug in EN_getcurve --- include/epanet2.h | 2 +- include/epanet2_2.h | 2 +- include/epanet_py.h | 2 +- src/epanet.c | 6 +++--- src/epanet2.c | 6 +++--- src/epanet_py.c | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/epanet2.h b/include/epanet2.h index 38448da..2bbc94f 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -343,7 +343,7 @@ extern "C" { EN_API_FLOAT_TYPE x, EN_API_FLOAT_TYPE y); int DLLEXPORT ENgetcurve(int index, char* id, int *nPoints, - EN_API_FLOAT_TYPE **xValues, EN_API_FLOAT_TYPE **yValues); + EN_API_FLOAT_TYPE *xValues, EN_API_FLOAT_TYPE *yValues); int DLLEXPORT ENsetcurve(int index, EN_API_FLOAT_TYPE *xValues, EN_API_FLOAT_TYPE *yValues, int nPoints); diff --git a/include/epanet2_2.h b/include/epanet2_2.h index c7774d3..f6ad002 100644 --- a/include/epanet2_2.h +++ b/include/epanet2_2.h @@ -1422,7 +1422,7 @@ typedef struct Project *EN_Project; @ref EN_MAXID characters. */ int DLLEXPORT EN_getcurve(EN_Project ph, int index, char* id, int *nPoints, - double **xValues, double **yValues); + double *xValues, double *yValues); /** @brief assigns a set of data points to a curve. diff --git a/include/epanet_py.h b/include/epanet_py.h index e708756..a559d6e 100644 --- a/include/epanet_py.h +++ b/include/epanet_py.h @@ -139,7 +139,7 @@ int EXPORT_PY_API curv_getlength(Handle ph, int index, int *len); int EXPORT_PY_API curv_gettype(Handle ph, int curveIndex, int *outType); int EXPORT_PY_API curv_getvalue(Handle ph, int curveIndex, int pointIndex, double *x, double *y); int EXPORT_PY_API curv_setvalue(Handle ph, int curveIndex, int pointIndex, double x, double y); -int EXPORT_PY_API curv_get(Handle ph, int curveIndex, char* id, int *nValues, double **xValues, double **yValues); +int EXPORT_PY_API curv_get(Handle ph, int curveIndex, char* id, int *nValues, double *xValues, double *yValues); int EXPORT_PY_API curv_set(Handle ph, int index, double *x, double *y, int len); int EXPORT_PY_API scntl_add(Handle ph, int type, int linkIndex, double setting, int nodeIndex, double level, int *index); diff --git a/src/epanet.c b/src/epanet.c index 8eb1ecf..8942f6e 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -4385,7 +4385,7 @@ int DLLEXPORT EN_setcurvevalue(EN_Project p, int curveIndex, int pointIndex, } int DLLEXPORT EN_getcurve(EN_Project p, int index, char *id, int *nPoints, - double **xValues, double **yValues) + double *xValues, double *yValues) /*---------------------------------------------------------------- ** Input: index = data curve index ** Output: id = ID name of data curve @@ -4410,8 +4410,8 @@ int DLLEXPORT EN_getcurve(EN_Project p, int index, char *id, int *nPoints, *nPoints = curve->Npts; for (i = 0; i < curve->Npts; i++) { - *xValues[i] = curve->X[i]; - *yValues[i] = curve->Y[i]; + xValues[i] = curve->X[i]; + yValues[i] = curve->Y[i]; } return 0; } diff --git a/src/epanet2.c b/src/epanet2.c index 935d6c4..6ebb278 100644 --- a/src/epanet2.c +++ b/src/epanet2.c @@ -645,7 +645,7 @@ int DLLEXPORT ENsetcurvevalue(int curveIndex, int pointIndex, EN_API_FLOAT_TYPE } int DLLEXPORT ENgetcurve(int index, char *id, int *nPoints, - EN_API_FLOAT_TYPE **xValues, EN_API_FLOAT_TYPE **yValues) + EN_API_FLOAT_TYPE *xValues, EN_API_FLOAT_TYPE *yValues) { int i; Network *net = &_defaultProject->network; @@ -657,8 +657,8 @@ int DLLEXPORT ENgetcurve(int index, char *id, int *nPoints, *nPoints = curve->Npts; for (i = 0; i < curve->Npts; i++) { - *xValues[i] = (EN_API_FLOAT_TYPE)curve->X[i]; - *yValues[i] = (EN_API_FLOAT_TYPE)curve->Y[i]; + xValues[i] = (EN_API_FLOAT_TYPE)curve->X[i]; + yValues[i] = (EN_API_FLOAT_TYPE)curve->Y[i]; } return 0; } diff --git a/src/epanet_py.c b/src/epanet_py.c index fb681aa..b1b315d 100644 --- a/src/epanet_py.c +++ b/src/epanet_py.c @@ -624,7 +624,7 @@ int EXPORT_PY_API curv_setvalue(Handle ph, int curveIndex, int pointIndex, doubl return set_error(pr->error, EN_setcurvevalue(pr->project, curveIndex, pointIndex, x, y)); } -int EXPORT_PY_API curv_get(Handle ph, int curveIndex, char* id, int *nValues, double **xValues, double **yValues) +int EXPORT_PY_API curv_get(Handle ph, int curveIndex, char* id, int *nValues, double *xValues, double *yValues) { handle_t *pr = (handle_t *)ph; return set_error(pr->error, EN_getcurve(pr->project, curveIndex, id, nValues, xValues, yValues)); From 23b11ab672e2e1ff179b089c044b89f8ff97d7a3 Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Wed, 3 Apr 2019 01:15:57 -0400 Subject: [PATCH 02/15] Add test of EN_setcurve & EN_getcurve to test_curve.cpp --- tests/test_curve.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/test_curve.cpp b/tests/test_curve.cpp index 941b473..12fd05d 100644 --- a/tests/test_curve.cpp +++ b/tests/test_curve.cpp @@ -35,6 +35,35 @@ BOOST_FIXTURE_TEST_CASE(test_curve_comments, FixtureOpenClose) error = EN_getcomment(ph, EN_CURVE, index, comment); BOOST_REQUIRE(error == 0); BOOST_CHECK(check_string(comment, (char *)"Curve 1")); + + // Test of EN_setcurve and EN_getcurve + int i; + char id1[] = "NewCurve"; + int n1 = 5; + double X1[] = {16.88889, 19.5, 22.13889, 25.94445, 33.33334}; + double Y1[] = {156.7, 146.5, 136.2, 117.9, 50.0}; + int n2; + double X2[5], Y2[5]; + char id2[EN_MAXID+1]; + + // Add data to a new curve + error = EN_addcurve(ph, id1); + BOOST_REQUIRE(error == 0); + error = EN_getcurveindex(ph, id1, &i); + BOOST_REQUIRE(error == 0); + error = EN_setcurve(ph, i, X1, Y1, n1); + BOOST_REQUIRE(error == 0); + + // Retrieve data from curve + error = EN_getcurve(ph, i, id2, &n2, X2, Y2); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(check_string(id2, id1)); + BOOST_REQUIRE(n2 == n1); + for (i = 0; i < n1; i++) + { + BOOST_REQUIRE(X1[i] == X2[i]); + BOOST_REQUIRE(Y1[i] == Y2[i]); + } } BOOST_AUTO_TEST_SUITE_END() From 83ffc1cfc7550313d2e0712c7ab7e7599bc0e9e1 Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Wed, 3 Apr 2019 10:25:37 -0400 Subject: [PATCH 03/15] Removed the EN_DEFDEMANDPAT option See issue #429. Also allowed the EN_HEADLOSSFORM option to be changed if the solver is not active. --- include/epanet2.bas | 11 ++++--- include/epanet2.vb | 11 ++++--- include/epanet2_enums.h | 13 ++++----- src/epanet.c | 64 ++++++++--------------------------------- src/inpfile.c | 6 +--- src/input1.c | 12 +++----- src/input2.c | 4 +-- src/types.h | 6 ++-- tests/test_pattern.cpp | 7 ++--- 9 files changed, 40 insertions(+), 94 deletions(-) diff --git a/include/epanet2.bas b/include/epanet2.bas index f0ba641..ba94210 100644 --- a/include/epanet2.bas +++ b/include/epanet2.bas @@ -147,12 +147,11 @@ Public Const EN_EMITEXPON = 3 Public Const EN_DEMANDMULT = 4 Public Const EN_HEADERROR = 5 Public Const EN_FLOWCHANGE = 6 -Public Const EN_DEMANDDEFPAT = 7 -Public Const EN_HEADLOSSFORM = 8 -Public Const EN_GLOBALEFFIC = 9 -Public Const EN_GLOBALPRICE = 10 -Public Const EN_GLOBALPATTERN = 11 -Public Const EN_DEMANDCHARGE = 12 +Public Const EN_HEADLOSSFORM = 7 +Public Const EN_GLOBALEFFIC = 8 +Public Const EN_GLOBALPRICE = 9 +Public Const EN_GLOBALPATTERN = 10 +Public Const EN_DEMANDCHARGE = 11 Public Const EN_LOWLEVEL = 0 ' Control types Public Const EN_HILEVEL = 1 diff --git a/include/epanet2.vb b/include/epanet2.vb index b4345eb..6f71b26 100644 --- a/include/epanet2.vb +++ b/include/epanet2.vb @@ -152,12 +152,11 @@ Public Const EN_EMITEXPON = 3 Public Const EN_DEMANDMULT = 4 Public Const EN_HEADERROR = 5 Public Const EN_FLOWCHANGE = 6 -Public Const EN_DEMANDDEFPAT = 7 -Public Const EN_HEADLOSSFORM = 8 -Public Const EN_GLOBALEFFIC = 9 -Public Const EN_GLOBALPRICE = 10 -Public Const EN_GLOBALPATTERN = 11 -Public Const EN_DEMANDCHARGE = 12 +Public Const EN_HEADLOSSFORM = 7 +Public Const EN_GLOBALEFFIC = 8 +Public Const EN_GLOBALPRICE = 9 +Public Const EN_GLOBALPATTERN = 10 +Public Const EN_DEMANDCHARGE = 11 Public Const EN_LOWLEVEL = 0 ' Control types Public Const EN_HILEVEL = 1 diff --git a/include/epanet2_enums.h b/include/epanet2_enums.h index 558d670..fa00688 100644 --- a/include/epanet2_enums.h +++ b/include/epanet2_enums.h @@ -9,7 +9,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 03/17/2019 + Last Updated: 04/03/2019 ****************************************************************************** */ @@ -294,12 +294,11 @@ typedef enum { EN_DEMANDMULT = 4, //!< Global demand multiplier EN_HEADERROR = 5, //!< Maximum head loss error for hydraulic convergence EN_FLOWCHANGE = 6, //!< Maximum flow change for hydraulic convergence - EN_DEFDEMANDPAT = 7, //!< Index of the default demand time pattern - EN_HEADLOSSFORM = 8, //!< Head loss formula (see @ref EN_HeadLossType) - EN_GLOBALEFFIC = 9, //!< Global pump efficiency (percent) - EN_GLOBALPRICE = 10, //!< Global energy price per KWH - EN_GLOBALPATTERN = 11, //!< Index of a global energy price pattern - EN_DEMANDCHARGE = 12 //!< Energy charge per max. KW usage + EN_HEADLOSSFORM = 7, //!< Head loss formula (see @ref EN_HeadLossType) + EN_GLOBALEFFIC = 8, //!< Global pump efficiency (percent) + EN_GLOBALPRICE = 9, //!< Global energy price per KWH + EN_GLOBALPATTERN = 10, //!< Index of a global energy price pattern + EN_DEMANDCHARGE = 11 //!< Energy charge per max. KW usage } EN_Option; /// Types of simple controls diff --git a/src/epanet.c b/src/epanet.c index 8942f6e..e2f1d4f 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 04/02/2019 + Last Updated: 04/03/2019 ****************************************************************************** */ @@ -1116,9 +1116,6 @@ int DLLEXPORT EN_getoption(EN_Project p, int option, double *value) case EN_FLOWCHANGE: v = hyd->FlowChangeLimit * Ucf[FLOW]; break; - case EN_DEFDEMANDPAT: - v = hyd->DefPat; - break; case EN_HEADLOSSFORM: v = hyd->Formflag; break; @@ -1156,13 +1153,9 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value) Hydraul *hyd = &p->hydraul; Quality *qual = &p->quality; - Snode *node; - Pdemand demand; - const int Njuncs = net->Njuncs; + int Njuncs = net->Njuncs; double *Ucf = p->Ucf; - int i, j; - int tmpPat, pat, error; - char tmpId[MAXID + 1]; + int i, j, pat; double Ke, n, ucf; if (!p->Openflag) return 102; @@ -1210,36 +1203,14 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value) hyd->FlowChangeLimit = value / Ucf[FLOW]; break; - case EN_DEFDEMANDPAT: - //check that the pattern exists or is set to zero to delete the default pattern - pat = ROUND(value); - if (pat < 0 || pat > net->Npats) return 205; - tmpPat = hyd->DefPat; - //get the new pattern ID - if (pat == 0) - { - strncpy(tmpId, p->parser.DefPatID, MAXID); - } - else - { - error = EN_getpatternid(p, pat, tmpId); - if (error != 0) return error; - } - // replace node patterns with default pattern - for (i = 1; i <= net->Nnodes; i++) - { - node = &net->Node[i]; - for (demand = node->D; demand != NULL; demand = demand->next) - { - if (demand->Pat == tmpPat) - { - demand->Pat = pat; - demand->Name = xstrcpy(&demand->Name, "", MAXMSG); - } - } - } - strncpy(p->parser.DefPatID, tmpId, MAXID); - hyd->DefPat = pat; + case EN_HEADLOSSFORM: + // Can't change if hydraulic solver is open + if (p->hydraul.OpenHflag) return 262; + i = ROUND(value); + if (i < HW || i > CM) return 213; + hyd->Formflag = i; + if (hyd->Formflag == HW) hyd->Hexp = 1.852; + else hyd->Hexp = 2.0; break; case EN_GLOBALEFFIC: @@ -1700,7 +1671,7 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType) demand = (struct Sdemand *)malloc(sizeof(struct Sdemand)); demand->Base = 0.0; - demand->Pat = hyd->DefPat; // Use default pattern + demand->Pat = 0; demand->Name = NULL; demand->next = NULL; node->D = demand; @@ -3917,9 +3888,6 @@ int DLLEXPORT EN_addpattern(EN_Project p, char *id) // Update the number of patterns net->Npats = n; parser->MaxPats = n; - - // Make new pattern be default demand pattern if name matches - if (strcmp(id, parser->DefPatID) == 0) hyd->DefPat = n; return 0; } @@ -3948,14 +3916,6 @@ int DLLEXPORT EN_deletepattern(EN_Project p, int index) // Adjust references by other objects to patterns adjustpatterns(net, index); - // Modify default demand pattern - if (hyd->DefPat == index) - { - hyd->DefPat = 0; - strcpy(parser->DefPatID, ""); - } - else if (hyd->DefPat > index) hyd->DefPat--; - // Modify global energy price pattern if (hyd->Epat == index) hyd->Epat = 0; else if (hyd->Epat > index) hyd->Epat--; diff --git a/src/inpfile.c b/src/inpfile.c index 8aa3c52..509a255 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -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: 04/02/2019 +Last Updated: 04/03/2019 ****************************************************************************** */ @@ -633,10 +633,6 @@ int saveinpfile(Project *pr, const char *fname) fprintf(f, "\n UNITS %s", FlowUnitsTxt[parser->Flowflag]); fprintf(f, "\n PRESSURE %s", PressUnitsTxt[parser->Pressflag]); fprintf(f, "\n HEADLOSS %s", FormTxt[hyd->Formflag]); - if (hyd->DefPat >= 1 && hyd->DefPat <= net->Npats) - { - fprintf(f, "\n PATTERN %s", net->Pattern[hyd->DefPat].ID); - } switch (out->Hydflag) { case USE: diff --git a/src/input1.c b/src/input1.c index fe606d9..1516a44 100644 --- a/src/input1.c +++ b/src/input1.c @@ -7,7 +7,7 @@ Description: retrieves network data from an EPANET input file Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE -Last Updated: 03/17/2019 +Last Updated: 04/03/2019 ****************************************************************************** */ @@ -100,6 +100,7 @@ void setdefaults(Project *pr) parser->Unitsflag = US; // US unit system parser->Flowflag = GPM; // Flow units are gpm parser->Pressflag = PSI; // Pressure units are psi + parser->DefPat = 0; // Default demand pattern index out->Hydflag = SCRATCH; // No external hydraulics file rpt->Tstatflag = SERIES; // Generate time series output @@ -117,7 +118,6 @@ void setdefaults(Project *pr) hyd->ExtraIter = -1; // Stop if network unbalanced hyd->Viscos = MISSING; // Temporary viscosity hyd->SpGrav = SPGRAV; // Default specific gravity - hyd->DefPat = 0; // Default demand pattern index hyd->Epat = 0; // No energy price pattern hyd->Ecost = 0.0; // Zero unit energy cost hyd->Dcost = 0.0; // Zero energy demand charge @@ -326,16 +326,12 @@ void adjustdata(Project *pr) } // Use default pattern if none assigned to a demand - for (i = 1; i <= net->Nnodes; i++) + if (parser->DefPat > 0) for (i = 1; i <= net->Nnodes; i++) { node = &net->Node[i]; for (demand = node->D; demand != NULL; demand = demand->next) { - if (demand->Pat == 0) - { - demand->Pat = hyd->DefPat; - xstrcpy(&demand->Name, "", MAXMSG); - } + if (demand->Pat == 0) demand->Pat = parser->DefPat; } } diff --git a/src/input2.c b/src/input2.c index f1d0c9f..b337e5a 100644 --- a/src/input2.c +++ b/src/input2.c @@ -7,7 +7,7 @@ Description: reads and interprets network data from an EPANET input file Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE -Last Updated: 04/02/2019 +Last Updated: 04/03/2019 ****************************************************************************** */ @@ -649,7 +649,7 @@ int getpatterns(Project *pr) i = tmppattern->i; // Check if this is the default pattern - if (strcmp(tmppattern->ID, parser->DefPatID) == 0) hyd->DefPat = i; + if (strcmp(tmppattern->ID, parser->DefPatID) == 0) parser->DefPat = i; // Copy temporary patttern to network's pattern if (i >= 0 && i <= parser->MaxPats) diff --git a/src/types.h b/src/types.h index 4329414..0f574ce 100755 --- a/src/types.h +++ b/src/types.h @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 03/17/2019 + Last Updated: 04/03/2019 ****************************************************************************** */ @@ -573,7 +573,8 @@ typedef struct { ErrTok, // Index of error-producing token Unitsflag, // Unit system flag Flowflag, // Flow units flag - Pressflag; // Pressure units flag + Pressflag, // Pressure units flag + DefPat; // Default demand pattern STmplist *Patlist, // Temporary time pattern list @@ -738,7 +739,6 @@ typedef struct { *Xflow; // Inflow - outflow at each node int - DefPat, // Default demand pattern Epat, // Energy cost time pattern DemandModel, // Fixed or pressure dependent Formflag, // Head loss formula flag diff --git a/tests/test_pattern.cpp b/tests/test_pattern.cpp index 674ea76..bedad48 100644 --- a/tests/test_pattern.cpp +++ b/tests/test_pattern.cpp @@ -33,12 +33,9 @@ BOOST_AUTO_TEST_CASE(add_set_pattern) error = EN_open(ph, path_inp.c_str(), path_rpt.c_str(), ""); BOOST_REQUIRE(error == 0); - // Get the default pattern index - double dblPatIdx; - int defPatIdx; + // Assign the default pattern index + int defPatIdx = 1; int patIdx; - EN_getoption(ph, EN_DEFDEMANDPAT, &dblPatIdx); - defPatIdx = (int)dblPatIdx; // Rename the default pattern EN_setpatternid(ph, defPatIdx, (char *)"Pat1"); From af825005d4bc37cd66fbbfb465775efae7ea86b0 Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Wed, 3 Apr 2019 10:43:19 -0400 Subject: [PATCH 04/15] Fixed failure to update test_net_builder.cpp --- tests/test_net_builder.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_net_builder.cpp b/tests/test_net_builder.cpp index 5c6f274..56efa8d 100644 --- a/tests/test_net_builder.cpp +++ b/tests/test_net_builder.cpp @@ -121,8 +121,8 @@ BOOST_FIXTURE_TEST_CASE(test_build_net1, FixtureInitClose) BOOST_REQUIRE(error == 0); error = EN_setpattern(ph, 1, P, 12); BOOST_REQUIRE(error == 0); - error = EN_setoption(ph, EN_DEFDEMANDPAT, 1); - BOOST_REQUIRE(error == 0); + //error = EN_setoption(ph, EN_DEFDEMANDPAT, 1); + //BOOST_REQUIRE(error == 0); for (i = 0; i < 9; i++) { error = EN_addnode(ph, juncs[i], EN_JUNCTION); @@ -131,6 +131,8 @@ BOOST_FIXTURE_TEST_CASE(test_build_net1, FixtureInitClose) BOOST_REQUIRE(error == 0); error = EN_setnodevalue(ph, i + 1, EN_BASEDEMAND, d[i]); BOOST_REQUIRE(error == 0); + error = EN_setnodevalue(ph, i+1, EN_PATTERN, 1); + BOOST_REQUIRE(error == 0); error = EN_setcoord(ph, i + 1, X[i], Y[i]); BOOST_REQUIRE(error == 0); //error = EN_setdemandpattern(ph, i + 1, 1, 1); From fa4952a265e150721c64d4fb476c8bd8ca55cffb Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Wed, 3 Apr 2019 10:56:24 -0400 Subject: [PATCH 05/15] Fixed failure to update test_analysis.cpp --- tests/test_analysis.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_analysis.cpp b/tests/test_analysis.cpp index f7120f1..30a159f 100644 --- a/tests/test_analysis.cpp +++ b/tests/test_analysis.cpp @@ -25,7 +25,7 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose) double array[13]; std::vector test; - std::vector ref = {40.0, 0.001, 0.01, 0.5, 1.0, 0.0, 0.0, 1.0, 0.0, 75.0, 0.0, 0.0, 0.0}; + std::vector ref = {40.0, 0.001, 0.01, 0.5, 1.0, 0.0, 0.0, 0.0, 75.0, 0.0, 0.0, 0.0}; error = EN_solveH(ph); BOOST_REQUIRE(error == 0); From 568f89ff9e48152a5f57adb50226369622f7d61b Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 3 Apr 2019 11:10:36 -0400 Subject: [PATCH 06/15] removing reference to strncpy --- tests/test_project.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/test_project.cpp b/tests/test_project.cpp index 6ae1143..6966f17 100644 --- a/tests/test_project.cpp +++ b/tests/test_project.cpp @@ -11,6 +11,8 @@ ****************************************************************************** */ +#include + #include #include @@ -121,21 +123,23 @@ BOOST_AUTO_TEST_SUITE(test_proj_fixture) BOOST_FIXTURE_TEST_CASE(test_title, FixtureOpenClose) { // How is the API user supposed to know array size? - char c_test[3][80], c_ref[3][80]; + char c_test[3][80]; - strncpy(c_ref[0], " EPANET Example Network 1", 26); - strncpy(c_ref[1], "A simple example of modeling chlorine decay. Both bulk and", 59); - strncpy(c_ref[2], "wall reactions are included. ", 30); + std::string ref[3] = { + " EPANET Example Network 1", + "A simple example of modeling chlorine decay. Both bulk and", + "wall reactions are included."}; error = EN_gettitle(ph, c_test[0], c_test[1], c_test[2]); BOOST_REQUIRE(error == 0); for (int i = 0; i < 3; i++) { std::string test (c_test[i]); - std::string ref (c_ref[i]); - BOOST_CHECK(check_string(test, ref)); + BOOST_CHECK(check_string(test, ref[i])); } + delete [] &ref; + // Need a test for EN_settitle } From efd86c3ddd2987ff617c487ceb126d1fa2b897c5 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 3 Apr 2019 14:05:41 -0400 Subject: [PATCH 07/15] Fixing memory problems with test_toolkit Fixes memory leaks and some minor refactoring. --- tests/CMakeLists.txt | 3 +- tests/test_analysis.cpp | 23 +- tests/test_curve.cpp | 8 +- tests/test_net_builder.cpp | 611 +++++++++++++++++++------------------ tests/test_project.cpp | 24 +- tests/test_report.cpp | 13 +- tests/test_toolkit.hpp | 9 + 7 files changed, 353 insertions(+), 338 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 64c7c23..a772b51 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,7 +30,8 @@ set(toolkit_test_srcs test_pattern.cpp test_curve.cpp test_control.cpp - test_net_builder.cpp) +# test_net_builder.cpp +) add_executable(test_toolkit ${toolkit_test_srcs}) diff --git a/tests/test_analysis.cpp b/tests/test_analysis.cpp index f7120f1..f396560 100644 --- a/tests/test_analysis.cpp +++ b/tests/test_analysis.cpp @@ -22,9 +22,10 @@ BOOST_AUTO_TEST_SUITE (test_analysis) BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose) { int i; - double array[13]; - std::vector test; + std::vector test(13); + double *array = test.data(); + std::vector ref = {40.0, 0.001, 0.01, 0.5, 1.0, 0.0, 0.0, 1.0, 0.0, 75.0, 0.0, 0.0, 0.0}; error = EN_solveH(ph); @@ -35,23 +36,24 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose) for (i=EN_TRIALS; i<=EN_DEMANDCHARGE; i++) { - error = EN_getoption(ph, i, &array[i]); + error = EN_getoption(ph, i, array++); BOOST_REQUIRE(error == 0); } - test.assign(array, array + 13); BOOST_CHECK_EQUAL_COLLECTIONS(ref.begin(), ref.end(), test.begin(), test.end()); - error = EN_getoption(ph, 18, &array[0]); + double temp; + error = EN_getoption(ph, 18, &temp); BOOST_CHECK(error == 251); } BOOST_FIXTURE_TEST_CASE(test_anlys_gettimeparam, FixtureOpenClose) { int i; - long array[16]; - std::vector test; + std::vector test(16); + long *array = test.data(); + std::vector ref = {86400, 3600, 300, 7200, 0, 3600, 0, 360, 0, 25, 0, 86400, 86400, 0, 3600, 0}; error = EN_solveH(ph); @@ -62,14 +64,15 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_gettimeparam, FixtureOpenClose) for (i=EN_DURATION; i<=EN_NEXTEVENTTANK; i++) { - error = EN_gettimeparam(ph, i, &array[i]); + error = EN_gettimeparam(ph, i, array++); BOOST_REQUIRE(error == 0); } - test.assign(array, array + 16); BOOST_CHECK_EQUAL_COLLECTIONS(ref.begin(), ref.end(), test.begin(), test.end()); - error = EN_gettimeparam(ph, 18, &array[0]); + long temp; + error = EN_gettimeparam(ph, 18, &temp); BOOST_CHECK(error == 251); } + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/test_curve.cpp b/tests/test_curve.cpp index 12fd05d..6eb5a63 100644 --- a/tests/test_curve.cpp +++ b/tests/test_curve.cpp @@ -45,7 +45,7 @@ BOOST_FIXTURE_TEST_CASE(test_curve_comments, FixtureOpenClose) int n2; double X2[5], Y2[5]; char id2[EN_MAXID+1]; - + // Add data to a new curve error = EN_addcurve(ph, id1); BOOST_REQUIRE(error == 0); @@ -53,7 +53,7 @@ BOOST_FIXTURE_TEST_CASE(test_curve_comments, FixtureOpenClose) BOOST_REQUIRE(error == 0); error = EN_setcurve(ph, i, X1, Y1, n1); BOOST_REQUIRE(error == 0); - + // Retrieve data from curve error = EN_getcurve(ph, i, id2, &n2, X2, Y2); BOOST_REQUIRE(error == 0); @@ -61,8 +61,8 @@ BOOST_FIXTURE_TEST_CASE(test_curve_comments, FixtureOpenClose) BOOST_REQUIRE(n2 == n1); for (i = 0; i < n1; i++) { - BOOST_REQUIRE(X1[i] == X2[i]); - BOOST_REQUIRE(Y1[i] == Y2[i]); + BOOST_CHECK(X1[i] == X2[i]); + BOOST_CHECK(Y1[i] == Y2[i]); } } diff --git a/tests/test_net_builder.cpp b/tests/test_net_builder.cpp index 5c6f274..cb7bf16 100644 --- a/tests/test_net_builder.cpp +++ b/tests/test_net_builder.cpp @@ -35,6 +35,9 @@ BOOST_AUTO_TEST_CASE(test_init_close) struct FixtureInitClose { FixtureInitClose() { + error = 0; + ph = NULL; + EN_createproject(&ph); EN_init(ph, DATA_PATH_RPT, DATA_PATH_OUT, EN_GPM, EN_HW); } @@ -100,309 +103,309 @@ struct FixtureInitClose { // EN_deleteproject(&ph); //} -BOOST_FIXTURE_TEST_CASE(test_build_net1, FixtureInitClose) -{ - int flag = 00; - long t, tstep; - int i, ind, Lindex, Nindex, Cindex; - double h_build; - - // now we build Net1 from scratch... - char juncs[9][10] = { "10", "11", "12", "13", "21", "22", "23", "31", "32" }; - double e[9] = { 710, 710, 700, 695, 700, 695, 690, 700, 710 }; - double d[9] = { 0, 150, 150, 100, 150, 200, 150, 100, 100 }; - double X[9] = { 20, 30, 50, 70, 30, 50, 70, 30, 50 }; - double Y[9] = { 70, 70, 70, 70, 40, 40, 40, 10, 10 }; - double L[12] = { 10530, 5280, 5280, 5280, 5280, 5280, 200, 5280, 5280, 5280, 5280, 5280 }; - double dia[12] = { 18, 14, 10, 10, 12, 6, 18, 10, 12, 8, 8, 6 }; - double P[12] = { 1.0f, 1.2f, 1.4f, 1.6f, 1.4f, 1.2f, 1.0f, 0.8f, 0.6f, 0.4f, 0.6f, 0.8f }; - - error = EN_addpattern(ph, (char *)"pat1"); - BOOST_REQUIRE(error == 0); - error = EN_setpattern(ph, 1, P, 12); - BOOST_REQUIRE(error == 0); - error = EN_setoption(ph, EN_DEFDEMANDPAT, 1); - BOOST_REQUIRE(error == 0); - for (i = 0; i < 9; i++) - { - error = EN_addnode(ph, juncs[i], EN_JUNCTION); - BOOST_REQUIRE(error == 0); - error = EN_setnodevalue(ph, i + 1, EN_ELEVATION, e[i]); - BOOST_REQUIRE(error == 0); - error = EN_setnodevalue(ph, i + 1, EN_BASEDEMAND, d[i]); - BOOST_REQUIRE(error == 0); - error = EN_setcoord(ph, i + 1, X[i], Y[i]); - BOOST_REQUIRE(error == 0); - //error = EN_setdemandpattern(ph, i + 1, 1, 1); - //BOOST_REQUIRE(error == 0); - } - error = EN_addnode(ph, (char *)"9", EN_RESERVOIR); - BOOST_REQUIRE(error == 0); - error = EN_setcoord(ph, 10, 10, 70); - BOOST_REQUIRE(error == 0); - error = EN_setnodevalue(ph, 10, EN_ELEVATION, 800); - BOOST_REQUIRE(error == 0); - - error = EN_addnode(ph, (char *)"2", EN_TANK); - BOOST_REQUIRE(error == 0); - error = EN_setcoord(ph, 11, 50, 90); - BOOST_REQUIRE(error == 0); - error = EN_setnodevalue(ph, 11, EN_TANKDIAM, 50.5); - BOOST_REQUIRE(error == 0); - error = EN_setnodevalue(ph, 11, EN_ELEVATION, 850); - BOOST_REQUIRE(error == 0); - error = EN_setnodevalue(ph, 11, EN_MAXLEVEL, 150); - BOOST_REQUIRE(error == 0); - error = EN_setnodevalue(ph, 11, EN_TANKLEVEL, 120); - BOOST_REQUIRE(error == 0); - error = EN_setnodevalue(ph, 11, EN_MINLEVEL, 100); - BOOST_REQUIRE(error == 0); - error = EN_setnodevalue(ph, 11, EN_MIXFRACTION, 1); - BOOST_REQUIRE(error == 0); - - error = EN_addlink(ph, (char *)"10", EN_PIPE, (char *)"10", (char *)"11"); - BOOST_REQUIRE(error == 0); - error = EN_addlink(ph, (char *)"11", EN_PIPE, (char *)"11", (char *)"12"); - BOOST_REQUIRE(error == 0); - error = EN_addlink(ph, (char *)"12", EN_PIPE, (char *)"12", (char *)"13"); - BOOST_REQUIRE(error == 0); - error = EN_addlink(ph, (char *)"21", EN_PIPE, (char *)"21", (char *)"22"); - BOOST_REQUIRE(error == 0); - error = EN_addlink(ph, (char *)"22", EN_PIPE, (char *)"22", (char *)"23"); - BOOST_REQUIRE(error == 0); - error = EN_addlink(ph, (char *)"31", EN_PIPE, (char *)"31", (char *)"32"); - BOOST_REQUIRE(error == 0); - error = EN_addlink(ph, (char *)"110", EN_PIPE, (char *)"2", (char *)"12"); - BOOST_REQUIRE(error == 0); - error = EN_addlink(ph, (char *)"111", EN_PIPE, (char *)"11", (char *)"21"); - BOOST_REQUIRE(error == 0); - error = EN_addlink(ph, (char *)"112", EN_PIPE, (char *)"12", (char *)"22"); - BOOST_REQUIRE(error == 0); - error = EN_addlink(ph, (char *)"113", EN_PIPE, (char *)"13", (char *)"23"); - BOOST_REQUIRE(error == 0); - error = EN_addlink(ph, (char *)"121", EN_PIPE, (char *)"21", (char *)"31"); - BOOST_REQUIRE(error == 0); - error = EN_addlink(ph, (char *)"122", EN_PIPE, (char *)"22", (char *)"32"); - BOOST_REQUIRE(error == 0); - for (i = 0; i < 12; i++) - { - error = EN_setlinkvalue(ph, i + 1, EN_LENGTH, L[i]); - BOOST_REQUIRE(error == 0); - error = EN_setlinkvalue(ph, i + 1, EN_DIAMETER, dia[i]); - BOOST_REQUIRE(error == 0); - } - - error = EN_addlink(ph, (char *)"9", EN_PUMP, (char *)"9", (char *)"10"); - BOOST_REQUIRE(error == 0); - error = EN_addcurve(ph, (char *)"1"); - BOOST_REQUIRE(error == 0); - error = EN_setcurvevalue(ph, 1, 1, 1500, 250); - BOOST_REQUIRE(error == 0); - error = EN_getlinkindex(ph, (char *)"9", &ind); - BOOST_REQUIRE(error == 0); - error = EN_setheadcurveindex(ph, ind, 1); - BOOST_REQUIRE(error == 0); - - error = EN_settimeparam(ph, EN_DURATION, 24 * 3600); - BOOST_REQUIRE(error == 0); - error = EN_settimeparam(ph, EN_PATTERNSTEP, 2 * 3600); - BOOST_REQUIRE(error == 0); - - error = EN_getlinkindex(ph, (char *)"9", &Lindex); - BOOST_REQUIRE(error == 0); - error = EN_getnodeindex(ph, (char *)"2", &Nindex); - BOOST_REQUIRE(error == 0); - - // Add controls - error = EN_addcontrol(ph, EN_LOWLEVEL, Lindex, 1, Nindex, 110, &Cindex); - BOOST_REQUIRE(error == 0); - error = EN_addcontrol(ph, EN_HILEVEL, Lindex, 0, Nindex, 140, &Cindex); - BOOST_REQUIRE(error == 0); - - error = EN_openH(ph); - BOOST_REQUIRE(error == 0); - error = EN_initH(ph, 0); - BOOST_REQUIRE(error == 0); - do { - error = EN_runH(ph, &t); - BOOST_REQUIRE(error == 0); - // this is the head at the end of the simulation after building the network *without* saving it to file - error = EN_getnodevalue(ph, Nindex, EN_HEAD, &h_build); - BOOST_REQUIRE(error == 0); - error = EN_nextH(ph, &tstep); - BOOST_REQUIRE(error == 0); - } while (tstep > 0); - error = EN_closeH(ph); - BOOST_REQUIRE(error == 0); - - error = EN_saveinpfile(ph, "net_builder.inp"); - BOOST_REQUIRE(error == 0); -} - -BOOST_AUTO_TEST_CASE(test_open_net1, * boost::unit_test::depends_on("test_net_builder/test_build_net1")) -{ - int error = 0; - int flag = 00; - long t, tstep; - int Nindex = -1; - double h_orig = 0.0, h_build = 0.0, h_build_loaded = 0.0; - - - EN_Project ph = NULL; - - // now we load the netwok we just built and saved - EN_createproject(&ph); - error = EN_open(ph, "net_builder.inp", DATA_PATH_RPT, DATA_PATH_OUT); - BOOST_REQUIRE(error == 0); - - error = EN_getnodeindex(ph, (char *)"2", &Nindex); - BOOST_REQUIRE(error == 0); - - 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); - // this is the head at the end of the simulation after building the network and saving it to file - error = EN_getnodevalue(ph, Nindex, EN_HEAD, &h_build_loaded); - BOOST_REQUIRE(error == 0); - error = EN_nextH(ph, &tstep); - BOOST_REQUIRE(error == 0); - - } while (tstep > 0); - - error = EN_closeH(ph); - BOOST_REQUIRE(error == 0); - - error = EN_close(ph); - BOOST_REQUIRE(error == 0); - - EN_deleteproject(&ph); - - //--------------------------------------------------------------------- - // if we got this far we can compare results - - // compare the original to the build & saved network - // BOOST_CHECK(abs(h_orig - h_build_loaded) < 0.0001); - - // compare the original to the build without saving - // BOOST_CHECK(abs(h_orig - h_build) < 0.0001); -} - - -BOOST_FIXTURE_TEST_CASE(test_save_net2, FixtureInitClose) -{ - //char id[EN_MAXID+1]; - double p1_1, p2_1; // p1_2, p2_2; - double q1_1, q2_1; // q1_2, q2_2; - - // Build a network - error = EN_addnode(ph, (char *)"N1", EN_JUNCTION); - BOOST_REQUIRE(error == 0); - error = EN_addnode(ph, (char *)"N2", EN_JUNCTION); - BOOST_REQUIRE(error == 0); - error = EN_addnode(ph, (char *)"N3", EN_RESERVOIR); - BOOST_REQUIRE(error == 0); - error = EN_addnode(ph, (char *)"N4", EN_TANK); - BOOST_REQUIRE(error == 0); - error = EN_addlink(ph, (char *)"L1", EN_PUMP, (char *)"N3", (char *)"N1"); - BOOST_REQUIRE(error == 0); - error = EN_addlink(ph, (char *)"L2", EN_PIPE, (char *)"N1", (char *)"N3"); - BOOST_REQUIRE(error == 0); - error = EN_addlink(ph, (char *)"L3", EN_PIPE, (char *)"N1", (char *)"N2"); - BOOST_REQUIRE(error == 0); - error = EN_addcurve(ph, (char *)"C1"); - BOOST_REQUIRE(error == 0); - - // Set network data using the new helper functions - error = EN_setcurvevalue(ph, 1, 1, 1500, 250); - BOOST_REQUIRE(error == 0); - error = EN_setjuncdata(ph, 1, 700, 500, (char *)""); - BOOST_REQUIRE(error == 0); - error = EN_setjuncdata(ph, 2, 710, 500, (char *)""); - BOOST_REQUIRE(error == 0); - error = EN_setnodevalue(ph, 3, EN_ELEVATION, 800); - BOOST_REQUIRE(error == 0); - error = EN_settankdata(ph, 4, 850, 120, 100, 150, 50.5, 0, (char *)""); - BOOST_REQUIRE(error == 0); - error = EN_setlinkvalue(ph, 1, EN_PUMP_HCURVE, 1); - BOOST_REQUIRE(error == 0); - error = EN_setpipedata(ph, 2, 10560, 12, 100, 0); - BOOST_REQUIRE(error == 0); - error = EN_setpipedata(ph, 3, 5280, 14, 100, 0); - BOOST_REQUIRE(error == 0); - - // Run hydraulics - error = EN_solveH(ph); - BOOST_REQUIRE(error == 0); - - // Save results - error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p1_1); - BOOST_REQUIRE(error == 0); - error = EN_getnodevalue(ph, 2, EN_PRESSURE, &p2_1); - BOOST_REQUIRE(error == 0); - error = EN_getlinkvalue(ph, 1, EN_FLOW, &q1_1); - BOOST_REQUIRE(error == 0); - error = EN_getlinkvalue(ph, 2, EN_FLOW, &q2_1); - BOOST_REQUIRE(error == 0); - - // Save project - error = EN_saveinpfile(ph, "netbuilder_test2.inp"); - BOOST_REQUIRE(error == 0); -} - - -BOOST_AUTO_TEST_CASE(test_reopen_net2, *boost::unit_test::depends_on("test_net_builder/test_save_net2")) -{ - int error, index; - - double p1_2, p2_2; - double q1_2, q2_2; - - // Open the saved project file - EN_Project ph = NULL; - error = EN_createproject(&ph); - BOOST_REQUIRE(error == 0); - error = EN_open(ph, "netbuilder_test2.inp", DATA_PATH_RPT, DATA_PATH_OUT); - BOOST_REQUIRE(error == 0); - - // Run hydraulics - error = EN_solveH(ph); - BOOST_REQUIRE(error == 0); - - // Save these new results - error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p1_2); - BOOST_REQUIRE(error == 0); - error = EN_getnodevalue(ph, 2, EN_PRESSURE, &p2_2); - BOOST_REQUIRE(error == 0); - error = EN_getlinkindex(ph, (char *)"L1", &index); - BOOST_REQUIRE(error == 0); - error = EN_getlinkvalue(ph, index, EN_FLOW, &q1_2); - BOOST_REQUIRE(error == 0); - error = EN_getlinkindex(ph, (char *)"L2", &index); - BOOST_REQUIRE(error == 0); - error = EN_getlinkvalue(ph, index, EN_FLOW, &q2_2); - BOOST_REQUIRE(error == 0); - - // Display old & new results - //cout << "\n Node N1 Pressure: " << p1_1 << " " << p1_2; - //cout << "\n Node N2 Pressure: " << p2_1 << " " << p2_2; - //cout << "\n Link L1 Flow: " << q1_1 << " " << q1_2; - //cout << "\n Link L2 Flow: " << q2_1 << " " << q2_2; - - // Compare old & new results -// BOOST_CHECK(abs(p1_1 - p1_2) < 1.e-5); -// BOOST_CHECK(abs(q1_1 - q1_2) < 1.e-5); -// BOOST_CHECK(abs(p2_1 - p2_2) < 1.e-5); -// BOOST_CHECK(abs(q2_1 - q2_2) < 1.e-5); - - // Close project - EN_close(ph); - EN_deleteproject(&ph); -} +// BOOST_FIXTURE_TEST_CASE(test_build_net1, FixtureInitClose) +// { +// int flag = 00; +// long t, tstep; +// int i, ind, Lindex, Nindex, Cindex; +// double h_build; +// +// // now we build Net1 from scratch... +// char juncs[9][10] = { "10", "11", "12", "13", "21", "22", "23", "31", "32" }; +// double e[9] = { 710, 710, 700, 695, 700, 695, 690, 700, 710 }; +// double d[9] = { 0, 150, 150, 100, 150, 200, 150, 100, 100 }; +// double X[9] = { 20, 30, 50, 70, 30, 50, 70, 30, 50 }; +// double Y[9] = { 70, 70, 70, 70, 40, 40, 40, 10, 10 }; +// double L[12] = { 10530, 5280, 5280, 5280, 5280, 5280, 200, 5280, 5280, 5280, 5280, 5280 }; +// double dia[12] = { 18, 14, 10, 10, 12, 6, 18, 10, 12, 8, 8, 6 }; +// double P[12] = { 1.0f, 1.2f, 1.4f, 1.6f, 1.4f, 1.2f, 1.0f, 0.8f, 0.6f, 0.4f, 0.6f, 0.8f }; +// +// error = EN_addpattern(ph, (char *)"pat1"); +// BOOST_REQUIRE(error == 0); +// error = EN_setpattern(ph, 1, P, 12); +// BOOST_REQUIRE(error == 0); +// error = EN_setoption(ph, EN_DEFDEMANDPAT, 1); +// BOOST_REQUIRE(error == 0); +// for (i = 0; i < 9; i++) +// { +// error = EN_addnode(ph, juncs[i], EN_JUNCTION); +// BOOST_REQUIRE(error == 0); +// error = EN_setnodevalue(ph, i + 1, EN_ELEVATION, e[i]); +// BOOST_REQUIRE(error == 0); +// error = EN_setnodevalue(ph, i + 1, EN_BASEDEMAND, d[i]); +// BOOST_REQUIRE(error == 0); +// error = EN_setcoord(ph, i + 1, X[i], Y[i]); +// BOOST_REQUIRE(error == 0); +// //error = EN_setdemandpattern(ph, i + 1, 1, 1); +// //BOOST_REQUIRE(error == 0); +// } +// error = EN_addnode(ph, (char *)"9", EN_RESERVOIR); +// BOOST_REQUIRE(error == 0); +// error = EN_setcoord(ph, 10, 10, 70); +// BOOST_REQUIRE(error == 0); +// error = EN_setnodevalue(ph, 10, EN_ELEVATION, 800); +// BOOST_REQUIRE(error == 0); +// +// error = EN_addnode(ph, (char *)"2", EN_TANK); +// BOOST_REQUIRE(error == 0); +// error = EN_setcoord(ph, 11, 50, 90); +// BOOST_REQUIRE(error == 0); +// error = EN_setnodevalue(ph, 11, EN_TANKDIAM, 50.5); +// BOOST_REQUIRE(error == 0); +// error = EN_setnodevalue(ph, 11, EN_ELEVATION, 850); +// BOOST_REQUIRE(error == 0); +// error = EN_setnodevalue(ph, 11, EN_MAXLEVEL, 150); +// BOOST_REQUIRE(error == 0); +// error = EN_setnodevalue(ph, 11, EN_TANKLEVEL, 120); +// BOOST_REQUIRE(error == 0); +// error = EN_setnodevalue(ph, 11, EN_MINLEVEL, 100); +// BOOST_REQUIRE(error == 0); +// error = EN_setnodevalue(ph, 11, EN_MIXFRACTION, 1); +// BOOST_REQUIRE(error == 0); +// +// error = EN_addlink(ph, (char *)"10", EN_PIPE, (char *)"10", (char *)"11"); +// BOOST_REQUIRE(error == 0); +// error = EN_addlink(ph, (char *)"11", EN_PIPE, (char *)"11", (char *)"12"); +// BOOST_REQUIRE(error == 0); +// error = EN_addlink(ph, (char *)"12", EN_PIPE, (char *)"12", (char *)"13"); +// BOOST_REQUIRE(error == 0); +// error = EN_addlink(ph, (char *)"21", EN_PIPE, (char *)"21", (char *)"22"); +// BOOST_REQUIRE(error == 0); +// error = EN_addlink(ph, (char *)"22", EN_PIPE, (char *)"22", (char *)"23"); +// BOOST_REQUIRE(error == 0); +// error = EN_addlink(ph, (char *)"31", EN_PIPE, (char *)"31", (char *)"32"); +// BOOST_REQUIRE(error == 0); +// error = EN_addlink(ph, (char *)"110", EN_PIPE, (char *)"2", (char *)"12"); +// BOOST_REQUIRE(error == 0); +// error = EN_addlink(ph, (char *)"111", EN_PIPE, (char *)"11", (char *)"21"); +// BOOST_REQUIRE(error == 0); +// error = EN_addlink(ph, (char *)"112", EN_PIPE, (char *)"12", (char *)"22"); +// BOOST_REQUIRE(error == 0); +// error = EN_addlink(ph, (char *)"113", EN_PIPE, (char *)"13", (char *)"23"); +// BOOST_REQUIRE(error == 0); +// error = EN_addlink(ph, (char *)"121", EN_PIPE, (char *)"21", (char *)"31"); +// BOOST_REQUIRE(error == 0); +// error = EN_addlink(ph, (char *)"122", EN_PIPE, (char *)"22", (char *)"32"); +// BOOST_REQUIRE(error == 0); +// for (i = 0; i < 12; i++) +// { +// error = EN_setlinkvalue(ph, i + 1, EN_LENGTH, L[i]); +// BOOST_REQUIRE(error == 0); +// error = EN_setlinkvalue(ph, i + 1, EN_DIAMETER, dia[i]); +// BOOST_REQUIRE(error == 0); +// } +// +// error = EN_addlink(ph, (char *)"9", EN_PUMP, (char *)"9", (char *)"10"); +// BOOST_REQUIRE(error == 0); +// error = EN_addcurve(ph, (char *)"1"); +// BOOST_REQUIRE(error == 0); +// error = EN_setcurvevalue(ph, 1, 1, 1500, 250); +// BOOST_REQUIRE(error == 0); +// error = EN_getlinkindex(ph, (char *)"9", &ind); +// BOOST_REQUIRE(error == 0); +// error = EN_setheadcurveindex(ph, ind, 1); +// BOOST_REQUIRE(error == 0); +// +// error = EN_settimeparam(ph, EN_DURATION, 24 * 3600); +// BOOST_REQUIRE(error == 0); +// error = EN_settimeparam(ph, EN_PATTERNSTEP, 2 * 3600); +// BOOST_REQUIRE(error == 0); +// +// error = EN_getlinkindex(ph, (char *)"9", &Lindex); +// BOOST_REQUIRE(error == 0); +// error = EN_getnodeindex(ph, (char *)"2", &Nindex); +// BOOST_REQUIRE(error == 0); +// +// // Add controls +// error = EN_addcontrol(ph, EN_LOWLEVEL, Lindex, 1, Nindex, 110, &Cindex); +// BOOST_REQUIRE(error == 0); +// error = EN_addcontrol(ph, EN_HILEVEL, Lindex, 0, Nindex, 140, &Cindex); +// BOOST_REQUIRE(error == 0); +// +// error = EN_openH(ph); +// BOOST_REQUIRE(error == 0); +// error = EN_initH(ph, 0); +// BOOST_REQUIRE(error == 0); +// do { +// error = EN_runH(ph, &t); +// BOOST_REQUIRE(error == 0); +// // this is the head at the end of the simulation after building the network *without* saving it to file +// error = EN_getnodevalue(ph, Nindex, EN_HEAD, &h_build); +// BOOST_REQUIRE(error == 0); +// error = EN_nextH(ph, &tstep); +// BOOST_REQUIRE(error == 0); +// } while (tstep > 0); +// error = EN_closeH(ph); +// BOOST_REQUIRE(error == 0); +// +// error = EN_saveinpfile(ph, "net_builder.inp"); +// BOOST_REQUIRE(error == 0); +// } +// +// BOOST_AUTO_TEST_CASE(test_open_net1, * boost::unit_test::depends_on("test_net_builder/test_build_net1")) +// { +// int error = 0; +// int flag = 00; +// long t, tstep; +// int Nindex = -1; +// double h_orig = 0.0, h_build = 0.0, h_build_loaded = 0.0; +// +// +// EN_Project ph = NULL; +// +// // now we load the netwok we just built and saved +// EN_createproject(&ph); +// error = EN_open(ph, "net_builder.inp", DATA_PATH_RPT, DATA_PATH_OUT); +// BOOST_REQUIRE(error == 0); +// +// error = EN_getnodeindex(ph, (char *)"2", &Nindex); +// BOOST_REQUIRE(error == 0); +// +// 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); +// // this is the head at the end of the simulation after building the network and saving it to file +// error = EN_getnodevalue(ph, Nindex, EN_HEAD, &h_build_loaded); +// BOOST_REQUIRE(error == 0); +// error = EN_nextH(ph, &tstep); +// BOOST_REQUIRE(error == 0); +// +// } while (tstep > 0); +// +// error = EN_closeH(ph); +// BOOST_REQUIRE(error == 0); +// +// error = EN_close(ph); +// BOOST_REQUIRE(error == 0); +// +// EN_deleteproject(&ph); +// +// //--------------------------------------------------------------------- +// // if we got this far we can compare results +// +// // compare the original to the build & saved network +// // BOOST_CHECK(abs(h_orig - h_build_loaded) < 0.0001); +// +// // compare the original to the build without saving +// // BOOST_CHECK(abs(h_orig - h_build) < 0.0001); +// } +// +// +// BOOST_FIXTURE_TEST_CASE(test_save_net2, FixtureInitClose) +// { +// //char id[EN_MAXID+1]; +// double p1_1, p2_1; // p1_2, p2_2; +// double q1_1, q2_1; // q1_2, q2_2; +// +// // Build a network +// error = EN_addnode(ph, (char *)"N1", EN_JUNCTION); +// BOOST_REQUIRE(error == 0); +// error = EN_addnode(ph, (char *)"N2", EN_JUNCTION); +// BOOST_REQUIRE(error == 0); +// error = EN_addnode(ph, (char *)"N3", EN_RESERVOIR); +// BOOST_REQUIRE(error == 0); +// error = EN_addnode(ph, (char *)"N4", EN_TANK); +// BOOST_REQUIRE(error == 0); +// error = EN_addlink(ph, (char *)"L1", EN_PUMP, (char *)"N3", (char *)"N1"); +// BOOST_REQUIRE(error == 0); +// error = EN_addlink(ph, (char *)"L2", EN_PIPE, (char *)"N1", (char *)"N3"); +// BOOST_REQUIRE(error == 0); +// error = EN_addlink(ph, (char *)"L3", EN_PIPE, (char *)"N1", (char *)"N2"); +// BOOST_REQUIRE(error == 0); +// error = EN_addcurve(ph, (char *)"C1"); +// BOOST_REQUIRE(error == 0); +// +// // Set network data using the new helper functions +// error = EN_setcurvevalue(ph, 1, 1, 1500, 250); +// BOOST_REQUIRE(error == 0); +// error = EN_setjuncdata(ph, 1, 700, 500, (char *)""); +// BOOST_REQUIRE(error == 0); +// error = EN_setjuncdata(ph, 2, 710, 500, (char *)""); +// BOOST_REQUIRE(error == 0); +// error = EN_setnodevalue(ph, 3, EN_ELEVATION, 800); +// BOOST_REQUIRE(error == 0); +// error = EN_settankdata(ph, 4, 850, 120, 100, 150, 50.5, 0, (char *)""); +// BOOST_REQUIRE(error == 0); +// error = EN_setlinkvalue(ph, 1, EN_PUMP_HCURVE, 1); +// BOOST_REQUIRE(error == 0); +// error = EN_setpipedata(ph, 2, 10560, 12, 100, 0); +// BOOST_REQUIRE(error == 0); +// error = EN_setpipedata(ph, 3, 5280, 14, 100, 0); +// BOOST_REQUIRE(error == 0); +// +// // Run hydraulics +// error = EN_solveH(ph); +// BOOST_REQUIRE(error == 0); +// +// // Save results +// error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p1_1); +// BOOST_REQUIRE(error == 0); +// error = EN_getnodevalue(ph, 2, EN_PRESSURE, &p2_1); +// BOOST_REQUIRE(error == 0); +// error = EN_getlinkvalue(ph, 1, EN_FLOW, &q1_1); +// BOOST_REQUIRE(error == 0); +// error = EN_getlinkvalue(ph, 2, EN_FLOW, &q2_1); +// BOOST_REQUIRE(error == 0); +// +// // Save project +// error = EN_saveinpfile(ph, "netbuilder_test2.inp"); +// BOOST_REQUIRE(error == 0); +// } +// +// +// BOOST_AUTO_TEST_CASE(test_reopen_net2, *boost::unit_test::depends_on("test_net_builder/test_save_net2")) +// { +// int error, index; +// +// double p1_2, p2_2; +// double q1_2, q2_2; +// +// // Open the saved project file +// EN_Project ph = NULL; +// error = EN_createproject(&ph); +// BOOST_REQUIRE(error == 0); +// error = EN_open(ph, "netbuilder_test2.inp", DATA_PATH_RPT, DATA_PATH_OUT); +// BOOST_REQUIRE(error == 0); +// +// // Run hydraulics +// error = EN_solveH(ph); +// BOOST_REQUIRE(error == 0); +// +// // Save these new results +// error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p1_2); +// BOOST_REQUIRE(error == 0); +// error = EN_getnodevalue(ph, 2, EN_PRESSURE, &p2_2); +// BOOST_REQUIRE(error == 0); +// error = EN_getlinkindex(ph, (char *)"L1", &index); +// BOOST_REQUIRE(error == 0); +// error = EN_getlinkvalue(ph, index, EN_FLOW, &q1_2); +// BOOST_REQUIRE(error == 0); +// error = EN_getlinkindex(ph, (char *)"L2", &index); +// BOOST_REQUIRE(error == 0); +// error = EN_getlinkvalue(ph, index, EN_FLOW, &q2_2); +// BOOST_REQUIRE(error == 0); +// +// // Display old & new results +// //cout << "\n Node N1 Pressure: " << p1_1 << " " << p1_2; +// //cout << "\n Node N2 Pressure: " << p2_1 << " " << p2_2; +// //cout << "\n Link L1 Flow: " << q1_1 << " " << q1_2; +// //cout << "\n Link L2 Flow: " << q2_1 << " " << q2_2; +// +// // Compare old & new results +// // BOOST_CHECK(abs(p1_1 - p1_2) < 1.e-5); +// // BOOST_CHECK(abs(q1_1 - q1_2) < 1.e-5); +// // BOOST_CHECK(abs(p2_1 - p2_2) < 1.e-5); +// // BOOST_CHECK(abs(q2_1 - q2_2) < 1.e-5); +// +// // Close project +// EN_close(ph); +// EN_deleteproject(&ph); +// } BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/test_project.cpp b/tests/test_project.cpp index 2c4f304..6642870 100644 --- a/tests/test_project.cpp +++ b/tests/test_project.cpp @@ -113,37 +113,37 @@ BOOST_FIXTURE_TEST_CASE(test_title, FixtureOpenClose) // How is the API user supposed to know array size? char c_test[3][80]; + // ref is an automatic variable and therefore doesn't need to be deleted std::string ref[3] = { " EPANET Example Network 1", "A simple example of modeling chlorine decay. Both bulk and", - "wall reactions are included."}; + "wall reactions are included. "}; error = EN_gettitle(ph, c_test[0], c_test[1], c_test[2]); BOOST_REQUIRE(error == 0); - for (int i = 0; i < 3; i++) { - std::string test (c_test[i]); - BOOST_CHECK(check_string(test, ref[i])); - } - - delete [] &ref; + for (int i = 0; i < 3; i++) { + std::string test (c_test[i]); + BOOST_CHECK(check_string(test, ref[i])); + } // Need a test for EN_settitle } BOOST_FIXTURE_TEST_CASE(test_getcount, FixtureOpenClose) { - int i, array[7]; + int i; - std::vector test; - std::vector ref = { 11, 2, 13, 1, 1, 2, 0 }; + std::vector test(7); + int *array = test.data(); + + std::vector ref = { 11, 2, 13, 1, 1, 2, 0 }; for (i=EN_NODECOUNT; i<=EN_RULECOUNT; i++) { - error = EN_getcount(ph, i, &array[i]); + error = EN_getcount(ph, i, array++); BOOST_REQUIRE(error == 0); } - test.assign(array, array + 7); BOOST_CHECK_EQUAL_COLLECTIONS(ref.begin(), ref.end(), test.begin(), test.end()); error = EN_getcount(ph, 7, &i); diff --git a/tests/test_report.cpp b/tests/test_report.cpp index f1268a3..5b5850c 100644 --- a/tests/test_report.cpp +++ b/tests/test_report.cpp @@ -21,9 +21,10 @@ BOOST_AUTO_TEST_SUITE (test_report) BOOST_FIXTURE_TEST_CASE(test_rprt_anlysstats, FixtureOpenClose) { int i; - double array[5]; - std::vector test; + std::vector test(5); + double *array = test.data(); + std::vector ref = {3.0, 7.0799498320679432e-06, 1.6680242187483429e-08, 0.0089173150106518495, 0.99999998187144024}; @@ -35,15 +36,13 @@ BOOST_FIXTURE_TEST_CASE(test_rprt_anlysstats, FixtureOpenClose) for (i=EN_ITERATIONS; i<=EN_MASSBALANCE; i++) { - error = EN_getstatistic(ph, i, &array[i]); + error = EN_getstatistic(ph, i, array++); BOOST_REQUIRE(error == 0); } - - test.assign(array, array + 5); -// BOOST_CHECK_EQUAL_COLLECTIONS(ref.begin(), ref.end(), test.begin(), test.end()); BOOST_CHECK(check_cdd_double(test, ref, 3)); - error = EN_getstatistic(ph, 8, &array[0]); + double temp; + error = EN_getstatistic(ph, 8, &temp); BOOST_CHECK(error == 251); } diff --git a/tests/test_toolkit.hpp b/tests/test_toolkit.hpp index 03ac664..7be983e 100644 --- a/tests/test_toolkit.hpp +++ b/tests/test_toolkit.hpp @@ -14,6 +14,9 @@ #ifndef TEST_TOOLKIT_HPP #define TEST_TOOLKIT_HPP +#define _CRTDBG_MAP_ALLOC +#include +#include #include "epanet2_2.h" @@ -25,6 +28,9 @@ struct FixtureOpenClose{ FixtureOpenClose() { + error = 0; + ph = NULL; + EN_createproject(&ph); error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT); } @@ -41,6 +47,9 @@ struct FixtureOpenClose{ struct FixtureAfterStep{ FixtureAfterStep() { + error = 0; + ph = NULL; + flag = 0; tstop = 10800; From b578380675b12c64cdde2d2d795ed09baf8e917d Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 3 Apr 2019 14:13:40 -0400 Subject: [PATCH 08/15] Update test_toolkit.hpp removing crtdbg.h from header --- tests/test_toolkit.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test_toolkit.hpp b/tests/test_toolkit.hpp index 7be983e..1373ce7 100644 --- a/tests/test_toolkit.hpp +++ b/tests/test_toolkit.hpp @@ -14,10 +14,6 @@ #ifndef TEST_TOOLKIT_HPP #define TEST_TOOLKIT_HPP -#define _CRTDBG_MAP_ALLOC -#include -#include - #include "epanet2_2.h" From be2b0a3ac837f6ec5313bc65e284faf622e8c555 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 3 Apr 2019 14:56:01 -0400 Subject: [PATCH 09/15] Update CMakeLists.txt Restoring test_net_builder to test_toolkit.exe --- tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a772b51..3d63d97 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,7 +30,7 @@ set(toolkit_test_srcs test_pattern.cpp test_curve.cpp test_control.cpp -# test_net_builder.cpp + test_net_builder.cpp ) add_executable(test_toolkit ${toolkit_test_srcs}) From 84bf6f98d04dd7055a50fb2c53416ac469c4e05a Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 3 Apr 2019 15:55:23 -0400 Subject: [PATCH 10/15] Cleaning up include statements adding crtdbg.h --- src/epanet.c | 20 +- src/epanet2.c | 8 +- src/epanet_py.c | 9 +- src/hash.c | 18 +- src/hydcoeffs.c | 57 ++-- src/hydraul.c | 227 +++++++------ src/hydsolver.c | 17 +- src/hydstatus.c | 15 +- src/inpfile.c | 29 +- src/input1.c | 31 +- src/input2.c | 62 ++-- src/input3.c | 14 +- src/mempool.c | 10 +- src/output.c | 47 +-- src/project.c | 8 +- src/quality.c | 15 +- src/qualreact.c | 7 + src/qualroute.c | 12 +- src/report.c | 16 +- src/rules.c | 12 +- src/smatrix.c | 13 +- tests/test_net_builder.cpp | 678 +++++++++++++++++++------------------ 22 files changed, 706 insertions(+), 619 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 8942f6e..82f44ea 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -11,12 +11,16 @@ ****************************************************************************** */ -#include -#include -#include -#ifndef __APPLE__ -#include +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include #endif +#include +#include + #include #include @@ -279,7 +283,7 @@ int DLLEXPORT EN_getcomment(EN_Project p, int object, int index, char *comment) /*---------------------------------------------------------------- ** Input: object = a type of object (see EN_ObjectType) ** index = the object's index -** Output: comment = the object's descriptive comment +** Output: comment = the object's descriptive comment ** Returns: error code ** Purpose: Retrieves an object's descriptive comment **---------------------------------------------------------------- @@ -840,7 +844,7 @@ int DLLEXPORT EN_closeQ(EN_Project p) if (!p->Openflag) return 102; closequal(p); p->quality.OpenQflag = FALSE; - closeoutfile(p); + closeoutfile(p); return 0; } @@ -1637,7 +1641,7 @@ int DLLEXPORT EN_setqualtype(EN_Project p, int qualType, char *chemName, p->network.Node[i].C0 *= Ucf[QUALITY]; } } - + Ucf[QUALITY] = ccf; Ucf[LINKQUAL] = ccf; Ucf[REACTRATE] = ccf; diff --git a/src/epanet2.c b/src/epanet2.c index 6ebb278..2490c64 100644 --- a/src/epanet2.c +++ b/src/epanet2.c @@ -10,10 +10,12 @@ Last Updated: 03/17/2019 ****************************************************************************** */ -#ifndef __APPLE__ -#include +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include #else -#include + #include #endif #include diff --git a/src/epanet_py.c b/src/epanet_py.c index b1b315d..6cc3302 100644 --- a/src/epanet_py.c +++ b/src/epanet_py.c @@ -11,8 +11,13 @@ ****************************************************************************** */ - -#include +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include #include "epanet_py.h" diff --git a/src/hash.c b/src/hash.c index 95ac8dd..5e8e7cd 100755 --- a/src/hash.c +++ b/src/hash.c @@ -11,11 +11,13 @@ ****************************************************************************** */ -#ifndef __APPLE__ -#include -#else -#include -#endif + #ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include + #else + #include + #endif #include #include "hash.h" @@ -84,7 +86,7 @@ int hashtable_update(HashTable *ht, char *key, int new_data) { unsigned int i = gethash(key); DataEntry *entry; - + if ( i >= HASHTABLEMAXSIZE ) return NOTFOUND; entry = ht[i]; while (entry != NULL) @@ -104,7 +106,7 @@ int hashtable_delete(HashTable *ht, char *key) { unsigned int i = gethash(key); DataEntry *entry, *preventry; - + if ( i >= HASHTABLEMAXSIZE ) return NOTFOUND; preventry = NULL; @@ -164,7 +166,7 @@ void hashtable_free(HashTable *ht) { DataEntry *entry, *nextentry; int i; - + for (i = 0; i < HASHTABLEMAXSIZE; i++) { entry = ht[i]; diff --git a/src/hydcoeffs.c b/src/hydcoeffs.c index b6c002c..69785d8 100644 --- a/src/hydcoeffs.c +++ b/src/hydcoeffs.c @@ -11,13 +11,16 @@ ****************************************************************************** */ +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif + #include #include "types.h" @@ -85,12 +88,12 @@ void resistcoeff(Project *pr, int k) double e, d, L; Slink *link = &net->Link[k]; - + link->Qa = 0.0; switch (link->Type) { // ... Link is a pipe. Compute resistance based on headloss formula. - // Friction factor for D-W formula gets included during head loss + // Friction factor for D-W formula gets included during head loss // calculation. case CVPIPE: case PIPE: @@ -244,14 +247,14 @@ void linkcoeffs(Project *pr) // Update linear system coeffs. associated with start node n1 // ... node n1 is junction - if (n1 <= net->Njuncs) + if (n1 <= net->Njuncs) { sm->Aii[sm->Row[n1]] += hyd->P[k]; // Diagonal coeff. sm->F[sm->Row[n1]] += hyd->Y[k]; // RHS coeff. } // ... node n1 is a tank/reservoir - else sm->F[sm->Row[n2]] += (hyd->P[k] * hyd->NodeHead[n1]); + else sm->F[sm->Row[n2]] += (hyd->P[k] * hyd->NodeHead[n1]); // Update linear system coeffs. associated with end node n2 // ... node n2 is junction @@ -262,7 +265,7 @@ void linkcoeffs(Project *pr) } // ... node n2 is a tank/reservoir - else sm->F[sm->Row[n1]] += (hyd->P[k] * hyd->NodeHead[n2]); + else sm->F[sm->Row[n1]] += (hyd->P[k] * hyd->NodeHead[n2]); } } @@ -321,13 +324,13 @@ void valvecoeffs(Project *pr) // Coeffs. for fixed status valves have already been computed if (hyd->LinkSetting[k] == MISSING) continue; - // Start & end nodes of valve's link + // Start & end nodes of valve's link link = &net->Link[k]; n1 = link->N1; n2 = link->N2; // Call valve-specific function - switch (link->Type) + switch (link->Type) { case PRV: prvcoeff(pr, k, n1, n2); @@ -482,7 +485,7 @@ void demandcoeffs(Project *pr) double dp, // pressure range over which demand can vary (ft) n, // exponent in head loss v. demand function hloss, // head loss in supplying demand (ft) - hgrad; // gradient of demand head loss (ft/cfs) + hgrad; // gradient of demand head loss (ft/cfs) // Get demand function parameters if (hyd->DemandModel == DDA) return; @@ -659,12 +662,12 @@ void DWpipecoeff(Project *pr, int k) Slink *link = &pr->network.Link[k]; double q = ABS(hyd->LinkFlow[k]); - double r = link->R; // Resistance coeff. - double ml = link->Km; // Minor loss coeff. + double r = link->R; // Resistance coeff. + double ml = link->Km; // Minor loss coeff. double e = link->Kc / link->Diam; // Relative roughness double s = hyd->Viscos * link->Diam; // Viscosity / diameter double hloss, hgrad, f, dfdq, r1; - + // Compute head loss and its derivative // ... use Hagen-Poiseuille formula for laminar flow (Re <= 2000) if (q <= A2 * s) @@ -673,7 +676,7 @@ void DWpipecoeff(Project *pr, int k) hloss = hyd->LinkFlow[k] * (r + ml * q); hgrad = r + 2.0 * ml * q; } - + // ... otherwise use Darcy-Weisbach formula with friction factor else { @@ -683,7 +686,7 @@ void DWpipecoeff(Project *pr, int k) hloss = r1 * q * hyd->LinkFlow[k]; hgrad = (2.0 * r1 * q) + (dfdq * r * q * q); } - + // Compute P and Y coefficients hyd->P[k] = 1.0 / hgrad; hyd->Y[k] = hloss / hgrad; @@ -753,7 +756,7 @@ void pumpcoeff(Project *pr, int k) int p; // Pump index double h0, // Shutoff head - q, // Abs. value of flow + q, // Abs. value of flow r, // Flow resistance coeff. n, // Flow exponent coeff. setting, // Pump speed setting @@ -899,7 +902,7 @@ void gpvcoeff(Project *pr, int k) Hydraul *hyd = &pr->hydraul; // Treat as a pipe if valve closed - if (hyd->LinkStatus[k] == CLOSED) valvecoeff(pr, k); + if (hyd->LinkStatus[k] == CLOSED) valvecoeff(pr, k); // Otherwise utilize segment of head loss curve // bracketing current flow (curve index is stored @@ -939,7 +942,7 @@ void pbvcoeff(Project *pr, int k) // If valve fixed OPEN or CLOSED then treat as a pipe if (hyd->LinkSetting[k] == MISSING || hyd->LinkSetting[k] == 0.0) { - valvecoeff(pr, k); + valvecoeff(pr, k); } // If valve is active @@ -948,7 +951,7 @@ void pbvcoeff(Project *pr, int k) // Treat as a pipe if minor loss > valve setting if (link->Km * SQR(hyd->LinkFlow[k]) > hyd->LinkSetting[k]) { - valvecoeff(pr, k); + valvecoeff(pr, k); } // Otherwise force headloss across valve to be equal to setting else @@ -983,7 +986,7 @@ void tcvcoeff(Project *pr, int k) } // Then apply usual valve formula - valvecoeff(pr, k); + valvecoeff(pr, k); // Restore original loss coeff. link->Km = km; @@ -1017,7 +1020,7 @@ void prvcoeff(Project *pr, int k, int n1, int n2) { // Set coeffs. to force head at downstream - // node equal to valve setting & force flow + // node equal to valve setting & force flow // to equal to flow excess at downstream node. hyd->P[k] = 0.0; @@ -1069,7 +1072,7 @@ void psvcoeff(Project *pr, int k, int n1, int n2) if (hyd->LinkStatus[k] == ACTIVE) { // Set coeffs. to force head at upstream - // node equal to valve setting & force flow + // node equal to valve setting & force flow // equal to flow excess at upstream node. hyd->P[k] = 0.0; @@ -1138,7 +1141,7 @@ void fcvcoeff(Project *pr, int k, int n1, int n2) else { - valvecoeff(pr, k); + valvecoeff(pr, k); sm->Aij[sm->Ndx[k]] -= hyd->P[k]; sm->Aii[i] += hyd->P[k]; sm->Aii[j] += hyd->P[k]; @@ -1162,7 +1165,7 @@ void valvecoeff(Project *pr, int k) Slink *link = &pr->network.Link[k]; double flow, q, y, qa, hgrad; - + flow = hyd->LinkFlow[k]; // Valve is closed. Use a very small matrix coeff. diff --git a/src/hydraul.c b/src/hydraul.c index 703f7b7..1e3532e 100755 --- a/src/hydraul.c +++ b/src/hydraul.c @@ -3,7 +3,7 @@ Project: OWA EPANET Version: 2.2 Module: hydraul.c - Description: implements EPANET's hydraulic engine + Description: implements EPANET's hydraulic engine Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE @@ -11,13 +11,16 @@ ****************************************************************************** */ +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif + #include #include "types.h" @@ -48,9 +51,9 @@ void tanklevels(Project *, long); int openhyd(Project *pr) /* *-------------------------------------------------------------- - * Input: none - * Output: returns error code - * Purpose: opens hydraulics solver system + * Input: none + * Output: returns error code + * Purpose: opens hydraulics solver system *-------------------------------------------------------------- */ { @@ -92,8 +95,8 @@ void inithyd(Project *pr, int initflag) **-------------------------------------------------------------- ** Input: initflag > 0 if link flows should be re-initialized ** = 0 if not -** Output: none -** Purpose: initializes hydraulics solver system +** Output: none +** Purpose: initializes hydraulics solver system **-------------------------------------------------------------- */ { @@ -106,7 +109,7 @@ void inithyd(Project *pr, int initflag) Stank *tank; Slink *link; Spump *pump; - + // Initialize tanks for (i = 1; i <= net->Ntanks; i++) { @@ -128,7 +131,7 @@ void inithyd(Project *pr, int initflag) for (i = 1; i <= net->Nlinks; i++) { link = &net->Link[i]; - + // Initialize status and setting hyd->LinkStatus[i] = link->Status; hyd->LinkSetting[i] = link->Kc; @@ -140,7 +143,7 @@ void inithyd(Project *pr, int initflag) if ( (link->Type == PRV || link->Type == PSV || link->Type == FCV) && (link->Kc != MISSING) - ) hyd->LinkStatus[i] = ACTIVE; + ) hyd->LinkStatus[i] = ACTIVE; // Initialize flows if necessary if (hyd->LinkStatus[i] <= CLOSED) @@ -170,7 +173,7 @@ void inithyd(Project *pr, int initflag) // Re-position hydraulics file if (pr->outfile.Saveflag) - { + { fseek(out->HydFile,out->HydOffset,SEEK_SET); } @@ -185,10 +188,10 @@ void inithyd(Project *pr, int initflag) int runhyd(Project *pr, long *t) /* **-------------------------------------------------------------- -** Input: none +** Input: none ** Output: t = pointer to current time (in seconds) -** Returns: error code -** Purpose: solves network hydraulics in a single time period +** Returns: error code +** Purpose: solves network hydraulics in a single time period **-------------------------------------------------------------- */ { @@ -199,7 +202,7 @@ int runhyd(Project *pr, long *t) int iter; // Iteration count int errcode; // Error code double relerr; // Solution accuracy - + // Find new demands & control actions *t = time->Htime; demands(pr); @@ -212,7 +215,7 @@ int runhyd(Project *pr, long *t) { // Report new status & save results if (rpt->Statflag) writehydstat(pr,iter,relerr); - + // If system unbalanced and no extra trials // allowed, then activate the Haltflag if (relerr > hyd->Hacc && hyd->ExtraIter == -1) @@ -229,11 +232,11 @@ int runhyd(Project *pr, long *t) int nexthyd(Project *pr, long *tstep) /* **-------------------------------------------------------------- -** Input: none +** Input: none ** Output: tstep = pointer to time step (in seconds) -** Returns: error code +** Returns: error code ** Purpose: finds length of next time step & updates tank -** levels and rule-based contol actions +** levels and rule-based contol actions **-------------------------------------------------------------- */ { @@ -242,7 +245,7 @@ int nexthyd(Project *pr, long *tstep) long hydstep; // Actual time step int errcode = 0; // Error code - + // Save current results to hydraulics file and // force end of simulation if Haltflag is active if (pr->outfile.Saveflag) errcode = savehyd(pr, &time->Htime); @@ -277,14 +280,14 @@ int nexthyd(Project *pr, long *tstep) *tstep = hydstep; return errcode; } - + void closehyd(Project *pr) /* **-------------------------------------------------------------- -** Input: none -** Output: returns error code -** Purpose: closes hydraulics solver system +** Input: none +** Output: returns error code +** Purpose: closes hydraulics solver system **-------------------------------------------------------------- */ { @@ -296,9 +299,9 @@ void closehyd(Project *pr) int allocmatrix(Project *pr) /* **-------------------------------------------------------------- -** Input: none -** Output: returns error code -** Purpose: allocates memory used for solution matrix coeffs. +** Input: none +** Output: returns error code +** Purpose: allocates memory used for solution matrix coeffs. **-------------------------------------------------------------- */ { @@ -306,7 +309,7 @@ int allocmatrix(Project *pr) Hydraul *hyd = &pr->hydraul; int errcode = 0; - + hyd->P = (double *) calloc(net->Nlinks+1,sizeof(double)); hyd->Y = (double *) calloc(net->Nlinks+1,sizeof(double)); hyd->DemandFlow = (double *) calloc(net->Nnodes + 1, sizeof(double)); @@ -328,14 +331,14 @@ int allocmatrix(Project *pr) void freematrix(Project *pr) /* **-------------------------------------------------------------- -** Input: none -** Output: none -** Purpose: frees memory used for solution matrix coeffs. +** Input: none +** Output: none +** Purpose: frees memory used for solution matrix coeffs. **-------------------------------------------------------------- */ { Hydraul *hyd = &pr->hydraul; - + free(hyd->P); free(hyd->Y); free(hyd->DemandFlow); @@ -351,7 +354,7 @@ void initlinkflow(Project *pr, int i, char s, double k) ** Input: i = link index ** s = link status ** k = link setting (i.e., pump speed) -** Output: none +** Output: none ** Purpose: sets initial flow in link to QZERO if link is closed, ** to design flow for a pump, or to flow at velocity of ** 1 fps for other links. @@ -362,7 +365,7 @@ void initlinkflow(Project *pr, int i, char s, double k) Network *n = &pr->network; Slink *link = &n->Link[i]; - + if (s == CLOSED) { hyd->LinkFlow[i] = QZERO; @@ -383,8 +386,8 @@ void setlinkflow(Project *pr, int k, double dh) **-------------------------------------------------------------- ** Input: k = link index ** dh = head loss across link -** Output: none -** Purpose: sets flow in link based on current headloss +** Output: none +** Purpose: sets flow in link based on current headloss **-------------------------------------------------------------- */ { @@ -396,7 +399,7 @@ void setlinkflow(Project *pr, int k, double dh) double x ,y; Slink *link = &net->Link[k]; Scurve *curve; - + switch (link->Type) { case CVPIPE: @@ -408,7 +411,7 @@ void setlinkflow(Project *pr, int k, double dh) y = sqrt(ABS(dh) / link->R / 1.32547); hyd->LinkFlow[k] = x * y; } - + // For Hazen-Williams or Manning formulas use inverse of formula else { @@ -416,16 +419,16 @@ void setlinkflow(Project *pr, int k, double dh) y = 1.0 / hyd->Hexp; hyd->LinkFlow[k] = pow(x, y); } - + // Change sign of flow to match sign of head loss if (dh < 0.0) hyd->LinkFlow[k] = -hyd->LinkFlow[k]; break; - + case PUMP: // Convert headloss to pump head gain dh = -dh; p = findpump(net, k); - + // For custom pump curve, interpolate from curve if (net->Pump[p].Ptype == CUSTOM) { @@ -435,7 +438,7 @@ void setlinkflow(Project *pr, int k, double dh) hyd->LinkFlow[k] = interp(curve->Npts, curve->Y, curve->X, dh) * hyd->LinkSetting[k] / pr->Ucf[FLOW]; } - + // Otherwise use inverse of power curve else { @@ -459,7 +462,7 @@ void setlinkstatus(Project *pr, int index, char value, StatusType *s, double *k ** s = pointer to link status ** k = pointer to link setting ** Output: none -** Purpose: sets link status to OPEN or CLOSED +** Purpose: sets link status to OPEN or CLOSED **---------------------------------------------------------------- */ { @@ -467,11 +470,11 @@ void setlinkstatus(Project *pr, int index, char value, StatusType *s, double *k Slink *link = &net->Link[index]; LinkType t = link->Type; - - // Status set to open + + // Status set to open if (value == 1) { - // Adjust link setting for pumps & valves + // Adjust link setting for pumps & valves if (t == PUMP) *k = 1.0; if (t > PUMP && t != GPV) *k = MISSING; @@ -479,7 +482,7 @@ void setlinkstatus(Project *pr, int index, char value, StatusType *s, double *k *s = OPEN; } - // Status set to closed + // Status set to closed else if (value == 0) { // Adjust link setting for pumps & valves @@ -509,7 +512,7 @@ void setlinksetting(Project *pr, int index, double value, StatusType *s, Slink *link = &net->Link[index]; LinkType t = link->Type; - + // For a pump, status is OPEN if speed > 0, CLOSED otherwise if (t == PUMP) { @@ -531,15 +534,15 @@ void setlinksetting(Project *pr, int index, double value, StatusType *s, if (*k == MISSING && *s <= CLOSED) *s = OPEN; *k = value; } -} +} void demands(Project *pr) /* **-------------------------------------------------------------------- -** Input: none -** Output: none -** Purpose: computes demands at nodes during current time period +** Input: none +** Output: none +** Purpose: computes demands at nodes during current time period **-------------------------------------------------------------------- */ { @@ -610,9 +613,9 @@ void demands(Project *pr) int controls(Project *pr) /* **--------------------------------------------------------------------- -** Input: none -** Output: number of links whose setting changes -** Purpose: implements simple controls based on time or tank levels +** Input: none +** Output: number of links whose setting changes +** Purpose: implements simple controls based on time or tank levels **--------------------------------------------------------------------- */ { @@ -626,7 +629,7 @@ int controls(Project *pr) double k1, k2; char s1, s2; Slink *link; - Scontrol *control; + Scontrol *control; // Examine each control statement setsum = 0; @@ -680,7 +683,7 @@ int controls(Project *pr) if (pr->report.Statflag) writecontrolaction(pr,k,i); setsum++; } - } + } } return setsum; } @@ -689,9 +692,9 @@ int controls(Project *pr) long timestep(Project *pr) /* **---------------------------------------------------------------- -** Input: none -** Output: returns time step until next change in hydraulics -** Purpose: computes time step to advance hydraulic simulation +** Input: none +** Output: returns time step until next change in hydraulics +** Purpose: computes time step to advance hydraulic simulation **---------------------------------------------------------------- */ { @@ -699,26 +702,26 @@ long timestep(Project *pr) Times *time = &pr->times; long n, t, tstep; - + // Normal time step is hydraulic time step tstep = time->Hstep; - + // Revise time step based on time until next demand period // (n = next pattern period, t = time till next period) n = ((time->Htime + time->Pstart) / time->Pstep) + 1; t = n * time->Pstep - time->Htime; if (t > 0 && t < tstep) tstep = t; - + // Revise time step based on time until next reporting period t = time->Rtime - time->Htime; if (t > 0 && t < tstep) tstep = t; - + // Revise time step based on smallest time to fill or drain a tank tanktimestep(pr, &tstep); - + // Revise time step based on smallest time to activate a control controltimestep(pr, &tstep); - + // Evaluate rule-based controls (which will also update tank levels) if (net->Nrules > 0) ruletimestep(pr, &tstep); else tanklevels(pr, tstep); @@ -729,10 +732,10 @@ long timestep(Project *pr) int tanktimestep(Project *pr, long *tstep) /* **----------------------------------------------------------------- -** Input: *tstep = current time step -** Output: *tstep = modified current time step +** Input: *tstep = current time step +** Output: *tstep = modified current time step ** Purpose: revises time step based on shortest time to fill or -** drain a tank +** drain a tank **----------------------------------------------------------------- */ { @@ -777,10 +780,10 @@ int tanktimestep(Project *pr, long *tstep) void controltimestep(Project *pr, long *tstep) /* **------------------------------------------------------------------ -** Input: *tstep = current time step -** Output: *tstep = modified current time step +** Input: *tstep = current time step +** Output: *tstep = modified current time step ** Purpose: revises time step based on shortest time to activate -** a simple control +** a simple control **------------------------------------------------------------------ */ { @@ -792,24 +795,24 @@ void controltimestep(Project *pr, long *tstep) long t, t1, t2; Slink *link; Scontrol *control; - + // Examine each control for (i = 1; i <= net->Ncontrols; i++) { t = 0; control = &net->Control[i]; - // Control depends on a tank level + // Control depends on a tank level if ( (n = control->Node) > 0) { // Skip node if not a tank or reservoir if ((j = n - net->Njuncs) <= 0) continue; - + // Find current head and flow into tank h = hyd->NodeHead[n]; q = hyd->NodeDemand[n]; if (ABS(q) <= QZERO) continue; - + // Find time to reach upper or lower control level if ( (h < control->Grade && control->Type == HILEVEL && q > 0.0) || (h > control->Grade && control->Type == LOWLEVEL && q < 0.0) ) @@ -821,7 +824,7 @@ void controltimestep(Project *pr, long *tstep) // Control is based on elapsed time if (control->Type == TIMER) - { + { if (control->Time > pr->times.Htime) { t = control->Time - pr->times.Htime; @@ -853,16 +856,16 @@ void controltimestep(Project *pr, long *tstep) void ruletimestep(Project *pr, long *tstep) /* **-------------------------------------------------------------- -** Input: *tstep = current time step (sec) -** Output: *tstep = modified time step +** Input: *tstep = current time step (sec) +** Output: *tstep = modified time step ** Purpose: updates next time step by checking if any rules -** will fire before then; also updates tank levels. +** will fire before then; also updates tank levels. **-------------------------------------------------------------- */ { Network *net = &pr->network; Times *time = &pr->times; - + long tnow, // Start of time interval for rule evaluation tmax, // End of time interval for rule evaluation dt, // Normal time increment for rule evaluation @@ -880,7 +883,7 @@ void ruletimestep(Project *pr, long *tstep) } // Otherwise, time increment equals rule evaluation time step and - // first actual increment equals time until next even multiple of + // first actual increment equals time until next even multiple of // Rulestep occurs. else { @@ -888,7 +891,7 @@ void ruletimestep(Project *pr, long *tstep) dt1 = time->Rulestep - (tnow % time->Rulestep); } - // Make sure time increment is no larger than current time step + // Make sure time increment is no larger than current time step dt = MIN(dt, *tstep); dt1 = MIN(dt1, *tstep); if (dt1 == 0) dt1 = dt; @@ -918,14 +921,14 @@ void ruletimestep(Project *pr, long *tstep) *tstep = time->Htime - tnow; time->Htime = tnow; } - + void addenergy(Project *pr, long hstep) /* **------------------------------------------------------------- -** Input: hstep = time step (sec) -** Output: none -** Purpose: accumulates pump energy usage +** Input: hstep = time step (sec) +** Output: none +** Purpose: accumulates pump energy usage **------------------------------------------------------------- */ { @@ -1003,10 +1006,10 @@ void addenergy(Project *pr, long hstep) void getenergy(Project *pr, int k, double *kw, double *eff) /* **---------------------------------------------------------------- -** Input: k = link index +** Input: k = link index ** Output: *kw = kwatt energy used ** *eff = efficiency (pumps only) -** Purpose: computes flow energy associated with link k +** Purpose: computes flow energy associated with link k **---------------------------------------------------------------- */ { @@ -1022,7 +1025,7 @@ void getenergy(Project *pr, int k, double *kw, double *eff) double speed; // current speed setting Scurve *curve; Slink *link = &net->Link[k]; - + // No energy if link is closed if (hyd->LinkStatus[k] <= CLOSED) { @@ -1065,10 +1068,10 @@ void getenergy(Project *pr, int k, double *kw, double *eff) void tanklevels(Project *pr, long tstep) /* **---------------------------------------------------------------- -** Input: tstep = current time step -** Output: none -** Purpose: computes new water levels in tanks after current -** time step +** Input: tstep = current time step +** Output: none +** Purpose: computes new water levels in tanks after current +** time step **---------------------------------------------------------------- */ { @@ -1077,17 +1080,17 @@ void tanklevels(Project *pr, long tstep) int i, n; double dv; - + for (i = 1; i <= net->Ntanks; i++) { Stank *tank = &net->Tank[i]; if (tank->A == 0.0) continue; // Skip reservoirs - - // Update the tank's volume & water elevation + + // Update the tank's volume & water elevation n = tank->Node; dv = hyd->NodeDemand[n] * tstep; tank->V += dv; - + // Check if tank full/empty within next second if (tank->V + hyd->NodeDemand[n] >= tank->Vmax) { @@ -1105,10 +1108,10 @@ void tanklevels(Project *pr, long tstep) double tankvolume(Project *pr, int i, double h) /* **-------------------------------------------------------------------- -** Input: i = tank index -** h = water elevation in tank -** Output: returns water volume in tank -** Purpose: finds water volume in tank i corresponding to elev. h. +** Input: i = tank index +** h = water elevation in tank +** Output: returns water volume in tank +** Purpose: finds water volume in tank i corresponding to elev. h. **-------------------------------------------------------------------- */ { @@ -1122,7 +1125,7 @@ double tankvolume(Project *pr, int i, double h) // Use level*area if no volume curve j = tank->Vcurve; if (j == 0) return(tank->Vmin + (h - tank->Hmin) * tank->A); - + // If curve exists, interpolate on h to find volume v // remembering that volume curve is in original units. else @@ -1138,10 +1141,10 @@ double tankvolume(Project *pr, int i, double h) double tankgrade(Project *pr, int i, double v) /* **------------------------------------------------------------------- -** Input: i = tank index -** v = volume in tank -** Output: returns water level in tank -** Purpose: finds water level in tank i corresponding to volume v. +** Input: i = tank index +** v = volume in tank +** Output: returns water level in tank +** Purpose: finds water level in tank i corresponding to volume v. **------------------------------------------------------------------- */ { @@ -1154,7 +1157,7 @@ double tankgrade(Project *pr, int i, double v) // Use area if no volume curve j = tank->Vcurve; if (j == 0) return(tank->Hmin + (v - tank->Vmin) / tank->A); - + // If curve exists, interpolate on volume (originally the Y-variable // but used here as the X-variable) to find new level above bottom. // Remember that volume curve is stored in original units. diff --git a/src/hydsolver.c b/src/hydsolver.c index 3c0694a..0b0da25 100644 --- a/src/hydsolver.c +++ b/src/hydsolver.c @@ -12,13 +12,16 @@ ****************************************************************************** */ +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif + #include #include "types.h" @@ -453,7 +456,7 @@ void newlinkflows(Project *pr, Hydbalance *hbal, double *qsum, double *dqsum) hbal->maxflownode = -1; } - // Update net flows to fixed grade nodes + // Update net flows to fixed grade nodes if (hyd->LinkStatus[k] > CLOSED) { if (n1 > net->Njuncs) hyd->NodeDemand[n1] -= hyd->LinkFlow[k]; @@ -487,7 +490,7 @@ void newemitterflows(Project *pr, Hydbalance *hbal, double *qsum, // Skip junction if it does not have an emitter if (net->Node[i].Ke == 0.0) continue; - // Find emitter head loss and gradient + // Find emitter head loss and gradient emitheadloss(pr, i, &hloss, &hgrad); // Find emitter flow change diff --git a/src/hydstatus.c b/src/hydstatus.c index f7edb6b..2a4d20e 100644 --- a/src/hydstatus.c +++ b/src/hydstatus.c @@ -10,8 +10,15 @@ License: see LICENSE Last Updated: 11/27/2018 ****************************************************************************** */ - +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include + #include "types.h" #include "funcs.h" @@ -48,7 +55,7 @@ int valvestatus(Project *pr) n1, n2; // Start & end nodes double hset; // Valve head setting StatusType status; // Valve status settings - Slink *link; + Slink *link; // Examine each valve for (i = 1; i <= net->Nvalves; i++) @@ -59,7 +66,7 @@ int valvestatus(Project *pr) // Ignore valve if its status is fixed to OPEN/CLOSED if (hyd->LinkSetting[k] == MISSING) continue; - + // Get start/end node indexes & save current status n1 = link->N1; n2 = link->N2; @@ -449,7 +456,7 @@ void tankstatus(Project *pr, int k, int n1, int n2) // Case 2: Downstream head > tank head // (e.g., an open outflow check valve would close) - else if (cvstatus(pr, OPEN, h, q) == CLOSED) + else if (cvstatus(pr, OPEN, h, q) == CLOSED) { hyd->LinkStatus[k] = TEMPCLOSED; } diff --git a/src/inpfile.c b/src/inpfile.c index 8aa3c52..f09eb2e 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -11,13 +11,16 @@ Last Updated: 04/02/2019 ****************************************************************************** */ +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif + #include #include "types.h" @@ -38,7 +41,7 @@ extern char *TstatTxt[]; extern char *RptFlagTxt[]; extern char *SectTxt[]; -void saveauxdata(Project *pr, FILE *f) +void saveauxdata(Project *pr, FILE *f) /* ------------------------------------------------------------ Writes auxilary data from original input file to new file. @@ -51,7 +54,7 @@ void saveauxdata(Project *pr, FILE *f) char line[MAXLINE + 1]; char s[MAXLINE + 1]; FILE *InFile = pr->parser.InFile; - + // Re-open the input file if (InFile == NULL) { @@ -88,7 +91,7 @@ void saveauxdata(Project *pr, FILE *f) } } } - + // Write line of auxilary data to file else { @@ -147,7 +150,7 @@ int saveinpfile(Project *pr, const char *fname) // Open the new text file if ((f = fopen(fname, "wt")) == NULL) return 302; - // Write [TITLE] section + // Write [TITLE] section fprintf(f, s_TITLE); for (i = 0; i < 3; i++) { @@ -205,7 +208,7 @@ int saveinpfile(Project *pr, const char *fname) } } - // Write [PIPES] section + // Write [PIPES] section fprintf(f, "\n\n"); fprintf(f, s_PIPES); for (i = 1; i <= net->Nlinks; i++) @@ -244,7 +247,7 @@ int saveinpfile(Project *pr, const char *fname) // Pump has constant power if (pump->Ptype == CONST_HP) sprintf(s1, " POWER %.4f", link->Km); - // Pump has a head curve + // Pump has a head curve else if ((j = pump->Hcurve) > 0) { sprintf(s1, " HEAD %s", net->Curve[j].ID); @@ -539,7 +542,7 @@ int saveinpfile(Project *pr, const char *fname) fprintf(f, "\n ORDER TANK %-.2f", qual->TankOrder); fprintf(f, "\n GLOBAL BULK %-.6f", qual->Kbulk * SECperDAY); fprintf(f, "\n GLOBAL WALL %-.6f", qual->Kwall * SECperDAY); - + if (qual->Climit > 0.0) { fprintf(f, "\n LIMITING POTENTIAL %-.6f", qual->Climit * pr->Ucf[QUALITY]); @@ -548,7 +551,7 @@ int saveinpfile(Project *pr, const char *fname) { fprintf(f, "\n ROUGHNESS CORRELATION %-.6f", qual->Rfactor); } - + // Pipe-specific parameters for (i = 1; i <= net->Nlinks; i++) { diff --git a/src/input1.c b/src/input1.c index fe606d9..694d3f6 100644 --- a/src/input1.c +++ b/src/input1.c @@ -3,7 +3,7 @@ Project: OWA EPANET Version: 2.2 Module: input1.c -Description: retrieves network data from an EPANET input file +Description: retrieves network data from an EPANET input file Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE @@ -11,18 +11,23 @@ Last Updated: 03/17/2019 ****************************************************************************** */ -#include -#include -#include -#ifndef __APPLE__ -#include +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include #endif +#include +#include + +#include #include "types.h" #include "funcs.h" #include "hash.h" #include "text.h" -#include + // Default values #define MAXITER 200 // Default max. # hydraulic iterations @@ -56,7 +61,7 @@ int getdata(Project *pr) int errcode = 0; // Assign default data values & reporting options - setdefaults(pr); + setdefaults(pr); initreport(&pr->report); // Read in network data @@ -102,7 +107,7 @@ void setdefaults(Project *pr) parser->Pressflag = PSI; // Pressure units are psi out->Hydflag = SCRATCH; // No external hydraulics file rpt->Tstatflag = SERIES; // Generate time series output - + hyd->Formflag = HW; // Use Hazen-Williams formula hyd->Htol = HTOL; // Default head tolerance hyd->Qtol = QTOL; // Default flow tolerance @@ -353,7 +358,7 @@ int inittanks(Project *pr) */ { Network *net = &pr->network; - + int i, j, n = 0; double a; int errcode = 0, levelerr; @@ -546,7 +551,7 @@ void convertunits(Project *pr) Slink *link; Spump *pump; Scontrol *control; - + // Convert nodal elevations & initial WQ // (WQ source units are converted in QUALITY.C for (i = 1; i <= net->Nnodes; i++) @@ -644,7 +649,7 @@ void convertunits(Project *pr) pump->H0 /= pr->Ucf[HEAD]; pump->R *= (pow(pr->Ucf[FLOW], pump->N) / pr->Ucf[HEAD]); } - + // Convert flow range & max. head units pump->Q0 /= pr->Ucf[FLOW]; pump->Qmax /= pr->Ucf[FLOW]; @@ -653,7 +658,7 @@ void convertunits(Project *pr) } else { - // For flow control valves, convert flow setting + // For flow control valves, convert flow setting // while for other valves convert pressure setting link->Diam /= pr->Ucf[DIAM]; link->Km = 0.02517 * link->Km / SQR(link->Diam) / SQR(link->Diam); diff --git a/src/input2.c b/src/input2.c index f1d0c9f..f7af31d 100644 --- a/src/input2.c +++ b/src/input2.c @@ -11,12 +11,16 @@ Last Updated: 04/02/2019 ****************************************************************************** */ -#include -#include -#include -#ifndef __APPLE__ -#include +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include #endif +#include +#include + #include #include "types.h" @@ -56,7 +60,7 @@ int netsize(Project *pr) */ { Parser *parser = &pr->parser; - + char line[MAXLINE + 1]; // Line from input data file char *tok; // First token of line int sect, newsect; // Input data sections @@ -246,10 +250,10 @@ int readdata(Project *pr) // Stop if reach end of file or max. error count if (errsum == MAXERRS) break; } - + // Check for errors if (errsum > 0) errcode = 200; - + // Check for unlinked nodes if (!errcode) errcode = unlinked(pr); @@ -397,7 +401,7 @@ int updatepumpparams(Project *pr, int pumpindex) curve->Type = PUMP_CURVE; npts = curve->Npts; - // Generic power function curve + // Generic power function curve if (npts == 1) { pump->Ptype = POWER_FUNC; @@ -407,7 +411,7 @@ int updatepumpparams(Project *pr, int pumpindex) q2 = 2.0 * q1; h2 = 0.0; } - + // 3 point curve with shutoff head else if (npts == 3 && curve->X[0] == 0.0) { @@ -418,7 +422,7 @@ int updatepumpparams(Project *pr, int pumpindex) q2 = curve->X[2]; h2 = curve->Y[2]; } - + // Custom pump curve else { @@ -431,7 +435,7 @@ int updatepumpparams(Project *pr, int pumpindex) 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) { @@ -461,7 +465,7 @@ int addnodeID(Network *net, int n, char *id) **-------------------------------------------------------------- */ { - if (findnode(net,id)) return 0; + if (findnode(net,id)) return 0; strncpy(net->Node[n].ID, id, MAXID); hashtable_insert(net->NodeHashTable, net->Node[n].ID, n); return 1; @@ -587,7 +591,7 @@ int unlinked(Project *pr) Network *net = &pr->network; int *marked; int i, err, errcode; - + errcode = 0; err = 0; @@ -596,19 +600,19 @@ int unlinked(Project *pr) ERRCODE(MEMCHECK(marked)); if (errcode) return errcode; memset(marked, 0, (net->Nnodes + 1) * sizeof(int)); - + // Mark end nodes of each link for (i = 1; i <= net->Nlinks; i++) { marked[net->Link[i].N1]++; marked[net->Link[i].N2]++; } - + // Check each junction for (i = 1; i <= net->Njuncs; i++) { // If not marked then error - if (marked[i] == 0) + if (marked[i] == 0) { err++; sprintf(pr->Msg, "Error 233: %s %s", geterrmsg(233, pr->Msg), net->Node[i].ID); @@ -638,7 +642,7 @@ int getpatterns(Project *pr) SFloatlist *f; STmplist *tmppattern; Spattern *pattern; - + // Start at head of the list of patterns tmppattern = parser->Patlist; @@ -696,7 +700,7 @@ int getcurves(Project *pr) { Network *net = &pr->network; Parser *parser = &pr->parser; - + int i, j; double x; char errmsg[MAXMSG+1]; @@ -827,14 +831,14 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment) int m, n; size_t len; char *c, *c2; - + // clear comment comment[0] = '\0'; - + // Begin with no tokens for (n=0; n 0 && n < MAXTOKS) { @@ -874,7 +878,7 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment) { s++; // Start token after quote m = (int)strcspn(s,"\"\n\r"); // Find end quote (or EOL) - } + } s[m] = '\0'; // Null-terminate the token Tok[n] = s; // Save pointer to token n++; // Update token count @@ -882,7 +886,7 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment) } } return n; -} +} double hour(char *time, char *units) /* @@ -920,7 +924,7 @@ double hour(char *time, char *units) if (match(units, w_DAYS)) return (y[0] * 24.0); } - // Convert hh:mm:ss format to decimal hours + // Convert hh:mm:ss format to decimal hours if (n > 1) y[0] = y[0] + y[1] / 60.0 + y[2] / 3600.0; // If am/pm attached then adjust hour accordingly @@ -939,7 +943,7 @@ double hour(char *time, char *units) else return (y[0] + 12.0); } return -1.0; -} +} int getfloat(char *s, double *y) /* @@ -985,14 +989,14 @@ void inperrmsg(Project *pr, int err, int sect, char *line) */ { Parser *parser = &pr->parser; - + char errStr[MAXMSG + 1] = ""; char tok[MAXMSG + 1]; // Get token associated with input error if (parser->ErrTok >= 0) strcpy(tok, parser->Tok[parser->ErrTok]); else strcpy(tok, ""); - + // write error message to report file sprintf(pr->Msg, "Error %d: %s %s in %s section:", err, geterrmsg(err, errStr), tok, SectTxt[sect]); diff --git a/src/input3.c b/src/input3.c index fb35da2..2a32179 100644 --- a/src/input3.c +++ b/src/input3.c @@ -11,12 +11,16 @@ Last Updated: 03/17/2019 ****************************************************************************** */ -#include -#include -#include -#ifndef __APPLE__ -#include +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include #endif +#include +#include + #include #include "types.h" diff --git a/src/mempool.c b/src/mempool.c index 55552ed..eb75e43 100755 --- a/src/mempool.c +++ b/src/mempool.c @@ -14,10 +14,14 @@ ****************************************************************************** */ -#include -#ifndef __APPLE__ -#include +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include #endif + #include "mempool.h" /* diff --git a/src/output.c b/src/output.c index fd92077..5082cbb 100644 --- a/src/output.c +++ b/src/output.c @@ -11,13 +11,16 @@ Last Updated: 11/27/2018 ****************************************************************************** */ +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif + #include #include "types.h" @@ -32,7 +35,7 @@ static int savetimestat(Project *, REAL4 *, HdrType); static int savenetreacts(Project *, double, double, double, double); static int saveepilog(Project *); -// Functions to write/read x[1] to x[n] to/from binary file +// Functions to write/read x[1] to x[n] to/from binary file size_t f_save(REAL4 *x, int n, FILE *file) { return fwrite(x + 1, sizeof(REAL4), n, file); @@ -79,7 +82,7 @@ int savenetdata(Project *pr) { // Write integer variables to outFile ibuf[0] = MAGICNUMBER; - ibuf[1] = 20012; // keep version at 2.00.12 so that GUI will run + ibuf[1] = 20012; // keep version at 2.00.12 so that GUI will run ibuf[2] = net->Nnodes; ibuf[3] = net->Ntanks; ibuf[4] = net->Nlinks; @@ -141,7 +144,7 @@ int savenetdata(Project *pr) x[i] = (REAL4)(net->Node[i].El * pr->Ucf[ELEV]); } f_save(x, net->Nnodes, outFile); - + // Save link lengths & diameters to outFile for (i = 1; i <= net->Nlinks; i++) { @@ -185,7 +188,7 @@ int savehyd(Project *pr, long *htime) int errcode = 0; REAL4 *x; FILE *HydFile = out->HydFile; - + x = (REAL4 *)calloc(MAX(net->Nnodes, net->Nlinks) + 1, sizeof(REAL4)); if (x == NULL) return 101; @@ -212,13 +215,13 @@ int savehyd(Project *pr, long *htime) fwrite(x + 1, sizeof(REAL4), net->Nlinks, HydFile); //f_save(x, net->Nlinks, HydFile); - // Save link status + // Save link status for (i = 1; i <= net->Nlinks; i++) x[i] = (REAL4)hyd->LinkStatus[i]; fwrite(x + 1, sizeof(REAL4), net->Nlinks, HydFile); //f_save(x, net->Nlinks, HydFile); - // Save link settings & check for successful write-to-disk - // (We assume that if any of the previous fwrites failed, + // Save link settings & check for successful write-to-disk + // (We assume that if any of the previous fwrites failed, // then this one will also fail.) for (i = 1; i <= net->Nlinks; i++) x[i] = (REAL4)hyd->LinkSetting[i]; if (fwrite(x + 1, sizeof(REAL4), net->Nlinks, HydFile) < @@ -354,7 +357,7 @@ int readhyd(Project *pr, long *hydtime) int result = 1; REAL4 *x; FILE *HydFile = out->HydFile; - + x = (REAL4 *)calloc(MAX(net->Nnodes, net->Nlinks) + 1, sizeof(REAL4)); if (x == NULL) return 0; @@ -473,7 +476,7 @@ int nodeoutput(Project *pr, int j, REAL4 *x, double ucf) } } - // Write x[1] to x[net->Nnodes] to output file + // Write x[1] to x[net->Nnodes] to output file if (f_save(x, net->Nnodes, outFile) < (unsigned)net->Nnodes) return 308; return 0; } @@ -497,7 +500,7 @@ int linkoutput(Project *pr, int j, REAL4 *x, double ucf) int i; double a, h, q, f, setting; FILE *outFile = out->TmpOutFile; - + // Load computed results (in proper units) into buffer x switch (j) { @@ -631,7 +634,7 @@ int savefinaloutput(Project *pr) int errcode = 0; REAL4 *x; FILE *outFile = out->OutFile; - + // Save time series statistic if computed if (rpt->Tstatflag != SERIES && out->TmpOutFile != NULL) { @@ -680,7 +683,7 @@ int savetimestat(Project *pr, REAL4 *x, HdrType objtype) long startbyte, skipbytes; float *stat1, *stat2, xx; FILE *outFile = out->OutFile; - + // Compute number of bytes in temp output file to skip over (skipbytes) // when moving from one time period to the next for a particular variable if (objtype == NODEHDR) @@ -722,11 +725,11 @@ int savetimestat(Project *pr, REAL4 *x, HdrType objtype) stat2[i] = MISSING; } - // Position temp output file at start of output + // Position temp output file at start of output fseek(out->TmpOutFile, startbyte + (j - n1) * n * sizeof(REAL4), SEEK_SET); - // Process each time period + // Process each time period for (p = 1; p <= rpt->Nperiods; p++) { // Get output results for time period & update stats @@ -751,7 +754,7 @@ int savetimestat(Project *pr, REAL4 *x, HdrType objtype) } } - // Advance file to next period + // Advance file to next period if (p < rpt->Nperiods) fseek(out->TmpOutFile, skipbytes, SEEK_CUR); } @@ -821,7 +824,7 @@ int savenetreacts(Project *pr, double wbulk, double wwall, double wtank, double double t; REAL4 w[4]; FILE *outFile = out->OutFile; - + if (time->Dur > 0) t = (double)time->Dur / 3600.; else t = 1.; w[0] = (REAL4)(wbulk / t); @@ -846,7 +849,7 @@ int saveepilog(Project *pr) int errcode = 0; INT4 i; FILE *outFile = out->OutFile; - + i = rpt->Nperiods; if (fwrite(&i, sizeof(INT4), 1, outFile) < 1) errcode = 308; i = pr->Warnflag; diff --git a/src/project.c b/src/project.c index 1e99817..a2e5654 100644 --- a/src/project.c +++ b/src/project.c @@ -11,7 +11,13 @@ ****************************************************************************** */ -#include +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include #include diff --git a/src/quality.c b/src/quality.c index de27f63..d46bd68 100644 --- a/src/quality.c +++ b/src/quality.c @@ -11,13 +11,16 @@ Last Updated: 11/27/2018 ****************************************************************************** */ +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif + #include #include "mempool.h" @@ -60,7 +63,7 @@ int openqual(Project *pr) int errcode = 0; int n; - + // Return if no quality analysis requested if (qual->Qualflag == NONE) return errcode; diff --git a/src/qualreact.c b/src/qualreact.c index 0805a21..8faf89b 100644 --- a/src/qualreact.c +++ b/src/qualreact.c @@ -11,6 +11,13 @@ Last Updated: 11/27/2018 ****************************************************************************** */ +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include #include #include "types.h" diff --git a/src/qualroute.c b/src/qualroute.c index 72bb66f..aa8e26a 100644 --- a/src/qualroute.c +++ b/src/qualroute.c @@ -11,13 +11,17 @@ Last Updated: 11/27/2018 ****************************************************************************** */ -#include -#ifndef __APPLE__ -#include +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include #else -#include + #include #endif +#include + #include + #include "mempool.h" #include "types.h" diff --git a/src/report.c b/src/report.c index 5605ffb..c35d73f 100644 --- a/src/report.c +++ b/src/report.c @@ -11,13 +11,15 @@ ****************************************************************************** */ +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif #ifdef _WIN32 #define snprintf _snprintf @@ -83,7 +85,7 @@ int copyreport(Project* pr, char *filename) FILE *tfile; int c; Report *rpt = &pr->report; - + // Check that project's report file exists if (rpt->RptFile == NULL) return 0; @@ -101,7 +103,7 @@ int copyreport(Project* pr, char *filename) while ((c = fgetc(rpt->RptFile)) != EOF) fputc(c, tfile); fclose(rpt->RptFile); } - + // Close destination file fclose(tfile); diff --git a/src/rules.c b/src/rules.c index 7e9945f..d0addb8 100644 --- a/src/rules.c +++ b/src/rules.c @@ -11,13 +11,15 @@ ****************************************************************************** */ +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif #include "types.h" #include "funcs.h" diff --git a/src/smatrix.c b/src/smatrix.c index 510bb3e..1b14794 100755 --- a/src/smatrix.c +++ b/src/smatrix.c @@ -18,13 +18,16 @@ linsolve() -- called from netsolve() in HYDRAUL.C */ +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif + #include #include diff --git a/tests/test_net_builder.cpp b/tests/test_net_builder.cpp index cb7bf16..577d0df 100644 --- a/tests/test_net_builder.cpp +++ b/tests/test_net_builder.cpp @@ -11,6 +11,14 @@ ****************************************************************************** */ +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif + #include #include "test_toolkit.hpp" @@ -37,7 +45,7 @@ struct FixtureInitClose { FixtureInitClose() { error = 0; ph = NULL; - + EN_createproject(&ph); EN_init(ph, DATA_PATH_RPT, DATA_PATH_OUT, EN_GPM, EN_HW); } @@ -53,359 +61,359 @@ struct FixtureInitClose { -//BOOST_AUTO_TEST_CASE(net_builder_I) -//{ -// int error = 0; -// int flag = 00; -// long t, tstep; -// int i, ind, Lindex, Nindex, Cindex; -// double h_orig, h_build, h_build_loaded; -// -// // first we load Net1.inp, run it and record the head in Tank 2 at the end of the simulation (h_orig) -// EN_Project ph = NULL; -// EN_createproject(&ph); -// -// std::string path_inp = std::string(DATA_PATH_NET1); -// 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(), path_out.c_str()); -// BOOST_REQUIRE(error == 0); -// -// error = EN_getnodeindex(ph, (char *)"2", &Nindex); -// BOOST_REQUIRE(error == 0); -// -// 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); -// -// // this is the head at the end of the simulation after loading the original Net1.inp -// error = EN_getnodevalue(ph, Nindex, EN_HEAD, &h_orig); -// BOOST_REQUIRE(error == 0); -// -// error = EN_nextH(ph, &tstep); -// BOOST_REQUIRE(error == 0); -// -// } while (tstep > 0); -// -// error = EN_closeH(ph); -// BOOST_REQUIRE(error == 0); -// -// error = EN_close(ph); -// BOOST_REQUIRE(error == 0); -// -// EN_deleteproject(&ph); -//} - -// BOOST_FIXTURE_TEST_CASE(test_build_net1, FixtureInitClose) -// { -// int flag = 00; -// long t, tstep; -// int i, ind, Lindex, Nindex, Cindex; -// double h_build; -// -// // now we build Net1 from scratch... -// char juncs[9][10] = { "10", "11", "12", "13", "21", "22", "23", "31", "32" }; -// double e[9] = { 710, 710, 700, 695, 700, 695, 690, 700, 710 }; -// double d[9] = { 0, 150, 150, 100, 150, 200, 150, 100, 100 }; -// double X[9] = { 20, 30, 50, 70, 30, 50, 70, 30, 50 }; -// double Y[9] = { 70, 70, 70, 70, 40, 40, 40, 10, 10 }; -// double L[12] = { 10530, 5280, 5280, 5280, 5280, 5280, 200, 5280, 5280, 5280, 5280, 5280 }; -// double dia[12] = { 18, 14, 10, 10, 12, 6, 18, 10, 12, 8, 8, 6 }; -// double P[12] = { 1.0f, 1.2f, 1.4f, 1.6f, 1.4f, 1.2f, 1.0f, 0.8f, 0.6f, 0.4f, 0.6f, 0.8f }; -// -// error = EN_addpattern(ph, (char *)"pat1"); -// BOOST_REQUIRE(error == 0); -// error = EN_setpattern(ph, 1, P, 12); -// BOOST_REQUIRE(error == 0); -// error = EN_setoption(ph, EN_DEFDEMANDPAT, 1); -// BOOST_REQUIRE(error == 0); -// for (i = 0; i < 9; i++) -// { -// error = EN_addnode(ph, juncs[i], EN_JUNCTION); -// BOOST_REQUIRE(error == 0); -// error = EN_setnodevalue(ph, i + 1, EN_ELEVATION, e[i]); -// BOOST_REQUIRE(error == 0); -// error = EN_setnodevalue(ph, i + 1, EN_BASEDEMAND, d[i]); -// BOOST_REQUIRE(error == 0); -// error = EN_setcoord(ph, i + 1, X[i], Y[i]); -// BOOST_REQUIRE(error == 0); -// //error = EN_setdemandpattern(ph, i + 1, 1, 1); -// //BOOST_REQUIRE(error == 0); -// } -// error = EN_addnode(ph, (char *)"9", EN_RESERVOIR); -// BOOST_REQUIRE(error == 0); -// error = EN_setcoord(ph, 10, 10, 70); -// BOOST_REQUIRE(error == 0); -// error = EN_setnodevalue(ph, 10, EN_ELEVATION, 800); -// BOOST_REQUIRE(error == 0); -// -// error = EN_addnode(ph, (char *)"2", EN_TANK); -// BOOST_REQUIRE(error == 0); -// error = EN_setcoord(ph, 11, 50, 90); -// BOOST_REQUIRE(error == 0); -// error = EN_setnodevalue(ph, 11, EN_TANKDIAM, 50.5); -// BOOST_REQUIRE(error == 0); -// error = EN_setnodevalue(ph, 11, EN_ELEVATION, 850); -// BOOST_REQUIRE(error == 0); -// error = EN_setnodevalue(ph, 11, EN_MAXLEVEL, 150); -// BOOST_REQUIRE(error == 0); -// error = EN_setnodevalue(ph, 11, EN_TANKLEVEL, 120); -// BOOST_REQUIRE(error == 0); -// error = EN_setnodevalue(ph, 11, EN_MINLEVEL, 100); -// BOOST_REQUIRE(error == 0); -// error = EN_setnodevalue(ph, 11, EN_MIXFRACTION, 1); -// BOOST_REQUIRE(error == 0); -// -// error = EN_addlink(ph, (char *)"10", EN_PIPE, (char *)"10", (char *)"11"); -// BOOST_REQUIRE(error == 0); -// error = EN_addlink(ph, (char *)"11", EN_PIPE, (char *)"11", (char *)"12"); -// BOOST_REQUIRE(error == 0); -// error = EN_addlink(ph, (char *)"12", EN_PIPE, (char *)"12", (char *)"13"); -// BOOST_REQUIRE(error == 0); -// error = EN_addlink(ph, (char *)"21", EN_PIPE, (char *)"21", (char *)"22"); -// BOOST_REQUIRE(error == 0); -// error = EN_addlink(ph, (char *)"22", EN_PIPE, (char *)"22", (char *)"23"); -// BOOST_REQUIRE(error == 0); -// error = EN_addlink(ph, (char *)"31", EN_PIPE, (char *)"31", (char *)"32"); -// BOOST_REQUIRE(error == 0); -// error = EN_addlink(ph, (char *)"110", EN_PIPE, (char *)"2", (char *)"12"); -// BOOST_REQUIRE(error == 0); -// error = EN_addlink(ph, (char *)"111", EN_PIPE, (char *)"11", (char *)"21"); -// BOOST_REQUIRE(error == 0); -// error = EN_addlink(ph, (char *)"112", EN_PIPE, (char *)"12", (char *)"22"); -// BOOST_REQUIRE(error == 0); -// error = EN_addlink(ph, (char *)"113", EN_PIPE, (char *)"13", (char *)"23"); -// BOOST_REQUIRE(error == 0); -// error = EN_addlink(ph, (char *)"121", EN_PIPE, (char *)"21", (char *)"31"); -// BOOST_REQUIRE(error == 0); -// error = EN_addlink(ph, (char *)"122", EN_PIPE, (char *)"22", (char *)"32"); -// BOOST_REQUIRE(error == 0); -// for (i = 0; i < 12; i++) -// { -// error = EN_setlinkvalue(ph, i + 1, EN_LENGTH, L[i]); -// BOOST_REQUIRE(error == 0); -// error = EN_setlinkvalue(ph, i + 1, EN_DIAMETER, dia[i]); -// BOOST_REQUIRE(error == 0); -// } -// -// error = EN_addlink(ph, (char *)"9", EN_PUMP, (char *)"9", (char *)"10"); -// BOOST_REQUIRE(error == 0); -// error = EN_addcurve(ph, (char *)"1"); -// BOOST_REQUIRE(error == 0); -// error = EN_setcurvevalue(ph, 1, 1, 1500, 250); -// BOOST_REQUIRE(error == 0); -// error = EN_getlinkindex(ph, (char *)"9", &ind); -// BOOST_REQUIRE(error == 0); -// error = EN_setheadcurveindex(ph, ind, 1); -// BOOST_REQUIRE(error == 0); -// -// error = EN_settimeparam(ph, EN_DURATION, 24 * 3600); -// BOOST_REQUIRE(error == 0); -// error = EN_settimeparam(ph, EN_PATTERNSTEP, 2 * 3600); -// BOOST_REQUIRE(error == 0); -// -// error = EN_getlinkindex(ph, (char *)"9", &Lindex); -// BOOST_REQUIRE(error == 0); -// error = EN_getnodeindex(ph, (char *)"2", &Nindex); -// BOOST_REQUIRE(error == 0); -// -// // Add controls -// error = EN_addcontrol(ph, EN_LOWLEVEL, Lindex, 1, Nindex, 110, &Cindex); -// BOOST_REQUIRE(error == 0); -// error = EN_addcontrol(ph, EN_HILEVEL, Lindex, 0, Nindex, 140, &Cindex); -// BOOST_REQUIRE(error == 0); -// -// error = EN_openH(ph); -// BOOST_REQUIRE(error == 0); -// error = EN_initH(ph, 0); -// BOOST_REQUIRE(error == 0); -// do { -// error = EN_runH(ph, &t); -// BOOST_REQUIRE(error == 0); -// // this is the head at the end of the simulation after building the network *without* saving it to file -// error = EN_getnodevalue(ph, Nindex, EN_HEAD, &h_build); -// BOOST_REQUIRE(error == 0); -// error = EN_nextH(ph, &tstep); -// BOOST_REQUIRE(error == 0); -// } while (tstep > 0); -// error = EN_closeH(ph); -// BOOST_REQUIRE(error == 0); -// -// error = EN_saveinpfile(ph, "net_builder.inp"); -// BOOST_REQUIRE(error == 0); -// } -// -// BOOST_AUTO_TEST_CASE(test_open_net1, * boost::unit_test::depends_on("test_net_builder/test_build_net1")) +// BOOST_AUTO_TEST_CASE(net_builder_I) // { // int error = 0; // int flag = 00; // long t, tstep; -// int Nindex = -1; -// double h_orig = 0.0, h_build = 0.0, h_build_loaded = 0.0; -// +// int i, ind, Lindex, Nindex, Cindex; +// double h_orig, h_build, h_build_loaded; // +// // first we load Net1.inp, run it and record the head in Tank 2 at the end of the simulation (h_orig) // EN_Project ph = NULL; +// EN_createproject(&ph); // -// // now we load the netwok we just built and saved -// EN_createproject(&ph); -// error = EN_open(ph, "net_builder.inp", DATA_PATH_RPT, DATA_PATH_OUT); -// BOOST_REQUIRE(error == 0); +// std::string path_inp = std::string(DATA_PATH_NET1); +// 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(), path_out.c_str()); +// BOOST_REQUIRE(error == 0); // // error = EN_getnodeindex(ph, (char *)"2", &Nindex); // BOOST_REQUIRE(error == 0); // -// 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); -// // this is the head at the end of the simulation after building the network and saving it to file -// error = EN_getnodevalue(ph, Nindex, EN_HEAD, &h_build_loaded); -// BOOST_REQUIRE(error == 0); -// error = EN_nextH(ph, &tstep); -// BOOST_REQUIRE(error == 0); -// -// } while (tstep > 0); -// -// error = EN_closeH(ph); -// BOOST_REQUIRE(error == 0); -// -// error = EN_close(ph); -// BOOST_REQUIRE(error == 0); -// -// EN_deleteproject(&ph); -// -// //--------------------------------------------------------------------- -// // if we got this far we can compare results -// -// // compare the original to the build & saved network -// // BOOST_CHECK(abs(h_orig - h_build_loaded) < 0.0001); -// -// // compare the original to the build without saving -// // BOOST_CHECK(abs(h_orig - h_build) < 0.0001); -// } -// -// -// BOOST_FIXTURE_TEST_CASE(test_save_net2, FixtureInitClose) -// { -// //char id[EN_MAXID+1]; -// double p1_1, p2_1; // p1_2, p2_2; -// double q1_1, q2_1; // q1_2, q2_2; -// -// // Build a network -// error = EN_addnode(ph, (char *)"N1", EN_JUNCTION); -// BOOST_REQUIRE(error == 0); -// error = EN_addnode(ph, (char *)"N2", EN_JUNCTION); -// BOOST_REQUIRE(error == 0); -// error = EN_addnode(ph, (char *)"N3", EN_RESERVOIR); -// BOOST_REQUIRE(error == 0); -// error = EN_addnode(ph, (char *)"N4", EN_TANK); -// BOOST_REQUIRE(error == 0); -// error = EN_addlink(ph, (char *)"L1", EN_PUMP, (char *)"N3", (char *)"N1"); -// BOOST_REQUIRE(error == 0); -// error = EN_addlink(ph, (char *)"L2", EN_PIPE, (char *)"N1", (char *)"N3"); -// BOOST_REQUIRE(error == 0); -// error = EN_addlink(ph, (char *)"L3", EN_PIPE, (char *)"N1", (char *)"N2"); -// BOOST_REQUIRE(error == 0); -// error = EN_addcurve(ph, (char *)"C1"); +// error = EN_openH(ph); // BOOST_REQUIRE(error == 0); // -// // Set network data using the new helper functions -// error = EN_setcurvevalue(ph, 1, 1, 1500, 250); -// BOOST_REQUIRE(error == 0); -// error = EN_setjuncdata(ph, 1, 700, 500, (char *)""); -// BOOST_REQUIRE(error == 0); -// error = EN_setjuncdata(ph, 2, 710, 500, (char *)""); -// BOOST_REQUIRE(error == 0); -// error = EN_setnodevalue(ph, 3, EN_ELEVATION, 800); -// BOOST_REQUIRE(error == 0); -// error = EN_settankdata(ph, 4, 850, 120, 100, 150, 50.5, 0, (char *)""); -// BOOST_REQUIRE(error == 0); -// error = EN_setlinkvalue(ph, 1, EN_PUMP_HCURVE, 1); -// BOOST_REQUIRE(error == 0); -// error = EN_setpipedata(ph, 2, 10560, 12, 100, 0); -// BOOST_REQUIRE(error == 0); -// error = EN_setpipedata(ph, 3, 5280, 14, 100, 0); +// error = EN_initH(ph, flag); // BOOST_REQUIRE(error == 0); // -// // Run hydraulics -// error = EN_solveH(ph); +// do { +// error = EN_runH(ph, &t); +// BOOST_REQUIRE(error == 0); +// +// // this is the head at the end of the simulation after loading the original Net1.inp +// error = EN_getnodevalue(ph, Nindex, EN_HEAD, &h_orig); +// BOOST_REQUIRE(error == 0); +// +// error = EN_nextH(ph, &tstep); +// BOOST_REQUIRE(error == 0); +// +// } while (tstep > 0); +// +// error = EN_closeH(ph); // BOOST_REQUIRE(error == 0); // -// // Save results -// error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p1_1); -// BOOST_REQUIRE(error == 0); -// error = EN_getnodevalue(ph, 2, EN_PRESSURE, &p2_1); -// BOOST_REQUIRE(error == 0); -// error = EN_getlinkvalue(ph, 1, EN_FLOW, &q1_1); -// BOOST_REQUIRE(error == 0); -// error = EN_getlinkvalue(ph, 2, EN_FLOW, &q2_1); +// error = EN_close(ph); // BOOST_REQUIRE(error == 0); // -// // Save project -// error = EN_saveinpfile(ph, "netbuilder_test2.inp"); -// BOOST_REQUIRE(error == 0); -// } -// -// -// BOOST_AUTO_TEST_CASE(test_reopen_net2, *boost::unit_test::depends_on("test_net_builder/test_save_net2")) -// { -// int error, index; -// -// double p1_2, p2_2; -// double q1_2, q2_2; -// -// // Open the saved project file -// EN_Project ph = NULL; -// error = EN_createproject(&ph); -// BOOST_REQUIRE(error == 0); -// error = EN_open(ph, "netbuilder_test2.inp", DATA_PATH_RPT, DATA_PATH_OUT); -// BOOST_REQUIRE(error == 0); -// -// // Run hydraulics -// error = EN_solveH(ph); -// BOOST_REQUIRE(error == 0); -// -// // Save these new results -// error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p1_2); -// BOOST_REQUIRE(error == 0); -// error = EN_getnodevalue(ph, 2, EN_PRESSURE, &p2_2); -// BOOST_REQUIRE(error == 0); -// error = EN_getlinkindex(ph, (char *)"L1", &index); -// BOOST_REQUIRE(error == 0); -// error = EN_getlinkvalue(ph, index, EN_FLOW, &q1_2); -// BOOST_REQUIRE(error == 0); -// error = EN_getlinkindex(ph, (char *)"L2", &index); -// BOOST_REQUIRE(error == 0); -// error = EN_getlinkvalue(ph, index, EN_FLOW, &q2_2); -// BOOST_REQUIRE(error == 0); -// -// // Display old & new results -// //cout << "\n Node N1 Pressure: " << p1_1 << " " << p1_2; -// //cout << "\n Node N2 Pressure: " << p2_1 << " " << p2_2; -// //cout << "\n Link L1 Flow: " << q1_1 << " " << q1_2; -// //cout << "\n Link L2 Flow: " << q2_1 << " " << q2_2; -// -// // Compare old & new results -// // BOOST_CHECK(abs(p1_1 - p1_2) < 1.e-5); -// // BOOST_CHECK(abs(q1_1 - q1_2) < 1.e-5); -// // BOOST_CHECK(abs(p2_1 - p2_2) < 1.e-5); -// // BOOST_CHECK(abs(q2_1 - q2_2) < 1.e-5); -// -// // Close project -// EN_close(ph); -// EN_deleteproject(&ph); +// EN_deleteproject(&ph); // } +BOOST_FIXTURE_TEST_CASE(test_build_net1, FixtureInitClose) +{ + int flag = 00; + long t, tstep; + int i, ind, Lindex, Nindex, Cindex; + double h_build; + + // now we build Net1 from scratch... + char juncs[9][10] = { "10", "11", "12", "13", "21", "22", "23", "31", "32" }; + double e[9] = { 710, 710, 700, 695, 700, 695, 690, 700, 710 }; + double d[9] = { 0, 150, 150, 100, 150, 200, 150, 100, 100 }; + double X[9] = { 20, 30, 50, 70, 30, 50, 70, 30, 50 }; + double Y[9] = { 70, 70, 70, 70, 40, 40, 40, 10, 10 }; + double L[12] = { 10530, 5280, 5280, 5280, 5280, 5280, 200, 5280, 5280, 5280, 5280, 5280 }; + double dia[12] = { 18, 14, 10, 10, 12, 6, 18, 10, 12, 8, 8, 6 }; + double P[12] = { 1.0f, 1.2f, 1.4f, 1.6f, 1.4f, 1.2f, 1.0f, 0.8f, 0.6f, 0.4f, 0.6f, 0.8f }; + + error = EN_addpattern(ph, (char *)"pat1"); + BOOST_REQUIRE(error == 0); + error = EN_setpattern(ph, 1, P, 12); + BOOST_REQUIRE(error == 0); + error = EN_setoption(ph, EN_DEFDEMANDPAT, 1); + BOOST_REQUIRE(error == 0); + for (i = 0; i < 9; i++) + { + error = EN_addnode(ph, juncs[i], EN_JUNCTION); + BOOST_REQUIRE(error == 0); + error = EN_setnodevalue(ph, i + 1, EN_ELEVATION, e[i]); + BOOST_REQUIRE(error == 0); + error = EN_setnodevalue(ph, i + 1, EN_BASEDEMAND, d[i]); + BOOST_REQUIRE(error == 0); + error = EN_setcoord(ph, i + 1, X[i], Y[i]); + BOOST_REQUIRE(error == 0); + //error = EN_setdemandpattern(ph, i + 1, 1, 1); + //BOOST_REQUIRE(error == 0); + } + error = EN_addnode(ph, (char *)"9", EN_RESERVOIR); + BOOST_REQUIRE(error == 0); + error = EN_setcoord(ph, 10, 10, 70); + BOOST_REQUIRE(error == 0); + error = EN_setnodevalue(ph, 10, EN_ELEVATION, 800); + BOOST_REQUIRE(error == 0); + + error = EN_addnode(ph, (char *)"2", EN_TANK); + BOOST_REQUIRE(error == 0); + error = EN_setcoord(ph, 11, 50, 90); + BOOST_REQUIRE(error == 0); + error = EN_setnodevalue(ph, 11, EN_TANKDIAM, 50.5); + BOOST_REQUIRE(error == 0); + error = EN_setnodevalue(ph, 11, EN_ELEVATION, 850); + BOOST_REQUIRE(error == 0); + error = EN_setnodevalue(ph, 11, EN_MAXLEVEL, 150); + BOOST_REQUIRE(error == 0); + error = EN_setnodevalue(ph, 11, EN_TANKLEVEL, 120); + BOOST_REQUIRE(error == 0); + error = EN_setnodevalue(ph, 11, EN_MINLEVEL, 100); + BOOST_REQUIRE(error == 0); + error = EN_setnodevalue(ph, 11, EN_MIXFRACTION, 1); + BOOST_REQUIRE(error == 0); + + error = EN_addlink(ph, (char *)"10", EN_PIPE, (char *)"10", (char *)"11"); + BOOST_REQUIRE(error == 0); + error = EN_addlink(ph, (char *)"11", EN_PIPE, (char *)"11", (char *)"12"); + BOOST_REQUIRE(error == 0); + error = EN_addlink(ph, (char *)"12", EN_PIPE, (char *)"12", (char *)"13"); + BOOST_REQUIRE(error == 0); + error = EN_addlink(ph, (char *)"21", EN_PIPE, (char *)"21", (char *)"22"); + BOOST_REQUIRE(error == 0); + error = EN_addlink(ph, (char *)"22", EN_PIPE, (char *)"22", (char *)"23"); + BOOST_REQUIRE(error == 0); + error = EN_addlink(ph, (char *)"31", EN_PIPE, (char *)"31", (char *)"32"); + BOOST_REQUIRE(error == 0); + error = EN_addlink(ph, (char *)"110", EN_PIPE, (char *)"2", (char *)"12"); + BOOST_REQUIRE(error == 0); + error = EN_addlink(ph, (char *)"111", EN_PIPE, (char *)"11", (char *)"21"); + BOOST_REQUIRE(error == 0); + error = EN_addlink(ph, (char *)"112", EN_PIPE, (char *)"12", (char *)"22"); + BOOST_REQUIRE(error == 0); + error = EN_addlink(ph, (char *)"113", EN_PIPE, (char *)"13", (char *)"23"); + BOOST_REQUIRE(error == 0); + error = EN_addlink(ph, (char *)"121", EN_PIPE, (char *)"21", (char *)"31"); + BOOST_REQUIRE(error == 0); + error = EN_addlink(ph, (char *)"122", EN_PIPE, (char *)"22", (char *)"32"); + BOOST_REQUIRE(error == 0); + for (i = 0; i < 12; i++) + { + error = EN_setlinkvalue(ph, i + 1, EN_LENGTH, L[i]); + BOOST_REQUIRE(error == 0); + error = EN_setlinkvalue(ph, i + 1, EN_DIAMETER, dia[i]); + BOOST_REQUIRE(error == 0); + } + + error = EN_addlink(ph, (char *)"9", EN_PUMP, (char *)"9", (char *)"10"); + BOOST_REQUIRE(error == 0); + error = EN_addcurve(ph, (char *)"1"); + BOOST_REQUIRE(error == 0); + error = EN_setcurvevalue(ph, 1, 1, 1500, 250); + BOOST_REQUIRE(error == 0); + error = EN_getlinkindex(ph, (char *)"9", &ind); + BOOST_REQUIRE(error == 0); + error = EN_setheadcurveindex(ph, ind, 1); + BOOST_REQUIRE(error == 0); + + error = EN_settimeparam(ph, EN_DURATION, 24 * 3600); + BOOST_REQUIRE(error == 0); + error = EN_settimeparam(ph, EN_PATTERNSTEP, 2 * 3600); + BOOST_REQUIRE(error == 0); + + error = EN_getlinkindex(ph, (char *)"9", &Lindex); + BOOST_REQUIRE(error == 0); + error = EN_getnodeindex(ph, (char *)"2", &Nindex); + BOOST_REQUIRE(error == 0); + + // Add controls + error = EN_addcontrol(ph, EN_LOWLEVEL, Lindex, 1, Nindex, 110, &Cindex); + BOOST_REQUIRE(error == 0); + error = EN_addcontrol(ph, EN_HILEVEL, Lindex, 0, Nindex, 140, &Cindex); + BOOST_REQUIRE(error == 0); + + error = EN_openH(ph); + BOOST_REQUIRE(error == 0); + error = EN_initH(ph, 0); + BOOST_REQUIRE(error == 0); + do { + error = EN_runH(ph, &t); + BOOST_REQUIRE(error == 0); + // this is the head at the end of the simulation after building the network *without* saving it to file + error = EN_getnodevalue(ph, Nindex, EN_HEAD, &h_build); + BOOST_REQUIRE(error == 0); + error = EN_nextH(ph, &tstep); + BOOST_REQUIRE(error == 0); + } while (tstep > 0); + error = EN_closeH(ph); + BOOST_REQUIRE(error == 0); + + error = EN_saveinpfile(ph, "net_builder.inp"); + BOOST_REQUIRE(error == 0); +} + +BOOST_AUTO_TEST_CASE(test_open_net1, * boost::unit_test::depends_on("test_net_builder/test_build_net1")) +{ + int error = 0; + int flag = 00; + long t, tstep; + int Nindex = -1; + double h_orig = 0.0, h_build = 0.0, h_build_loaded = 0.0; + + + EN_Project ph = NULL; + + // now we load the netwok we just built and saved + EN_createproject(&ph); + error = EN_open(ph, "net_builder.inp", DATA_PATH_RPT, DATA_PATH_OUT); + BOOST_REQUIRE(error == 0); + + error = EN_getnodeindex(ph, (char *)"2", &Nindex); + BOOST_REQUIRE(error == 0); + + 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); + // this is the head at the end of the simulation after building the network and saving it to file + error = EN_getnodevalue(ph, Nindex, EN_HEAD, &h_build_loaded); + BOOST_REQUIRE(error == 0); + error = EN_nextH(ph, &tstep); + BOOST_REQUIRE(error == 0); + + } while (tstep > 0); + + error = EN_closeH(ph); + BOOST_REQUIRE(error == 0); + + error = EN_close(ph); + BOOST_REQUIRE(error == 0); + + EN_deleteproject(&ph); + + //--------------------------------------------------------------------- + // if we got this far we can compare results + + // compare the original to the build & saved network + // BOOST_CHECK(abs(h_orig - h_build_loaded) < 0.0001); + + // compare the original to the build without saving + // BOOST_CHECK(abs(h_orig - h_build) < 0.0001); +} + + +BOOST_FIXTURE_TEST_CASE(test_save_net2, FixtureInitClose) +{ + //char id[EN_MAXID+1]; + double p1_1, p2_1; // p1_2, p2_2; + double q1_1, q2_1; // q1_2, q2_2; + + // Build a network + error = EN_addnode(ph, (char *)"N1", EN_JUNCTION); + BOOST_REQUIRE(error == 0); + error = EN_addnode(ph, (char *)"N2", EN_JUNCTION); + BOOST_REQUIRE(error == 0); + error = EN_addnode(ph, (char *)"N3", EN_RESERVOIR); + BOOST_REQUIRE(error == 0); + error = EN_addnode(ph, (char *)"N4", EN_TANK); + BOOST_REQUIRE(error == 0); + error = EN_addlink(ph, (char *)"L1", EN_PUMP, (char *)"N3", (char *)"N1"); + BOOST_REQUIRE(error == 0); + error = EN_addlink(ph, (char *)"L2", EN_PIPE, (char *)"N1", (char *)"N3"); + BOOST_REQUIRE(error == 0); + error = EN_addlink(ph, (char *)"L3", EN_PIPE, (char *)"N1", (char *)"N2"); + BOOST_REQUIRE(error == 0); + error = EN_addcurve(ph, (char *)"C1"); + BOOST_REQUIRE(error == 0); + + // Set network data using the new helper functions + error = EN_setcurvevalue(ph, 1, 1, 1500, 250); + BOOST_REQUIRE(error == 0); + error = EN_setjuncdata(ph, 1, 700, 500, (char *)""); + BOOST_REQUIRE(error == 0); + error = EN_setjuncdata(ph, 2, 710, 500, (char *)""); + BOOST_REQUIRE(error == 0); + error = EN_setnodevalue(ph, 3, EN_ELEVATION, 800); + BOOST_REQUIRE(error == 0); + error = EN_settankdata(ph, 4, 850, 120, 100, 150, 50.5, 0, (char *)""); + BOOST_REQUIRE(error == 0); + error = EN_setlinkvalue(ph, 1, EN_PUMP_HCURVE, 1); + BOOST_REQUIRE(error == 0); + error = EN_setpipedata(ph, 2, 10560, 12, 100, 0); + BOOST_REQUIRE(error == 0); + error = EN_setpipedata(ph, 3, 5280, 14, 100, 0); + BOOST_REQUIRE(error == 0); + + // Run hydraulics + error = EN_solveH(ph); + BOOST_REQUIRE(error == 0); + + // Save results + error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p1_1); + BOOST_REQUIRE(error == 0); + error = EN_getnodevalue(ph, 2, EN_PRESSURE, &p2_1); + BOOST_REQUIRE(error == 0); + error = EN_getlinkvalue(ph, 1, EN_FLOW, &q1_1); + BOOST_REQUIRE(error == 0); + error = EN_getlinkvalue(ph, 2, EN_FLOW, &q2_1); + BOOST_REQUIRE(error == 0); + + // Save project + error = EN_saveinpfile(ph, "netbuilder_test2.inp"); + BOOST_REQUIRE(error == 0); +} + + +BOOST_AUTO_TEST_CASE(test_reopen_net2, *boost::unit_test::depends_on("test_net_builder/test_save_net2")) +{ + int error, index; + + double p1_2, p2_2; + double q1_2, q2_2; + + // Open the saved project file + EN_Project ph = NULL; + error = EN_createproject(&ph); + BOOST_REQUIRE(error == 0); + error = EN_open(ph, "netbuilder_test2.inp", DATA_PATH_RPT, DATA_PATH_OUT); + BOOST_REQUIRE(error == 0); + + // Run hydraulics + error = EN_solveH(ph); + BOOST_REQUIRE(error == 0); + + // Save these new results + error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p1_2); + BOOST_REQUIRE(error == 0); + error = EN_getnodevalue(ph, 2, EN_PRESSURE, &p2_2); + BOOST_REQUIRE(error == 0); + error = EN_getlinkindex(ph, (char *)"L1", &index); + BOOST_REQUIRE(error == 0); + error = EN_getlinkvalue(ph, index, EN_FLOW, &q1_2); + BOOST_REQUIRE(error == 0); + error = EN_getlinkindex(ph, (char *)"L2", &index); + BOOST_REQUIRE(error == 0); + error = EN_getlinkvalue(ph, index, EN_FLOW, &q2_2); + BOOST_REQUIRE(error == 0); + + // Display old & new results + //cout << "\n Node N1 Pressure: " << p1_1 << " " << p1_2; + //cout << "\n Node N2 Pressure: " << p2_1 << " " << p2_2; + //cout << "\n Link L1 Flow: " << q1_1 << " " << q1_2; + //cout << "\n Link L2 Flow: " << q2_1 << " " << q2_2; + + // Compare old & new results +// BOOST_CHECK(abs(p1_1 - p1_2) < 1.e-5); +// BOOST_CHECK(abs(q1_1 - q1_2) < 1.e-5); +// BOOST_CHECK(abs(p2_1 - p2_2) < 1.e-5); +// BOOST_CHECK(abs(q2_1 - q2_2) < 1.e-5); + + // Close project + EN_close(ph); + EN_deleteproject(&ph); +} + BOOST_AUTO_TEST_SUITE_END() From 502e5f16a09aabf706165205af2a8b53dc8f4817 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 3 Apr 2019 16:25:51 -0400 Subject: [PATCH 11/15] Fixing index error in test --- tests/test_analysis.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_analysis.cpp b/tests/test_analysis.cpp index 30a159f..dfdbc13 100644 --- a/tests/test_analysis.cpp +++ b/tests/test_analysis.cpp @@ -22,7 +22,7 @@ BOOST_AUTO_TEST_SUITE (test_analysis) BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose) { int i; - double array[13]; + double array[12]; std::vector test; std::vector ref = {40.0, 0.001, 0.01, 0.5, 1.0, 0.0, 0.0, 0.0, 75.0, 0.0, 0.0, 0.0}; @@ -39,7 +39,7 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose) BOOST_REQUIRE(error == 0); } - test.assign(array, array + 13); + test.assign(array, array + 12); BOOST_CHECK_EQUAL_COLLECTIONS(ref.begin(), ref.end(), test.begin(), test.end()); error = EN_getoption(ph, 18, &array[0]); From 3e733f5a2ae25f49eb1ceb3d2dd771262f3afee1 Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Wed, 3 Apr 2019 21:17:28 -0400 Subject: [PATCH 12/15] Add more analysis options to the API (issue #425) --- include/epanet2.bas | 13 ++++- include/epanet2.vb | 13 ++++- include/epanet2_enums.h | 19 +++++-- src/epanet.c | 106 ++++++++++++++++++++++++++++++++++++---- tests/test_analysis.cpp | 9 ++-- 5 files changed, 140 insertions(+), 20 deletions(-) diff --git a/include/epanet2.bas b/include/epanet2.bas index ba94210..c09fd4a 100644 --- a/include/epanet2.bas +++ b/include/epanet2.bas @@ -140,7 +140,7 @@ Public Const EN_CMD = 9 Public Const EN_DDA = 0 ' Demand driven analysis Public Const EN_PDA = 1 ' Pressure driven analysis -Public Const EN_TRIALS = 0 ' Hydraulic options +Public Const EN_TRIALS = 0 ' Simulation options Public Const EN_ACCURACY = 1 Public Const EN_TOLERANCE = 2 Public Const EN_EMITEXPON = 3 @@ -152,6 +152,17 @@ Public Const EN_GLOBALEFFIC = 8 Public Const EN_GLOBALPRICE = 9 Public Const EN_GLOBALPATTERN = 10 Public Const EN_DEMANDCHARGE = 11 +Public Const EN_SP_GRAVITY = 12 +Public Const EN_SP_VISCOS = 13 +Public Const EN_UNBALANCED = 14 +Public Const EN_CHECKFREQ = 15 +Public Const EN_MAXCHECK = 16 +Public Const EN_DAMPLIMIT = 17 +Public Const EN_SP_DIFFUS = 18 +Public Const EN_BULKORDER = 19 +Public Const EN_WALLORDER = 20 +Public Const EN_TANKORDER = 21 +Public Const EN_CONCENLIMIT = 22 Public Const EN_LOWLEVEL = 0 ' Control types Public Const EN_HILEVEL = 1 diff --git a/include/epanet2.vb b/include/epanet2.vb index 6f71b26..58cad9f 100644 --- a/include/epanet2.vb +++ b/include/epanet2.vb @@ -145,7 +145,7 @@ Public Const EN_CMD = 9 Public Const EN_DDA = 0 ' Demand driven analysis Public Const EN_PDA = 1 ' Pressure driven analysis -Public Const EN_TRIALS = 0 ' Hydraulic options +Public Const EN_TRIALS = 0 ' Simulation options Public Const EN_ACCURACY = 1 Public Const EN_TOLERANCE = 2 Public Const EN_EMITEXPON = 3 @@ -157,6 +157,17 @@ Public Const EN_GLOBALEFFIC = 8 Public Const EN_GLOBALPRICE = 9 Public Const EN_GLOBALPATTERN = 10 Public Const EN_DEMANDCHARGE = 11 +Public Const EN_SP_GRAVITY = 12 +Public Const EN_SP_VISCOS = 13 +Public Const EN_UNBALANCED = 14 +Public Const EN_CHECKFREQ = 15 +Public Const EN_MAXCHECK = 16 +Public Const EN_DAMPLIMIT = 17 +Public Const EN_SP_DIFFUS = 18 +Public Const EN_BULKORDER = 19 +Public Const EN_WALLORDER = 20 +Public Const EN_TANKORDER = 21 +Public Const EN_CONCENLIMIT = 22 Public Const EN_LOWLEVEL = 0 ' Control types Public Const EN_HILEVEL = 1 diff --git a/include/epanet2_enums.h b/include/epanet2_enums.h index fa00688..33f353b 100644 --- a/include/epanet2_enums.h +++ b/include/epanet2_enums.h @@ -282,13 +282,13 @@ typedef enum { /// Simulation options /** -These options specify hydraulic convergence criteria, choice of head loss formula, and -several other parameters applied on a network-wide basis. They are accessed using the +These constants identify the hydraulic and water quality simulation options +that are applied on a network-wide basis. They are accessed using the @ref EN_getoption and @ref EN_setoption functions. */ typedef enum { - EN_TRIALS = 0, //!< Maximum hydraulic trials allowed - EN_ACCURACY = 1, //!< Maximum total relative flow change for hydraulic convergence + EN_TRIALS = 0, //!< Maximum hydraulic trials allowed for hydraulic convergence + EN_ACCURACY = 1, //!< Total normalized flow change for hydraulic convergence EN_TOLERANCE = 2, //!< Water quality tolerance EN_EMITEXPON = 3, //!< Exponent in emitter discharge formula EN_DEMANDMULT = 4, //!< Global demand multiplier @@ -299,6 +299,17 @@ typedef enum { EN_GLOBALPRICE = 9, //!< Global energy price per KWH EN_GLOBALPATTERN = 10, //!< Index of a global energy price pattern EN_DEMANDCHARGE = 11 //!< Energy charge per max. KW usage + EN_SP_GRAVITY = 12, //!< Specific gravity + EN_SP_VISCOS = 13, //!< Specific viscosity (relative to water at 20 deg C) + EN_UNBALANCED = 14, //!< Extra trials allowed if hydraulics don't converge + EN_CHECKFREQ = 15, //!< Frequency of hydraulic status checks + EN_MAXCHECK = 16, //!< Maximum trials for status checking + EN_DAMPLIMIT = 17, //!< Accuracy level where solution damping begins + EN_SP_DIFFUS = 18, //!< Specific diffusivity (relative to chlorine at 20 deg C) + EN_BULKORDER = 19, //!< Bulk water reaction order for pipes + EN_WALLORDER = 20, //!< Wall reaction order for pipes (either 0 or 1) + EN_TANKORDER = 21, //!< Bulk water reaction order for tanks + EN_CONCENLIMIT = 22 //!< Limiting concentration for growth reactions } EN_Option; /// Types of simple controls diff --git a/src/epanet.c b/src/epanet.c index 88a7669..30894fc 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -1108,8 +1108,7 @@ int DLLEXPORT EN_getoption(EN_Project p, int option, double *value) v = qual->Ctol * Ucf[QUALITY]; break; case EN_EMITEXPON: - if (hyd->Qexp > 0.0) - v = 1.0 / hyd->Qexp; + if (hyd->Qexp > 0.0) v = 1.0 / hyd->Qexp; break; case EN_DEMANDMULT: v = hyd->Dmult; @@ -1135,6 +1134,39 @@ int DLLEXPORT EN_getoption(EN_Project p, int option, double *value) case EN_DEMANDCHARGE: v = hyd->Dcost; break; + case EN_SP_GRAVITY: + v = hyd->SpGrav; + break; + case EN_SP_VISCOS: + v = hyd->Viscos / VISCOS; + break; + case EN_UNBALANCED: + v = hyd->ExtraIter; + break; + case EN_CHECKFREQ: + v = hyd->CheckFreq; + break; + case EN_MAXCHECK: + v = hyd->MaxCheck; + break; + case EN_DAMPLIMIT: + v = hyd->DampLimit; + break; + case EN_SP_DIFFUS: + v = qual->Diffus / DIFFUS; + break; + case EN_BULKORDER: + v = qual->BulkOrder; + break; + case EN_WALLORDER: + v = qual->WallOrder; + break; + case EN_TANKORDER: + v = qual->TankOrder; + break; + case EN_CONCENLIMIT: + v = qual->Climit * p->Ucf[QUALITY]; + break; default: return 251; @@ -1163,6 +1195,22 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value) double Ke, n, ucf; if (!p->Openflag) return 102; + + // The EN_UNBALANCED option can be < 0 indicating that the simulation + // should be halted if no convergence is reached in EN_TRIALS. Other + // values set the number of additional trials to use with no more + // link status changes to achieve convergence. + if (option == EN_UNBALANCED) + { + hyd->ExtraIter = (int)value; + if (hyd->ExtraIter < 0) hyd->ExtraIter = -1; + return 0; + } + + // All other option values must be non-negative + if (value < 0.0) return 213; + + // Process the speficied option switch (option) { case EN_TRIALS: @@ -1171,12 +1219,11 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value) break; case EN_ACCURACY: - if (value < 1.e-5 || value > 1.e-1) return 213; + if (value < 1.e-8 || value > 1.e-1) return 213; hyd->Hacc = value; break; case EN_TOLERANCE: - if (value < 0.0) return 213; qual->Ctol = value / Ucf[QUALITY]; break; @@ -1193,17 +1240,14 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value) break; case EN_DEMANDMULT: - if (value <= 0.0) return 213; hyd->Dmult = value; break; case EN_HEADERROR: - if (value < 0.0) return 213; hyd->HeadErrorLimit = value / Ucf[HEAD]; break; case EN_FLOWCHANGE: - if (value < 0.0) return 213; hyd->FlowChangeLimit = value / Ucf[FLOW]; break; @@ -1218,12 +1262,11 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value) break; case EN_GLOBALEFFIC: - if (value <= 0.0 || value > 100.0) return 213; + if (value <= 1.0 || value > 100.0) return 213; hyd->Epump = value; break; case EN_GLOBALPRICE: - if (value < 0.0) return 213; hyd->Ecost = value; break; @@ -1234,10 +1277,53 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value) break; case EN_DEMANDCHARGE: - if (value < 0.0) return 213; hyd->Dcost = value; break; + case EN_SP_GRAVITY: + if (value <= 0.0) return 213; + Ucf[PRESSURE] *= (value / hyd->SpGrav); + hyd->SpGrav = value; + break; + + case EN_SP_VISCOS: + if (value <= 0.0) return 213; + hyd->Viscos = value * VISCOS; + break; + + case EN_CHECKFREQ: + hyd->CheckFreq = (int)value; + break; + + case EN_MAXCHECK: + hyd->MaxCheck = (int)value; + break; + + case EN_DAMPLIMIT: + hyd->DampLimit = value; + break; + + case EN_SP_DIFFUS: + qual->Diffus = value * DIFFUS; + break; + + case EN_BULKORDER: + qual->BulkOrder = value; + break; + + case EN_WALLORDER: + if (value == 0.0 || value == 1.0) qual->WallOrder = value; + else return 213; + break; + + case EN_TANKORDER: + qual->TankOrder = value; + break; + + case EN_CONCENLIMIT: + qual->Climit = value / p->Ucf[QUALITY]; + break; + default: return 251; } diff --git a/tests/test_analysis.cpp b/tests/test_analysis.cpp index 0787c4e..b3c9a93 100644 --- a/tests/test_analysis.cpp +++ b/tests/test_analysis.cpp @@ -23,10 +23,11 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose) { int i; - std::vector test(12); + std::vector test(23); double *array = test.data(); - std::vector ref = {40.0, 0.001, 0.01, 0.5, 1.0, 0.0, 0.0, 0.0, 75.0, 0.0, 0.0, 0.0}; + std::vector ref = {40.0, 0.001, 0.01, 0.5, 1.0, 0.0, 0.0, 0.0, 75.0, 0.0, 0.0, 0.0, + 1.0, 1.0, 10.0, 2.0, 10.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0}; error = EN_solveH(ph); BOOST_REQUIRE(error == 0); @@ -35,7 +36,7 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose) BOOST_REQUIRE(error == 0); - for (i=EN_TRIALS; i<=EN_DEMANDCHARGE; i++) { + for (i=EN_TRIALS; i<=EN_CONCENLIMIT; i++) { error = EN_getoption(ph, i, array++); BOOST_REQUIRE(error == 0); } @@ -43,7 +44,7 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose) BOOST_CHECK_EQUAL_COLLECTIONS(ref.begin(), ref.end(), test.begin(), test.end()); double temp; - error = EN_getoption(ph, 18, &temp); + error = EN_getoption(ph, 25, &temp); BOOST_CHECK(error == 251); } From 1632508545f7c98a8749e74e44056d01c42a0f21 Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Wed, 3 Apr 2019 21:23:46 -0400 Subject: [PATCH 13/15] Fixed epanet2_enums.h --- include/epanet2_enums.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/epanet2_enums.h b/include/epanet2_enums.h index 33f353b..52a4eb4 100644 --- a/include/epanet2_enums.h +++ b/include/epanet2_enums.h @@ -298,7 +298,7 @@ typedef enum { EN_GLOBALEFFIC = 8, //!< Global pump efficiency (percent) EN_GLOBALPRICE = 9, //!< Global energy price per KWH EN_GLOBALPATTERN = 10, //!< Index of a global energy price pattern - EN_DEMANDCHARGE = 11 //!< Energy charge per max. KW usage + EN_DEMANDCHARGE = 11, //!< Energy charge per max. KW usage EN_SP_GRAVITY = 12, //!< Specific gravity EN_SP_VISCOS = 13, //!< Specific viscosity (relative to water at 20 deg C) EN_UNBALANCED = 14, //!< Extra trials allowed if hydraulics don't converge From edcd4b69c7d1f6f849a276292f0c0f246b1ee6bb Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Fri, 5 Apr 2019 13:02:39 -0400 Subject: [PATCH 14/15] Eliminates use of temporary linked lists to process Patterns & Curves (issue #449) --- src/epanet.c | 68 ++++++------ src/funcs.h | 10 +- src/input1.c | 1 + src/input2.c | 291 +++++++++++++------------------------------------- src/input3.c | 202 +++++++++++++++++------------------ src/project.c | 146 ++++++++++++------------- src/types.h | 26 +---- 7 files changed, 295 insertions(+), 449 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 30894fc..55b1265 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -172,10 +172,7 @@ int DLLEXPORT EN_init(EN_Project p, const char *rptFile, const char *outFile, initunits(p); inittanks(p); convertunits(p); - - // Initialize the default demand pattern p->parser.MaxPats = 0; - getpatterns(p); p->Openflag = TRUE; return errcode; } @@ -230,10 +227,6 @@ int DLLEXPORT EN_open(EN_Project p, const char *inpFile, const char *rptFile, p->parser.InFile = NULL; } - // Free temporary linked lists used for Patterns & Curves - freeTmplist(p->parser.Patlist); - freeTmplist(p->parser.Curvelist); - // If using previously saved hydraulics file then open it if (p->outfile.Hydflag == USE) ERRCODE(openhydfile(p)); @@ -3943,7 +3936,6 @@ int DLLEXPORT EN_addpattern(EN_Project p, char *id) { Network *net = &p->network; Parser *parser = &p->parser; - Hydraul *hyd = &p->hydraul; int i, n, err = 0; Spattern *pat; @@ -4231,6 +4223,7 @@ int DLLEXPORT EN_addcurve(EN_Project p, char *id) curve = &net->Curve[n]; strcpy(curve->ID, id); curve->Comment = NULL; + curve->Capacity = 1; curve->Npts = 1; curve->Type = GENERIC_CURVE; curve->X = (double *)calloc(1, sizeof(double)); @@ -4302,20 +4295,11 @@ int DLLEXPORT EN_getcurveindex(EN_Project p, char *id, int *index) **---------------------------------------------------------------- */ { - int i; - *index = 0; if (!p->Openflag) return 102; - for (i = 1; i <= p->network.Ncurves; i++) - { - if (strcmp(id, p->network.Curve[i].ID) == 0) - { - *index = i; - return 0; - } - } - *index = 0; - return 206; + *index = findcurve(&p->network, id); + if (*index == 0) return 206; + return 0; } int DLLEXPORT EN_getcurveid(EN_Project p, int index, char *id) @@ -4404,8 +4388,8 @@ int DLLEXPORT EN_getcurvevalue(EN_Project p, int curveIndex, int pointIndex, if (!p->Openflag) return 102; if (curveIndex < 1 || curveIndex > p->network.Ncurves) return 206; if (pointIndex < 1 || pointIndex > p->network.Curve[curveIndex].Npts) return 251; - *x = (double)p->network.Curve[curveIndex].X[pointIndex - 1]; - *y = (double)p->network.Curve[curveIndex].Y[pointIndex - 1]; + *x = p->network.Curve[curveIndex].X[pointIndex - 1]; + *y = p->network.Curve[curveIndex].Y[pointIndex - 1]; return 0; } @@ -4419,18 +4403,43 @@ int DLLEXPORT EN_setcurvevalue(EN_Project p, int curveIndex, int pointIndex, ** Output: none ** Returns: error code ** Purpose: sets the value of a specific point on a data curve +** Note: if pointIndex exceeds the curve's length a new point is added. **---------------------------------------------------------------- */ { Network *net = &p->network; Scurve *curve; + double x1 = -1.e37, x2 = 1.e37; + int n = pointIndex - 1; + // Check for valid input if (!p->Openflag) return 102; if (curveIndex <= 0 || curveIndex > net->Ncurves) return 206; curve = &net->Curve[curveIndex]; - if (pointIndex <= 0 || pointIndex > curve->Npts) return 251; - curve->X[pointIndex - 1] = x; - curve->Y[pointIndex - 1] = y; + if (pointIndex <= 0) return 251; + + // Check that new point maintains increasing x values + if (n - 1 >= 0) x1 = curve->X[n-1]; + if (n + 1 < curve->Npts) x2 = curve->X[n+1]; + if (x <= x1 || x >= x2) return 230; + + // Expand curve if need be + if (pointIndex > curve->Npts) pointIndex = curve->Npts + 1; + if (pointIndex >= curve->Capacity) + { + if (resizecurve(curve, curve->Capacity + 10) > 0) return 101; + } + + // Increase curve's number of points if need be + if (pointIndex > curve->Npts) + { + curve->Npts++; + n = curve->Npts - 1; + } + + // Insert new point into curve + curve->X[n] = x; + curve->Y[n] = y; return 0; } @@ -4490,15 +4499,12 @@ int DLLEXPORT EN_setcurve(EN_Project p, int index, double *xValues, // Check that x values are increasing for (j = 1; j < nPoints; j++) if (xValues[j-1] >= xValues[j]) return 230; - // Re-set number of points & reallocate memory for values + // Expand size of curve's data arrays if need be curve = &net->Curve[index]; - curve->Npts = nPoints; - curve->X = (double *)realloc(curve->X, nPoints * sizeof(double)); - curve->Y = (double *)realloc(curve->Y, nPoints * sizeof(double)); - if (curve->X == NULL) return 101; - if (curve->Y == NULL) return 101; + if (resizecurve(curve, nPoints) > 0) return 101; // Load values into curve + curve->Npts = nPoints; for (j = 0; j < nPoints; j++) { curve->X[j] = xValues[j]; diff --git a/src/funcs.h b/src/funcs.h index 6fffeb3..ac17b55 100755 --- a/src/funcs.h +++ b/src/funcs.h @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 03/17/2019 + Last Updated: 04/03/2019 ****************************************************************************** */ #ifndef FUNCS_H @@ -17,8 +17,6 @@ void initpointers(Project *); int allocdata(Project *); -void freeTmplist(STmplist *); -void freeFloatlist(SFloatlist *); void freedata(Project *); int openfiles(Project *, const char *, const char *,const char *); @@ -36,8 +34,12 @@ int findlink(Network *, char *); int findtank(Network *, int); int findvalve(Network *, int); int findpump(Network *, int); +int findpattern(Network *, char *); +int findcurve(Network *, char *); + void adjustpatterns(Network *, int); void adjustcurves(Network *, int); +int resizecurve(Scurve *, int); int getcomment(Network *, int, int, char *); int setcomment(Network *, int, int, const char *); @@ -65,8 +67,6 @@ void convertunits(Project *); int netsize(Project *); int readdata(Project *); int updatepumpparams(Project *, int); -int getpatterns(Project *); -int getcurves(Project *); int findmatch(char *, char *[]); int match(const char *, const char *); int gettokens(char *, char **, int, char *); diff --git a/src/input1.c b/src/input1.c index 6b900a5..219caaf 100644 --- a/src/input1.c +++ b/src/input1.c @@ -331,6 +331,7 @@ void adjustdata(Project *pr) } // Use default pattern if none assigned to a demand + parser->DefPat = findpattern(net, parser->DefPatID); if (parser->DefPat > 0) for (i = 1; i <= net->Nnodes; i++) { node = &net->Node[i]; diff --git a/src/input2.c b/src/input2.c index 0508ee4..482103e 100644 --- a/src/input2.c +++ b/src/input2.c @@ -35,7 +35,6 @@ extern char *SectTxt[]; // Input section keywords (see ENUMSTXT.H) // Exported functions int addnodeID(Network *n, int, char *); int addlinkID(Network *n, int, char *); -STmplist *getlistitem(char *, STmplist *); // Imported functions extern int powercurve(double, double, double, double, double, double *, @@ -43,8 +42,8 @@ extern int powercurve(double, double, double, double, double, double *, // Local functions static int newline(Project *, int, char *); -static int addpattern(Parser *, char *); -static int addcurve(Parser *, char *); +static int addpattern(Network *, char *); +static int addcurve(Network *, char *); static int unlinked(Project *); static int getpumpparams(Project *); static void inperrmsg(Project *, int, int, char *); @@ -65,6 +64,7 @@ int netsize(Project *pr) char *tok; // First token of line int sect, newsect; // Input data sections int errcode = 0; // Error code + Spattern *pattern; // Initialize object counts parser->MaxJuncs = 0; @@ -77,13 +77,20 @@ int netsize(Project *pr) parser->MaxCurves = 0; sect = -1; - // Add a default demand pattern - parser->MaxPats = -1; - addpattern(parser,""); - if (parser->InFile == NULL) return 0; + // Add a "dummy" time pattern with index of 0 and a single multiplier + // of 1.0 to be used by all demands not assigned a pattern + pr->network.Npats = -1; + errcode = addpattern(&pr->network, ""); + if (errcode) return errcode; + pattern = &pr->network.Pattern[0]; + pattern->Length = 1; + pattern[0].F = (double *)calloc(1, sizeof(double)); + pattern[0].F[0] = 1.0; + parser->MaxPats = pr->network.Npats; // Make a pass through input file counting number of each object + if (parser->InFile == NULL) return 0; while (fgets(line, MAXLINE, parser->InFile) != NULL) { // Skip blank lines & those beginning with a comment @@ -115,8 +122,14 @@ int netsize(Project *pr) case _VALVES: parser->MaxValves++; break; case _CONTROLS: parser->MaxControls++; break; case _RULES: addrule(parser,tok); break; - case _PATTERNS: errcode = addpattern(parser, tok); break; - case _CURVES: errcode = addcurve(parser, tok); break; + case _PATTERNS: + errcode = addpattern(&pr->network, tok); + parser->MaxPats = pr->network.Npats; + break; + case _CURVES: + errcode = addcurve(&pr->network, tok); + parser->MaxCurves = pr->network.Ncurves; + break; } if (errcode) break; } @@ -166,12 +179,15 @@ int readdata(Project *pr) net->Nvalves = 0; net->Ncontrols = 0; net->Nrules = 0; - net->Ncurves = parser->MaxCurves; - net->Npats = parser->MaxPats; + + // Patterns & Curves were created previously in netsize() + parser->MaxPats = net->Npats; + parser->MaxCurves = net->Ncurves; parser->PrevPat = NULL; parser->PrevCurve = NULL; + + // Initialize full line comment, input data section and error count parser->LineComment[0] = '\0'; - sect = -1; errsum = 0; @@ -257,9 +273,7 @@ int readdata(Project *pr) // Check for unlinked nodes if (!errcode) errcode = unlinked(pr); - // Get pattern & curve data from temporary lists - if (!errcode) errcode = getpatterns(pr); - if (!errcode) errcode = getcurves(pr); + // Determine pump curve parameters if (!errcode) errcode = getpumpparams(pr); // Free input buffer @@ -487,7 +501,7 @@ int addlinkID(Network *net, int n, char *id) return 1; } -int addpattern(Parser *parser, char *id) +int addpattern(Network *network, char *id) /* **------------------------------------------------------------- ** Input: id = pattern ID label @@ -496,34 +510,33 @@ int addpattern(Parser *parser, char *id) **-------------------------------------------------------------- */ { - STmplist *patlist; + int n = network->Npats; + Spattern *pattern; - // Check if ID is same as last one processed - if (parser->Patlist != NULL && strcmp(id, parser->Patlist->ID) == 0) return 0; - - // Check that pattern was not already created - if (getlistitem(id, parser->Patlist) == NULL) + // Check if pattern was already created + if (n > 0) { - // Update pattern count & create new list element - (parser->MaxPats)++; - patlist = (STmplist *)malloc(sizeof(STmplist)); - if (patlist == NULL) return 101; - - // Initialize list element properties - else - { - patlist->i = parser->MaxPats; - strncpy(patlist->ID, id, MAXID); - patlist->x = NULL; - patlist->y = NULL; - patlist->next = parser->Patlist; - parser->Patlist = patlist; - } + if (strcmp(id, network->Pattern[n].ID) == 0) return 0; + if (findpattern(network, id) > 0) return 0; } + if (strlen(id) > MAXID) return 250; + + // Update pattern count & add a new pattern to the database + n = n + 2; + network->Pattern = (Spattern *)realloc(network->Pattern, n * sizeof(Spattern)); + if (network->Pattern == NULL) return 101; + (network->Npats)++; + + // Initialize the pattern + pattern = &network->Pattern[network->Npats]; + strncpy(pattern->ID, id, MAXID); + pattern->Comment = NULL; + pattern->Length = 0; + pattern->F = NULL; return 0; } -int addcurve(Parser *parser, char *id) +int addcurve(Network *network, char *id) /* **------------------------------------------------------------- ** Input: id = curve ID label @@ -532,51 +545,33 @@ int addcurve(Parser *parser, char *id) **-------------------------------------------------------------- */ { - STmplist *curvelist; + int n = network->Ncurves; + Scurve *curve; - // Check if ID is same as last one processed - if (parser->Curvelist != NULL && strcmp(id, parser->Curvelist->ID) == 0) return 0; - - // Check that curve was not already created - if (getlistitem(id, parser->Curvelist) == NULL) + // Check if was already created + if (n > 0) { - // Update curve count & create new list element - (parser->MaxCurves)++; - curvelist = (STmplist *)malloc(sizeof(STmplist)); - if (curvelist == NULL) return 101; - - // Initialize list element properties - else - { - curvelist->i = parser->MaxCurves; - strncpy(curvelist->ID, id, MAXID); - curvelist->x = NULL; - curvelist->y = NULL; - curvelist->next = parser->Curvelist; - parser->Curvelist = curvelist; - } + if (strcmp(id, network->Curve[n].ID) == 0) return 0; + if (findcurve(network, id) > 0) return 0; } + if (strlen(id) > MAXID) return 250; + + n = n + 2; + network->Curve = (Scurve *)realloc(network->Curve, n * sizeof(Scurve)); + if (network->Curve == NULL) return 101; + (network->Ncurves)++; + + // Initialize the curve + curve = &network->Curve[network->Ncurves]; + strncpy(curve->ID, id, MAXID); + curve->Comment = NULL; + curve->Capacity = 0; + curve->Npts = 0; + curve->X = NULL; + curve->Y = NULL; return 0; } -STmplist *getlistitem(char *id, STmplist *list) -/* -**------------------------------------------------------------- -** Input: id = ID label -** list = pointer to head of a temporary list -** Output: returns list item with requested ID label -** Purpose: searches for item in temporary list -**------------------------------------------------------------- -*/ -{ - STmplist *item; - for (item = list; item != NULL; item = item->next) - { - if (strcmp(item->ID, id) == 0) return item; - } - return NULL; -} - int unlinked(Project *pr) /* **-------------------------------------------------------------- @@ -625,144 +620,6 @@ int unlinked(Project *pr) return errcode; } -int getpatterns(Project *pr) -/* -**----------------------------------------------------------- -** Input: none -** Output: returns error code -** Purpose: retrieves pattern data from temporary linked list -**------------------------------------------------------------- -*/ -{ - Network *net = &pr->network; - Hydraul *hyd = &pr->hydraul; - Parser *parser = &pr->parser; - - int i, j; - SFloatlist *f; - STmplist *tmppattern; - Spattern *pattern; - - // Start at head of the list of patterns - tmppattern = parser->Patlist; - - // Traverse list of temporary patterns - while (tmppattern != NULL) - { - // Get index of temporary pattern in network's Pattern array - i = tmppattern->i; - - // Check if this is the default pattern - if (strcmp(tmppattern->ID, parser->DefPatID) == 0) parser->DefPat = i; - - // Copy temporary patttern to network's pattern - if (i >= 0 && i <= parser->MaxPats) - { - pattern = &net->Pattern[i]; - strcpy(pattern->ID, tmppattern->ID); - - /* Give pattern a length of at least 1 */ - if (pattern->Length == 0) pattern->Length = 1; - - // Allocate array of pattern factors - pattern->F = (double *)calloc(pattern->Length, sizeof(double)); - if (pattern->F == NULL) return 101; - - // Start at head of temporary pattern multiplier list - // (which holds multipliers in reverse order) - f = tmppattern->x; - j = pattern->Length - 1; - - // Use at least one multiplier equal to 1.0 - if (f == NULL) pattern->F[0] = 1.0; - - // Traverse temporary multiplier list, copying Pattern array */ - else while (f != NULL && j >= 0) - { - pattern->F[j] = f->value; - f = f->next; - j--; - } - } - tmppattern = tmppattern->next; - } - return 0; -} - -int getcurves(Project *pr) -/* -**----------------------------------------------------------- -** Input: none -** Output: returns error code -** Purpose: retrieves curve data from temporary linked list -**----------------------------------------------------------- -*/ -{ - Network *net = &pr->network; - Parser *parser = &pr->parser; - - int i, j; - double x; - char errmsg[MAXMSG+1]; - SFloatlist *fx, *fy; - STmplist *tmpcurve; - Scurve *curve; - - // Traverse list of temporary curves - tmpcurve = parser->Curvelist; - while (tmpcurve != NULL) - { - // Get index of temporary curve in network's Curve array - i = tmpcurve->i; - - // Copy temporary curve to network's curve - if (i >= 1 && i <= parser->MaxCurves) - { - curve = &net->Curve[i]; - strcpy(curve->ID, tmpcurve->ID); - - // Check that network curve has data points - if (curve->Npts <= 0) - { - sprintf(pr->Msg, "Error 230: %s %s", geterrmsg(230, errmsg), curve->ID); - writeline(pr, pr->Msg); - return 200; - } - - // Allocate memory for network's curve data - curve->X = (double *)calloc(curve->Npts, sizeof(double)); - curve->Y = (double *)calloc(curve->Npts, sizeof(double)); - if (curve->X == NULL || curve->Y == NULL) return 101; - - // Traverse list of x,y data - x = BIG; - fx = tmpcurve->x; - fy = tmpcurve->y; - j = curve->Npts - 1; - while (fx != NULL && fy != NULL && j >= 0) - { - // Check that x data is in ascending order - if (fx->value >= x) - { - sprintf(pr->Msg, "Error 230: %s %s", geterrmsg(230, errmsg), curve->ID); - writeline(pr, pr->Msg); - return 200; - } - x = fx->value; - - // Copy x,y data to network's curve - curve->X[j] = fx->value; - fx = fx->next; - curve->Y[j] = fy->value; - fy = fy->next; - j--; - } - } - tmpcurve = tmpcurve->next; - } - return 0; -} - int findmatch(char *line, char *keyword[]) /* **-------------------------------------------------------------- @@ -828,8 +685,8 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment) **-------------------------------------------------------------- */ { - int m, n; - size_t len; + int n; + size_t len, m; char *c, *c2; // clear comment diff --git a/src/input3.c b/src/input3.c index 2a32179..2035d8d 100644 --- a/src/input3.c +++ b/src/input3.c @@ -7,7 +7,7 @@ Description: parses network data from a line of an EPANET input file Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE -Last Updated: 03/17/2019 +Last Updated: 04/03/2019 ****************************************************************************** */ @@ -40,7 +40,6 @@ int powercurve(double, double, double, double, double, double *, double *, // Imported Functions extern int addnodeID(Network *, int, char *); extern int addlinkID(Network *, int, char *); -extern STmplist *getlistitem(char *, STmplist *); // Local functions static int optionchoice(Project *, int); @@ -87,7 +86,6 @@ int juncdata(Project *pr) double el, // elevation y = 0.0; // base demand Pdemand demand; // demand record - STmplist *patlist; // list of demands Snode *node; // Add new junction to data base @@ -104,9 +102,8 @@ int juncdata(Project *pr) if (n >= 3 && !getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202); if (n >= 4) { - patlist = getlistitem(parser->Tok[3], parser->Patlist); - if (patlist == NULL) return setError(parser, 3, 205); - p = patlist->i; + p = findpattern(net, parser->Tok[3]); + if (p == 0) return setError(parser, 3, 205); } // Save junction data @@ -162,7 +159,6 @@ int tankdata(Project *pr) minvol = 0.0, // Minimum volume diam = 0.0, // Diameter area; // X-sect. area - STmplist *tmplist; Snode *node; Stank *tank; @@ -186,9 +182,8 @@ int tankdata(Project *pr) // Head pattern supplied if (n == 3) { - tmplist = getlistitem(parser->Tok[2], parser->Patlist); - if (tmplist == NULL) return setError(parser, 2, 205); - pattern = tmplist->i; + pattern = findpattern(net, parser->Tok[2]); + if (pattern == 0) return setError(parser, 2, 205); } } else if (n < 6) return 201; @@ -205,9 +200,8 @@ int tankdata(Project *pr) // If volume curve supplied check it exists if (n == 8) { - tmplist = getlistitem(parser->Tok[7], parser->Curvelist); - if (tmplist == NULL) return setError(parser, 7, 206); - curve = tmplist->i; + curve = findcurve(net, parser->Tok[7]); + if (curve == 0) return setError(parser, 7, 206); net->Curve[curve].Type = VOLUME_CURVE; } if (initlevel < 0.0) return setError(parser, 2, 209); @@ -357,12 +351,12 @@ int pumpdata(Project *pr) Network *net = &pr->network; Parser *parser = &pr->parser; - int j, + int j, m, // Token array indexes j1, // Start-node index j2, // End-node index - m, n; // # data items + n, // # data items + c, p; // Curve & Pattern indexes double y; - STmplist *tmplist; // Temporary list Slink *link; Spump *pump; @@ -432,15 +426,15 @@ int pumpdata(Project *pr) } else if (match(parser->Tok[m - 1], w_HEAD)) // Custom pump curve { - tmplist = getlistitem(parser->Tok[m], parser->Curvelist); - if (tmplist == NULL) return setError(parser, m, 206); - pump->Hcurve = tmplist->i; + c = findcurve(net, parser->Tok[m]); + if (c == 0) return setError(parser, m, 206); + pump->Hcurve = c; } else if (match(parser->Tok[m - 1], w_PATTERN)) // Speed/status pattern { - tmplist = getlistitem(parser->Tok[m], parser->Patlist); - if (tmplist == NULL) return setError(parser, m, 205); - pump->Upat = tmplist->i; + p = findpattern(net, parser->Tok[m]); + if (p == 0) return setError(parser, m, 205); + pump->Upat = p; } else if (match(parser->Tok[m - 1], w_SPEED)) // Speed setting { @@ -469,7 +463,8 @@ int valvedata(Project *pr) Network *net = &pr->network; Parser *parser = &pr->parser; - int j1, // Start-node index + int c, // Curve index + j1, // Start-node index j2, // End-node index n; // # data items char status = ACTIVE, // Valve status @@ -477,7 +472,6 @@ int valvedata(Project *pr) double diam = 0.0, // Valve diameter setting, // Valve setting lcoeff = 0.0; // Minor loss coeff. - STmplist *tmplist; // Temporary list Slink *link; // Add new valve to data base @@ -508,10 +502,10 @@ int valvedata(Project *pr) // Find headloss curve for GPV if (type == GPV) { - tmplist = getlistitem(parser->Tok[5], parser->Curvelist); - if (tmplist == NULL) return setError(parser, 5, 206); - setting = tmplist->i; - net->Curve[tmplist->i].Type = HLOSS_CURVE; + c = findcurve(net, parser->Tok[5]); + if (c == 0) return setError(parser, 5, 206); + setting = c; + net->Curve[c].Type = HLOSS_CURVE; status = OPEN; } else if (!getfloat(parser->Tok[5], &setting)) return setError(parser, 5, 202); @@ -558,43 +552,47 @@ int patterndata(Project *pr) Network *net = &pr->network; Parser *parser = &pr->parser; - int i, n; + int i, j, n, n1; double x; - SFloatlist *f; - STmplist *p; Spattern *pattern; + // "n" is the number of pattern factors contained in the line n = parser->Ntokens - 1; if (n < 1) return 201; - // Check for a new pattern - if (parser->PrevPat != NULL && - strcmp(parser->Tok[0], parser->PrevPat->ID) == 0) p = parser->PrevPat; + // Check if previous input line was for the same pattern + if (parser->PrevPat && strcmp(parser->Tok[0], parser->PrevPat->ID) == 0) + { + pattern = parser->PrevPat; + } + + // Otherwise retrieve pattern from the network's Pattern array else { - p = getlistitem(parser->Tok[0], parser->Patlist); - if (p == NULL) return setError(parser, 0, 205); - pattern = &(net->Pattern[p->i]); - pattern->Comment = xstrcpy(&pattern->Comment, parser->Comment, MAXMSG); + i = findpattern(net, parser->Tok[0]); + if (i == 0) return setError(parser, 0, 205); + pattern = &(net->Pattern[i]); + if (pattern->Comment == NULL && parser->Comment[0]) + { + pattern->Comment = xstrcpy(&pattern->Comment, parser->Comment, MAXMSG); + } } + // Expand size of the pattern's factors array + n1 = pattern->Length; + pattern->Length += n; + pattern->F = realloc(pattern->F, pattern->Length * sizeof(double)); + // Add parsed multipliers to the pattern - for (i = 1; i <= n; i++) + for (j = 1; j <= n; j++) { - if (!getfloat(parser->Tok[i], &x)) return setError(parser, i, 202); - f = (SFloatlist *)malloc(sizeof(SFloatlist)); - if (f == NULL) return 101; - f->value = x; - f->next = p->x; - p->x = f; + if (!getfloat(parser->Tok[j], &x)) return setError(parser, j, 202); + pattern->F[n1 + j - 1] = x; } - // Save # multipliers for pattern - net->Pattern[p->i].Length += n; - - // Set previous pattern pointer - parser->PrevPat = p; - return (0); + // Save a reference to this pattern for processing additional pattern data + parser->PrevPat = pattern; + return 0; } int curvedata(Project *pr) @@ -612,46 +610,46 @@ int curvedata(Project *pr) Network *net = &pr->network; Parser *parser = &pr->parser; + int i; double x, y; - SFloatlist *fx, *fy; - STmplist *c; Scurve *curve; - // Check for valid curve ID - if (parser->Ntokens < 3) return 201; - if (parser->PrevCurve != NULL && - strcmp(parser->Tok[0], parser->PrevCurve->ID) == 0) c = parser->PrevCurve; - else - { - c = getlistitem(parser->Tok[0], parser->Curvelist); - if (c == NULL) return setError(parser, 0, 206); - curve = &(net->Curve[c->i]); - curve->Comment = xstrcpy(&curve->Comment, parser->Comment, MAXMSG); - } - // Check for valid data + if (parser->Ntokens < 3) return 201; if (!getfloat(parser->Tok[1], &x)) return setError(parser, 1, 202); if (!getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202); - // Add new data point to curve - fx = (SFloatlist *)malloc(sizeof(SFloatlist)); - if (fx == NULL) return 101; - fy = (SFloatlist *)malloc(sizeof(SFloatlist)); - if (fy == NULL) + // Check if previous input line was for the same curve + if (parser->PrevCurve && strcmp(parser->Tok[0], parser->PrevCurve->ID) == 0) { - free(fx); - return 101; + curve = parser->PrevCurve; } - fx->value = x; - fx->next = c->x; - c->x = fx; - fy->value = y; - fy->next = c->y; - c->y = fy; - net->Curve[c->i].Npts++; - // Save the pointer to this curve - parser->PrevCurve = c; + // Otherwise retrieve curve from the network's Curve array + else + { + i = findcurve(net, parser->Tok[0]); + if (i == 0) return setError(parser, 0, 206); + curve = &(net->Curve[i]); + if (curve->Comment == NULL && parser->Comment[0]) + { + curve->Comment = xstrcpy(&curve->Comment, parser->Comment, MAXMSG); + } + } + + // Expand size of data arrays if need be + if (curve->Capacity == curve->Npts) + { + if (resizecurve(curve, curve->Capacity + 10) > 0) return 101; + } + + // Add new data point to curve + curve->X[curve->Npts] = x; + curve->Y[curve->Npts] = y; + curve->Npts++; + + // Save a reference to this curve for processing additional curve data + parser->PrevCurve = curve; return 0; } @@ -713,7 +711,6 @@ int demanddata(Project *pr) double y; Pdemand demand; Pdemand cur_demand; - STmplist *patlist; // Extract data from tokens n = parser->Ntokens; @@ -733,9 +730,8 @@ int demanddata(Project *pr) if (j > net->Njuncs) return 0; if (n >= 3) { - patlist = getlistitem(parser->Tok[2], parser->Patlist); - if (patlist == NULL) return setError(parser, 2, 205); - p = patlist->i; + p = findpattern(net, parser->Tok[2]); + if (p == 0) return setError(parser, 2, 205); } // Replace any demand entered in [JUNCTIONS] section @@ -746,7 +742,10 @@ int demanddata(Project *pr) // with what is specified in this section demand->Base = y; demand->Pat = p; - demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXMSG); + if (parser->Comment[0]) + { + demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID); + } hyd->NodeDemand[j] = MISSING; // marker - next iteration will append a new category. } @@ -759,7 +758,11 @@ int demanddata(Project *pr) if (demand == NULL) return 101; demand->Base = y; demand->Pat = p; - demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXMSG); + demand->Name = NULL; + if (parser->Comment[0]) + { + demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID); + } demand->next = NULL; cur_demand->next = demand; } @@ -900,7 +903,6 @@ int sourcedata(Project *pr) p = 0; // Time pattern index char type = CONCEN; // Source type double c0 = 0; // Initial quality - STmplist *patlist; Psource source; // Check for enough tokens & that source node exists @@ -929,9 +931,8 @@ int sourcedata(Project *pr) if (n > i + 1 && strlen(parser->Tok[i + 1]) > 0 && strcmp(parser->Tok[i + 1], "*") != 0) { - patlist = getlistitem(parser->Tok[i + 1], parser->Patlist); - if (patlist == NULL) return setError(parser, i+1, 205); - p = patlist->i; + p = findpattern(net, parser->Tok[i + 1]); + if (p == 0) return setError(parser, i + 1, 205); } // Destroy any existing source assigned to node @@ -1335,10 +1336,9 @@ int energydata(Project *pr) Hydraul *hyd = &pr->hydraul; Parser *parser = &pr->parser; - int j, k, n; + int j, k, n, p, c; double y; - STmplist *listitem; Slink *Link = net->Link; Spump *Pump = net->Pump; @@ -1385,10 +1385,10 @@ int energydata(Project *pr) // Price PATTERN being set else if (match(parser->Tok[n - 2], w_PATTERN)) { - listitem = getlistitem(parser->Tok[n - 1], parser->Patlist); - if (listitem == NULL) return setError(parser, n - 1, 205); - if (j == 0) hyd->Epat = listitem->i; - else Pump[j].Epat = listitem->i; + p = findpattern(net, parser->Tok[n - 1]); + if (p == 0) return setError(parser, n - 1, 205); + if (j == 0) hyd->Epat = p; + else Pump[j].Epat = p; return 0; } @@ -1403,10 +1403,10 @@ int energydata(Project *pr) } else { - listitem = getlistitem(parser->Tok[n - 1], parser->Curvelist); - if (listitem == NULL) return setError(parser, n - 1, 206); - Pump[j].Ecurve = listitem->i; - net->Curve[listitem->i].Type = EFFIC_CURVE; + c = findcurve(net, parser->Tok[n - 1]); + if (c == 0) return setError(parser, n - 1, 206); + Pump[j].Ecurve = c; + net->Curve[c].Type = EFFIC_CURVE; } return 0; } diff --git a/src/project.c b/src/project.c index a2e5654..1ee3295 100644 --- a/src/project.c +++ b/src/project.c @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 03/17/2019 + Last Updated: 04/03/2019 ****************************************************************************** */ @@ -274,9 +274,6 @@ void initpointers(Project *pr) pr->network.NodeHashTable = NULL; pr->network.LinkHashTable = NULL; - pr->parser.Patlist = NULL; - pr->parser.Curvelist = NULL; - pr->hydraul.smatrix.Aii = NULL; pr->hydraul.smatrix.Aij = NULL; pr->hydraul.smatrix.F = NULL; @@ -317,10 +314,10 @@ int allocdata(Project *pr) if (!errcode) { n = pr->parser.MaxNodes + 1; - pr->network.Node = (Snode *)calloc(n, sizeof(Snode)); + pr->network.Node = (Snode *)calloc(n, sizeof(Snode)); pr->hydraul.NodeDemand = (double *)calloc(n, sizeof(double)); pr->hydraul.NodeHead = (double *)calloc(n, sizeof(double)); - pr->quality.NodeQual = (double *)calloc(n, sizeof(double)); + pr->quality.NodeQual = (double *)calloc(n, sizeof(double)); ERRCODE(MEMCHECK(pr->network.Node)); ERRCODE(MEMCHECK(pr->hydraul.NodeDemand)); ERRCODE(MEMCHECK(pr->hydraul.NodeHead)); @@ -331,8 +328,8 @@ int allocdata(Project *pr) if (!errcode) { n = pr->parser.MaxLinks + 1; - pr->network.Link = (Slink *)calloc(n, sizeof(Slink)); - pr->hydraul.LinkFlow = (double *)calloc(n, sizeof(double)); + pr->network.Link = (Slink *)calloc(n, sizeof(Slink)); + pr->hydraul.LinkFlow = (double *)calloc(n, sizeof(double)); pr->hydraul.LinkSetting = (double *)calloc(n, sizeof(double)); pr->hydraul.LinkStatus = (StatusType *)calloc(n, sizeof(StatusType)); ERRCODE(MEMCHECK(pr->network.Link)); @@ -341,8 +338,8 @@ int allocdata(Project *pr) ERRCODE(MEMCHECK(pr->hydraul.LinkStatus)); } - // Allocate memory for tanks, sources, pumps, valves, - // controls, demands, time patterns, & operating curves + // Allocate memory for tanks, sources, pumps, valves, and controls + // (memory for Patterns and Curves arrays expanded as each is added) if (!errcode) { pr->network.Tank = @@ -353,35 +350,15 @@ int allocdata(Project *pr) (Svalve *)calloc(pr->parser.MaxValves + 1, sizeof(Svalve)); pr->network.Control = (Scontrol *)calloc(pr->parser.MaxControls + 1, sizeof(Scontrol)); - pr->network.Pattern = - (Spattern *)calloc(pr->parser.MaxPats + 1, sizeof(Spattern)); - pr->network.Curve = - (Scurve *)calloc(pr->parser.MaxCurves + 1, sizeof(Scurve)); ERRCODE(MEMCHECK(pr->network.Tank)); ERRCODE(MEMCHECK(pr->network.Pump)); ERRCODE(MEMCHECK(pr->network.Valve)); ERRCODE(MEMCHECK(pr->network.Control)); - ERRCODE(MEMCHECK(pr->network.Pattern)); - ERRCODE(MEMCHECK(pr->network.Curve)); } - // Initialize pointers used in patterns, curves, and demand category lists + // Initialize pointers used in nodes and links if (!errcode) { - for (n = 0; n <= pr->parser.MaxPats; n++) - { - pr->network.Pattern[n].Length = 0; - pr->network.Pattern[n].F = NULL; - pr->network.Pattern[n].Comment = NULL; - } - for (n = 0; n <= pr->parser.MaxCurves; n++) - { - pr->network.Curve[n].Npts = 0; - pr->network.Curve[n].Type = GENERIC_CURVE; - pr->network.Curve[n].X = NULL; - pr->network.Curve[n].Y = NULL; - pr->network.Curve[n].Comment = NULL; - } for (n = 0; n <= pr->parser.MaxNodes; n++) { pr->network.Node[n].D = NULL; // node demand @@ -399,43 +376,6 @@ int allocdata(Project *pr) return errcode; } -void freeTmplist(STmplist *t) -/*---------------------------------------------------------------- -** Input: t = pointer to start of a temporary list -** Output: none -** Purpose: frees memory used for temporary storage -** of pattern & curve data -**---------------------------------------------------------------- -*/ -{ - STmplist *tnext; - while (t != NULL) - { - tnext = t->next; - freeFloatlist(t->x); - freeFloatlist(t->y); - free(t); - t = tnext; - } -} - -void freeFloatlist(SFloatlist *f) -/*---------------------------------------------------------------- -** Input: f = pointer to start of list of floats -** Output: none -** Purpose: frees memory used for storing list of floats -**---------------------------------------------------------------- -*/ -{ - SFloatlist *fnext; - while (f != NULL) - { - fnext = f->next; - free(f); - f = fnext; - } -} - void freedata(Project *pr) /*---------------------------------------------------------------- ** Input: none @@ -446,7 +386,6 @@ void freedata(Project *pr) { int j; Pdemand demand, nextdemand; - Psource source; // Free memory for computed results free(pr->hydraul.NodeDemand); @@ -474,8 +413,7 @@ void freedata(Project *pr) demand = nextdemand; } // Free memory used for WQ source data - source = pr->network.Node[j].S; - free(source); + free(pr->network.Node[j].S); free(pr->network.Node[j].Comment); } free(pr->network.Node); @@ -511,7 +449,8 @@ void freedata(Project *pr) // Free memory for curves if (pr->network.Curve != NULL) { - for (j = 0; j <= pr->parser.MaxCurves; j++) + // There is no Curve[0] + for (j = 1; j <= pr->parser.MaxCurves; j++) { free(pr->network.Curve[j].X); free(pr->network.Curve[j].Y); @@ -809,6 +748,40 @@ int findvalve(Network *network, int index) return NOTFOUND; } +int findpattern(Network *network, char *id) +/*---------------------------------------------------------------- +** Input: id = time pattern ID +** Output: none +** Returns: time pattern index, or 0 if pattern not found +** Purpose: finds index of time pattern given its ID +**---------------------------------------------------------------- +*/ +{ + int i; + for (i = 1; i <= network->Npats; i++) + { + if (strcmp(id, network->Pattern[i].ID) == 0) return i; + } + return 0; +} + +int findcurve(Network *network, char *id) +/*---------------------------------------------------------------- +** Input: id = data curve ID +** Output: none +** Returns: data curve index, or 0 if curve not found +** Purpose: finds index of data curve given its ID +**---------------------------------------------------------------- +*/ +{ + int i; + for (i = 1; i <= network->Ncurves; i++) + { + if (strcmp(id, network->Curve[i].ID) == 0) return i; + } + return 0; +} + void adjustpattern(int *pat, int index) /*---------------------------------------------------------------- ** Local function that modifies a reference to a deleted time pattern @@ -904,6 +877,35 @@ void adjustcurves(Network *network, int index) } } +int resizecurve(Scurve *curve, int size) +/*---------------------------------------------------------------- +** Input: curve = a data curve object +** size = desired number of curve data points +** Output: error code +** Purpose: resizes a data curve to a desired size +**---------------------------------------------------------------- +*/ +{ + double *x; + double *y; + + if (curve->Capacity < size) + { + x = (double *)realloc(curve->X, size * sizeof(double)); + if (x == NULL) return 101; + y = (double *)realloc(curve->Y, size * sizeof(double)); + if (y == NULL) + { + free(x); + return 101; + } + curve->X = x; + curve->Y = y; + curve->Capacity = size; + } + return 0; +} + int getcomment(Network *network, int object, int index, char *comment) //---------------------------------------------------------------- // Input: object = a type of network object diff --git a/src/types.h b/src/types.h index 0f574ce..476afac 100755 --- a/src/types.h +++ b/src/types.h @@ -317,23 +317,6 @@ struct IDstring // Holds component ID label char ID[MAXID+1]; }; -struct Floatlist // Element of List of Numbers -{ - double value; // element's numerical value - struct Floatlist *next; // next element on the list -}; -typedef struct Floatlist SFloatlist; - -struct Tmplist // Item of Temporary List of Objects -{ - int i; // object's index - char ID[MAXID+1]; // object's ID name - SFloatlist *x; // list of data values - SFloatlist *y; // list of data values - struct Tmplist *next; // next object on list -}; -typedef struct Tmplist STmplist; // Pointer to temporary list of objects - typedef struct // Time Pattern Object { char ID[MAXID+1]; // pattern ID @@ -348,6 +331,7 @@ typedef struct // Curve Object char *Comment; // curve comment CurveType Type; // curve type int Npts; // number of points + int Capacity; // size of X & Y arrays double *X; // x-values double *Y; // y-values } Scurve; @@ -576,12 +560,8 @@ typedef struct { Pressflag, // Pressure units flag DefPat; // Default demand pattern - STmplist - *Patlist, // Temporary time pattern list - *PrevPat, // Previous pattern list element - *Curvelist, // Temporary list of curves - *PrevCurve; // Previous curve list element - + Spattern *PrevPat; // Previous pattern processed + Scurve *PrevCurve; // Previous curve processed double *X; // Temporary array for curve data } Parser; From b2a8b55bc64e0c6fc8ea6508efba19e0a118fe5a Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Fri, 5 Apr 2019 16:28:55 -0400 Subject: [PATCH 15/15] Update input2.c --- src/input2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/input2.c b/src/input2.c index 482103e..5adb3e4 100644 --- a/src/input2.c +++ b/src/input2.c @@ -564,6 +564,7 @@ int addcurve(Network *network, char *id) // Initialize the curve curve = &network->Curve[network->Ncurves]; strncpy(curve->ID, id, MAXID); + curve->Type = GENERIC_CURVE; curve->Comment = NULL; curve->Capacity = 0; curve->Npts = 0;