From 27bf153941a2c2b023a1d07225bd8cb28ebdd9f8 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 26 Mar 2019 13:09:09 -0400 Subject: [PATCH 01/49] Updating py API with changes to errormanager --- src/epanet_py.c | 224 ++++++++++++++++++++++++------------------------ 1 file changed, 112 insertions(+), 112 deletions(-) diff --git a/src/epanet_py.c b/src/epanet_py.c index 3ee3898..fb681aa 100644 --- a/src/epanet_py.c +++ b/src/epanet_py.c @@ -39,7 +39,7 @@ int EXPORT_PY_API proj_create(Handle *ph) if (handle != NULL) { EN_createproject(&handle->project); - handle->error = error_new_manager(&error_lookup); + handle->error = create_error_manager(&error_lookup); *ph = handle; return 0; } @@ -55,7 +55,7 @@ int EXPORT_PY_API proj_delete(Handle *ph) else { EN_deleteproject(&handle->project); - error_dst_manager(handle->error); + delete_error_manager(handle->error); } free(handle); *ph = NULL; @@ -67,51 +67,51 @@ int EXPORT_PY_API proj_run(Handle ph, const char *input_path, const char *report_path, const char *output_path) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_runproject(pr->project, input_path, report_path, output_path, NULL)); + return set_error(pr->error, EN_runproject(pr->project, input_path, report_path, output_path, NULL)); } int EXPORT_PY_API proj_init(Handle ph, const char *rptFile, const char *outFile, EN_FlowUnits unitsType, EN_HeadLossType headLossType) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_init(pr->project, rptFile, outFile, unitsType, headLossType)); + return set_error(pr->error, EN_init(pr->project, rptFile, outFile, unitsType, headLossType)); } int EXPORT_PY_API proj_open(Handle ph, const char *inpFile, const char *rptFile, const char *binOutFile) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_open(pr->project, inpFile, rptFile, binOutFile)); + return set_error(pr->error, EN_open(pr->project, inpFile, rptFile, binOutFile)); } int EXPORT_PY_API proj_gettitle(Handle ph, char *line1, char *line2, char *line3) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_gettitle(pr->project, line1, line2, line3)); + return set_error(pr->error, EN_gettitle(pr->project, line1, line2, line3)); } int EXPORT_PY_API proj_settitle(Handle ph, const char *line1, const char *line2, const char *line3) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_settitle(pr->project, (char *)line1, (char *)line2, (char *)line3)); + return set_error(pr->error, EN_settitle(pr->project, (char *)line1, (char *)line2, (char *)line3)); } int EXPORT_PY_API proj_getcount(Handle ph, EN_CountType code, int *count) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getcount(pr->project, code, count)); + return set_error(pr->error, EN_getcount(pr->project, code, count)); } int EXPORT_PY_API proj_savefile(Handle ph, const char *filename) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_saveinpfile(pr->project, filename)); + return set_error(pr->error, EN_saveinpfile(pr->project, filename)); } int EXPORT_PY_API proj_close(Handle ph) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_close(pr->project)); + return set_error(pr->error, EN_close(pr->project)); } @@ -120,55 +120,55 @@ int EXPORT_PY_API proj_close(Handle ph) int EXPORT_PY_API hydr_solve(Handle ph) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_solveH(pr->project)); + return set_error(pr->error, EN_solveH(pr->project)); } int EXPORT_PY_API hydr_save(Handle ph) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_saveH(pr->project)); + return set_error(pr->error, EN_saveH(pr->project)); } int EXPORT_PY_API hydr_open(Handle ph) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_openH(pr->project)); + return set_error(pr->error, EN_openH(pr->project)); } int EXPORT_PY_API hydr_init(Handle ph, EN_InitHydOption saveFlag) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_initH(pr->project, saveFlag)); + return set_error(pr->error, EN_initH(pr->project, saveFlag)); } int EXPORT_PY_API hydr_run(Handle ph, long *currentTime) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_runH(pr->project, currentTime)); + return set_error(pr->error, EN_runH(pr->project, currentTime)); } int EXPORT_PY_API hydr_next(Handle ph, long *tStep) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_nextH(pr->project, tStep)); + return set_error(pr->error, EN_nextH(pr->project, tStep)); } int EXPORT_PY_API hydr_close(Handle ph) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_closeH(pr->project)); + return set_error(pr->error, EN_closeH(pr->project)); } int EXPORT_PY_API hydr_savefile(Handle ph, char *filename) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_savehydfile(pr->project, filename)); + return set_error(pr->error, EN_savehydfile(pr->project, filename)); } int EXPORT_PY_API hydr_usefile(Handle ph, char *filename) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_usehydfile(pr->project, filename)); + return set_error(pr->error, EN_usehydfile(pr->project, filename)); } @@ -177,43 +177,43 @@ int EXPORT_PY_API hydr_usefile(Handle ph, char *filename) int EXPORT_PY_API qual_solve(Handle ph) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_solveQ(pr->project)); + return set_error(pr->error, EN_solveQ(pr->project)); } int EXPORT_PY_API qual_open(Handle ph) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_openQ(pr->project)); + return set_error(pr->error, EN_openQ(pr->project)); } int EXPORT_PY_API qual_init(Handle ph, EN_InitHydOption saveFlag) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_initQ(pr->project, saveFlag)); + return set_error(pr->error, EN_initQ(pr->project, saveFlag)); } int EXPORT_PY_API qual_run(Handle ph, long *currentTime) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_runQ(pr->project, currentTime)); + return set_error(pr->error, EN_runQ(pr->project, currentTime)); } int EXPORT_PY_API qual_next(Handle ph, long *tStep) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_nextQ(pr->project, tStep)); + return set_error(pr->error, EN_nextQ(pr->project, tStep)); } int EXPORT_PY_API qual_step(Handle ph, long *timeLeft) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_stepQ(pr->project, timeLeft)); + return set_error(pr->error, EN_stepQ(pr->project, timeLeft)); } int EXPORT_PY_API qual_close(Handle ph) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_closeQ(pr->project)); + return set_error(pr->error, EN_closeQ(pr->project)); } @@ -222,43 +222,43 @@ int EXPORT_PY_API qual_close(Handle ph) int EXPORT_PY_API rprt_writeline(Handle ph, char *line) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_writeline(pr->project, line)); + return set_error(pr->error, EN_writeline(pr->project, line)); } int EXPORT_PY_API rprt_writeresults(Handle ph) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_report(pr->project)); + return set_error(pr->error, EN_report(pr->project)); } int EXPORT_PY_API rprt_clear(Handle ph) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_clearreport(pr->project)); + return set_error(pr->error, EN_clearreport(pr->project)); } int EXPORT_PY_API rprt_reset(Handle ph) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_resetreport(pr->project)); + return set_error(pr->error, EN_resetreport(pr->project)); } int EXPORT_PY_API rprt_set(Handle ph, char *reportCommand) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setreport(pr->project, reportCommand)); + return set_error(pr->error, EN_setreport(pr->project, reportCommand)); } int EXPORT_PY_API rprt_setlevel(Handle ph, EN_StatusReport code) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setstatusreport(pr->project, code)); + return set_error(pr->error, EN_setstatusreport(pr->project, code)); } int EXPORT_PY_API rprt_anlysstats(Handle ph, EN_AnalysisStatistic code, double* value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getstatistic(pr->project, code, value)); + return set_error(pr->error, EN_getstatistic(pr->project, code, value)); } @@ -267,55 +267,55 @@ int EXPORT_PY_API rprt_anlysstats(Handle ph, EN_AnalysisStatistic code, double* int EXPORT_PY_API anlys_getoption(Handle ph, EN_Option code, double *value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getoption(pr->project, (int)code, value)); + return set_error(pr->error, EN_getoption(pr->project, (int)code, value)); } int EXPORT_PY_API anlys_setoption(Handle ph, EN_Option code, double value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setoption(pr->project, (int)code, value)); + return set_error(pr->error, EN_setoption(pr->project, (int)code, value)); } int EXPORT_PY_API anlys_getflowunits(Handle ph, int *code) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getflowunits(pr->project, code)); + return set_error(pr->error, EN_getflowunits(pr->project, code)); } int EXPORT_PY_API anlys_setflowunits(Handle ph, EN_FlowUnits code) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setflowunits(pr->project, code)); + return set_error(pr->error, EN_setflowunits(pr->project, code)); } int EXPORT_PY_API anlys_gettimeparam(Handle ph, EN_TimeParameter code, long *value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_gettimeparam(pr->project, code, value)); + return set_error(pr->error, EN_gettimeparam(pr->project, code, value)); } int EXPORT_PY_API anlys_settimeparam(Handle ph, EN_TimeParameter code, long value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_settimeparam(pr->project, code, value)); + return set_error(pr->error, EN_settimeparam(pr->project, code, value)); } int EXPORT_PY_API anlys_getqualinfo(Handle ph, int *qualcode, char *chemname, char *chemunits, int *tracenode) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getqualinfo(pr->project, qualcode, chemname, chemunits, tracenode)); + return set_error(pr->error, EN_getqualinfo(pr->project, qualcode, chemname, chemunits, tracenode)); } int EXPORT_PY_API anlys_getqualtype(Handle ph, int *qualcode, int *tracenode) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getqualtype(pr->project, qualcode, tracenode)); + return set_error(pr->error, EN_getqualtype(pr->project, qualcode, tracenode)); } int EXPORT_PY_API anlys_setqualtype(Handle ph, EN_QualityType qualcode, char *chemname, char *chemunits, char *tracenode) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setqualtype(pr->project, qualcode, chemname, chemunits, tracenode)); + return set_error(pr->error, EN_setqualtype(pr->project, qualcode, chemname, chemunits, tracenode)); } @@ -324,61 +324,61 @@ int EXPORT_PY_API anlys_setqualtype(Handle ph, EN_QualityType qualcode, char *ch int EXPORT_PY_API node_add(Handle ph, char *id, EN_NodeType nodeType) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_addnode(pr->project, id, nodeType)); + return set_error(pr->error, EN_addnode(pr->project, id, nodeType)); } int EXPORT_PY_API node_delete(Handle ph, int index, int actionCode) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_deletenode(pr->project, index, actionCode)); + return set_error(pr->error, EN_deletenode(pr->project, index, actionCode)); } int EXPORT_PY_API node_getindex(Handle ph, char *id, int *index) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getnodeindex(pr->project, id, index)); + return set_error(pr->error, EN_getnodeindex(pr->project, id, index)); } int EXPORT_PY_API node_getid(Handle ph, int index, char *id) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getnodeid(pr->project, index, id)); + return set_error(pr->error, EN_getnodeid(pr->project, index, id)); } int EXPORT_PY_API node_setid(Handle ph, int index, char *newid) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getnodeid(pr->project, index, newid)); + return set_error(pr->error, EN_getnodeid(pr->project, index, newid)); } int EXPORT_PY_API node_gettype(Handle ph, int index, int *code) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getnodetype(pr->project, index, code)); + return set_error(pr->error, EN_getnodetype(pr->project, index, code)); } int EXPORT_PY_API node_getvalue(Handle ph, int index, EN_NodeProperty code, double *value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getnodevalue(pr->project, index, (int)code, value)); + return set_error(pr->error, EN_getnodevalue(pr->project, index, (int)code, value)); } int EXPORT_PY_API node_setvalue(Handle ph, int index, EN_NodeProperty code, double value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setnodevalue(pr->project, index, (int)code, value)); + return set_error(pr->error, EN_setnodevalue(pr->project, index, (int)code, value)); } int EXPORT_PY_API node_getcoord(Handle ph, int index, double *x, double *y) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getcoord(pr->project, index, x, y)); + return set_error(pr->error, EN_getcoord(pr->project, index, x, y)); } int EXPORT_PY_API node_setcoord(Handle ph, int index, double x, double y) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setcoord(pr->project, index, x, y)); + return set_error(pr->error, EN_setcoord(pr->project, index, x, y)); } @@ -387,55 +387,55 @@ int EXPORT_PY_API node_setcoord(Handle ph, int index, double x, double y) int EXPORT_PY_API dmnd_getmodel(Handle ph, int *type, double *pmin, double *preq, double *pexp) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getdemandmodel(pr->project, type, pmin, preq, pexp)); + return set_error(pr->error, EN_getdemandmodel(pr->project, type, pmin, preq, pexp)); } int EXPORT_PY_API dmnd_setmodel(Handle ph, int type, double pmin, double preq, double pexp) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setdemandmodel(pr->project, type, pmin, preq, pexp)); + return set_error(pr->error, EN_setdemandmodel(pr->project, type, pmin, preq, pexp)); } int EXPORT_PY_API dmnd_getcount(Handle ph, int nodeIndex, int *numDemands) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getnumdemands(pr->project, nodeIndex, numDemands)); + return set_error(pr->error, EN_getnumdemands(pr->project, nodeIndex, numDemands)); } int EXPORT_PY_API dmnd_getbase(Handle ph, int nodeIndex, int demandIndex, double *baseDemand) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getbasedemand(pr->project, nodeIndex, demandIndex, baseDemand)); + return set_error(pr->error, EN_getbasedemand(pr->project, nodeIndex, demandIndex, baseDemand)); } int EXPORT_PY_API dmnd_setbase(Handle ph, int nodeIndex, int demandIndex, double baseDemand) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setbasedemand(pr->project, nodeIndex, demandIndex, baseDemand)); + return set_error(pr->error, EN_setbasedemand(pr->project, nodeIndex, demandIndex, baseDemand)); } int EXPORT_PY_API dmnd_getpattern(Handle ph, int nodeIndex, int demandIndex, int *patIndex) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getdemandpattern(pr->project, nodeIndex, demandIndex, patIndex)); + return set_error(pr->error, EN_getdemandpattern(pr->project, nodeIndex, demandIndex, patIndex)); } int EXPORT_PY_API dmnd_setpattern(Handle ph, int nodeIndex, int demandIndex, int patIndex) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setdemandpattern(pr->project, nodeIndex, demandIndex, patIndex)); + return set_error(pr->error, EN_setdemandpattern(pr->project, nodeIndex, demandIndex, patIndex)); } int EXPORT_PY_API dmnd_getname(Handle ph, int nodeIndex, int demandIdx, char *demandName) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getdemandname(pr->project, nodeIndex, demandIdx, demandName)); + return set_error(pr->error, EN_getdemandname(pr->project, nodeIndex, demandIdx, demandName)); } int EXPORT_PY_API dmnd_setname(Handle ph, int nodeIndex, int demandIdx, char *demandName) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setdemandname(pr->project, nodeIndex, demandIdx, demandName)); + return set_error(pr->error, EN_setdemandname(pr->project, nodeIndex, demandIdx, demandName)); } @@ -444,67 +444,67 @@ int EXPORT_PY_API dmnd_setname(Handle ph, int nodeIndex, int demandIdx, char *de int EXPORT_PY_API link_add(Handle ph, char *id, EN_LinkType linkType, char *fromNode, char *toNode) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_addlink(pr->project, id, linkType, fromNode, toNode)); + return set_error(pr->error, EN_addlink(pr->project, id, linkType, fromNode, toNode)); } int EXPORT_PY_API link_delete(Handle ph, int index, int actionCode) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_deletelink(pr->project, index, actionCode)); + return set_error(pr->error, EN_deletelink(pr->project, index, actionCode)); } int EXPORT_PY_API link_getindex(Handle ph, char *id, int *index) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getlinkindex(pr->project, id, index)); + return set_error(pr->error, EN_getlinkindex(pr->project, id, index)); } int EXPORT_PY_API link_getid(Handle ph, int index, char *id) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getlinkid(pr->project, index, id)); + return set_error(pr->error, EN_getlinkid(pr->project, index, id)); } int EXPORT_PY_API link_setid(Handle ph, int index, char *newid) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setlinkid(pr->project, index, newid)); + return set_error(pr->error, EN_setlinkid(pr->project, index, newid)); } int EXPORT_PY_API link_gettype(Handle ph, int index, int *code) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getlinktype(pr->project, index, code)); + return set_error(pr->error, EN_getlinktype(pr->project, index, code)); } int EXPORT_PY_API link_settype(Handle ph, int *index, EN_LinkType type, int actionCode) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setlinktype(pr->project, index, type, actionCode)); + return set_error(pr->error, EN_setlinktype(pr->project, index, type, actionCode)); } int EXPORT_PY_API link_getnodes(Handle ph, int index, int *node1, int *node2) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getlinknodes(pr->project, index, node1, node2)); + return set_error(pr->error, EN_getlinknodes(pr->project, index, node1, node2)); } int EXPORT_PY_API link_setnodes(Handle ph, int index, int node1, int node2) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setlinknodes(pr->project, index, node1, node2)); + return set_error(pr->error, EN_setlinknodes(pr->project, index, node1, node2)); } int EXPORT_PY_API link_getvalue(Handle ph, int index, EN_LinkProperty code, double *value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getlinkvalue(pr->project, index, code, value)); + return set_error(pr->error, EN_getlinkvalue(pr->project, index, code, value)); } int EXPORT_PY_API link_setvalue(Handle ph, int index, int code, double value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setlinkvalue(pr->project, index, code, value)); + return set_error(pr->error, EN_setlinkvalue(pr->project, index, code, value)); } @@ -513,19 +513,19 @@ int EXPORT_PY_API link_setvalue(Handle ph, int index, int code, double value) int EXPORT_PY_API pump_gettype(Handle ph, int linkIndex, int *outType) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getpumptype(pr->project, linkIndex, outType)); + return set_error(pr->error, EN_getpumptype(pr->project, linkIndex, outType)); } int EXPORT_PY_API pump_getheadcurveindex(Handle ph, int pumpIndex, int *curveIndex) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getheadcurveindex(pr->project, pumpIndex, curveIndex)); + return set_error(pr->error, EN_getheadcurveindex(pr->project, pumpIndex, curveIndex)); } int EXPORT_PY_API pump_setheadcurveindex(Handle ph, int pumpIndex, int curveIndex) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setheadcurveindex(pr->project, pumpIndex, curveIndex)); + return set_error(pr->error, EN_setheadcurveindex(pr->project, pumpIndex, curveIndex)); } @@ -534,49 +534,49 @@ int EXPORT_PY_API pump_setheadcurveindex(Handle ph, int pumpIndex, int curveInde int EXPORT_PY_API ptrn_add(Handle ph, char *id) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_addpattern(pr->project, id)); + return set_error(pr->error, EN_addpattern(pr->project, id)); } int EXPORT_PY_API ptrn_getindex(Handle ph, char *id, int *index) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getpatternindex(pr->project, id, index)); + return set_error(pr->error, EN_getpatternindex(pr->project, id, index)); } int EXPORT_PY_API ptrn_getid(Handle ph, int index, char *id) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getpatternid(pr->project, index, id)); + return set_error(pr->error, EN_getpatternid(pr->project, index, id)); } int EXPORT_PY_API ptrn_getlength(Handle ph, int index, int *len) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getpatternlen(pr->project, index, len)); + return set_error(pr->error, EN_getpatternlen(pr->project, index, len)); } int EXPORT_PY_API ptrn_getvalue(Handle ph, int index, int period, double *value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getpatternvalue(pr->project, index, period, value)); + return set_error(pr->error, EN_getpatternvalue(pr->project, index, period, value)); } int EXPORT_PY_API ptrn_setvalue(Handle ph, int index, int period, double value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setpatternvalue(pr->project, index, period, value)); + return set_error(pr->error, EN_setpatternvalue(pr->project, index, period, value)); } int EXPORT_PY_API ptrn_getavgvalue(Handle ph, int index, double *value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getaveragepatternvalue(pr->project, index, value)); + return set_error(pr->error, EN_getaveragepatternvalue(pr->project, index, value)); } int EXPORT_PY_API ptrn_set(Handle ph, int index, double *values, int len) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setpattern(pr->project, index, values, len)); + return set_error(pr->error, EN_setpattern(pr->project, index, values, len)); } @@ -585,55 +585,55 @@ int EXPORT_PY_API ptrn_set(Handle ph, int index, double *values, int len) int EXPORT_PY_API curv_add(Handle ph, char *id) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_addcurve(pr->project, id)); + return set_error(pr->error, EN_addcurve(pr->project, id)); } int EXPORT_PY_API curv_getindex(Handle ph, char *id, int *index) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getcurveindex(pr->project, id, index)); + return set_error(pr->error, EN_getcurveindex(pr->project, id, index)); } int EXPORT_PY_API curv_getid(Handle ph, int index, char *id) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getcurveid(pr->project, index, id)); + return set_error(pr->error, EN_getcurveid(pr->project, index, id)); } int EXPORT_PY_API curv_getlength(Handle ph, int index, int *len) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getcurvelen(pr->project, index, len)); + return set_error(pr->error, EN_getcurvelen(pr->project, index, len)); } int EXPORT_PY_API curv_gettype(Handle ph, int index, int *type) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getcurvetype(pr->project, index, type)); + return set_error(pr->error, EN_getcurvetype(pr->project, index, type)); } int EXPORT_PY_API curv_getvalue(Handle ph, int curveIndex, int pointIndex, double *x, double *y) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getcurvevalue(pr->project, curveIndex, pointIndex, x, y)); + return set_error(pr->error, EN_getcurvevalue(pr->project, curveIndex, pointIndex, x, y)); } int EXPORT_PY_API curv_setvalue(Handle ph, int curveIndex, int pointIndex, double x, double y) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setcurvevalue(pr->project, curveIndex, pointIndex, x, y)); + 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) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getcurve(pr->project, curveIndex, id, nValues, xValues, yValues)); + return set_error(pr->error, EN_getcurve(pr->project, curveIndex, id, nValues, xValues, yValues)); } int EXPORT_PY_API curv_set(Handle ph, int index, double *x, double *y, int len) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setcurve(pr->project, index, x, y, len)); + return set_error(pr->error, EN_setcurve(pr->project, index, x, y, len)); } @@ -642,25 +642,25 @@ 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) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_addcontrol(pr->project, type, linkIndex, setting, nodeIndex, level, index)); + return set_error(pr->error, EN_addcontrol(pr->project, type, linkIndex, setting, nodeIndex, level, index)); } int EXPORT_PY_API scntl_delete(Handle ph, int index) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_deletecontrol(pr->project, index)); + return set_error(pr->error, EN_deletecontrol(pr->project, index)); } int EXPORT_PY_API scntl_get(Handle ph, int controlIndex, int *controlType, int *linkIndex, double *setting, int *nodeIndex, double *level) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getcontrol(pr->project, controlIndex, controlType, linkIndex, setting, nodeIndex, level)); + return set_error(pr->error, EN_getcontrol(pr->project, controlIndex, controlType, linkIndex, setting, nodeIndex, level)); } int EXPORT_PY_API scntl_set(Handle ph, int cindex, int ctype, int lindex, double setting, int nindex, double level) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setcontrol(pr->project, cindex, ctype, lindex, setting, nindex, level)); + return set_error(pr->error, EN_setcontrol(pr->project, cindex, ctype, lindex, setting, nindex, level)); } @@ -669,85 +669,85 @@ int EXPORT_PY_API scntl_set(Handle ph, int cindex, int ctype, int lindex, double int EXPORT_PY_API rcntl_add(Handle ph, char *rule) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_addrule(pr->project, rule)); + return set_error(pr->error, EN_addrule(pr->project, rule)); } int EXPORT_PY_API rcntl_delete(Handle ph, int index) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_deleterule(pr->project, index)); + return set_error(pr->error, EN_deleterule(pr->project, index)); } int EXPORT_PY_API rcntl_get(Handle ph, int index, int *nPremises, int *nThenActions, int *nElseActions, double *priority) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getrule(pr->project, index, nPremises, nThenActions, nElseActions, priority)); + return set_error(pr->error, EN_getrule(pr->project, index, nPremises, nThenActions, nElseActions, priority)); } int EXPORT_PY_API rcntl_getid(Handle ph, int index, char *id) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getruleID(pr->project, index, id)); + return set_error(pr->error, EN_getruleID(pr->project, index, id)); } int EXPORT_PY_API rcntl_getpremise(Handle ph, int ruleIndex, int premiseIndex, int *logop, int *object, int *objIndex, int *variable, int *relop, int *status, double *value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getpremise(pr->project, ruleIndex, premiseIndex, logop, object, objIndex, variable, relop, status, value)); + return set_error(pr->error, EN_getpremise(pr->project, ruleIndex, premiseIndex, logop, object, objIndex, variable, relop, status, value)); } int EXPORT_PY_API rcntl_setpremise(Handle ph, int ruleIndex, int premiseIndex, int logop, int object, int objIndex, int variable, int relop, int status, double value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setpremise(pr->project, ruleIndex, premiseIndex, logop, object, objIndex, variable, relop, status, value)); + return set_error(pr->error, EN_setpremise(pr->project, ruleIndex, premiseIndex, logop, object, objIndex, variable, relop, status, value)); } int EXPORT_PY_API rcntl_setpremiseindex(Handle ph, int ruleIndex, int premiseIndex, int objIndex) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setpremiseindex(pr->project, ruleIndex, premiseIndex, objIndex)); + return set_error(pr->error, EN_setpremiseindex(pr->project, ruleIndex, premiseIndex, objIndex)); } int EXPORT_PY_API rcntl_setpremisestatus(Handle ph, int ruleIndex, int premiseIndex, int status) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setpremisestatus(pr->project, ruleIndex, premiseIndex, status)); + return set_error(pr->error, EN_setpremisestatus(pr->project, ruleIndex, premiseIndex, status)); } int EXPORT_PY_API rcntl_setpremisevalue(Handle ph, int ruleIndex, int premiseIndex, double value) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setpremisevalue(pr->project, ruleIndex, premiseIndex, value)); + return set_error(pr->error, EN_setpremisevalue(pr->project, ruleIndex, premiseIndex, value)); } int EXPORT_PY_API rcntl_getthenaction(Handle ph, int ruleIndex, int actionIndex, int *linkIndex, int *status, double *setting) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getthenaction(pr->project, ruleIndex, actionIndex, linkIndex, status, setting)); + return set_error(pr->error, EN_getthenaction(pr->project, ruleIndex, actionIndex, linkIndex, status, setting)); } int EXPORT_PY_API rcntl_setthenaction(Handle ph, int ruleIndex, int actionIndex, int linkIndex, int status, double setting) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setthenaction(pr->project, ruleIndex, actionIndex, linkIndex, status, setting)); + return set_error(pr->error, EN_setthenaction(pr->project, ruleIndex, actionIndex, linkIndex, status, setting)); } int EXPORT_PY_API rcntl_getelseaction(Handle ph, int ruleIndex, int actionIndex, int *linkIndex, int *status, double *setting) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_getelseaction(pr->project, ruleIndex, actionIndex, linkIndex, status, setting)); + return set_error(pr->error, EN_getelseaction(pr->project, ruleIndex, actionIndex, linkIndex, status, setting)); } int EXPORT_PY_API rcntl_setelseaction(Handle ph, int ruleIndex, int actionIndex, int linkIndex, int status, double setting) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setelseaction(pr->project, ruleIndex, actionIndex, linkIndex, status, setting)); + return set_error(pr->error, EN_setelseaction(pr->project, ruleIndex, actionIndex, linkIndex, status, setting)); } int EXPORT_PY_API rcntl_setrulepriority(Handle ph, int index, double priority) { handle_t *pr = (handle_t *)ph; - return error_set(pr->error, EN_setrulepriority(pr->project, index, priority)); + return set_error(pr->error, EN_setrulepriority(pr->project, index, priority)); } @@ -756,7 +756,7 @@ int EXPORT_PY_API rcntl_setrulepriority(Handle ph, int index, double priority) void EXPORT_PY_API err_clear(Handle ph) { handle_t *pr = (handle_t *)ph; - error_clear(pr->error); + clear_error(pr->error); } int EXPORT_PY_API err_check(Handle ph, char** msg_buffer) @@ -767,7 +767,7 @@ int EXPORT_PY_API err_check(Handle ph, char** msg_buffer) // { handle_t *pr = (handle_t *)ph; - return error_check(pr->error, msg_buffer); + return check_error(pr->error, msg_buffer); } int EXPORT_PY_API toolkit_getversion(int *version) From 1a01b46187dea607e51b86c27e1dd81c6a1a3902 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 26 Mar 2019 14:57:41 -0400 Subject: [PATCH 02/49] Adding build configuration Setting up debug build so we can better monitor memory leaks --- appveyor.yml | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 1d3f5ae..99b2d8d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,14 +20,23 @@ environment: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 GENERATOR: "Visual Studio 15 2017" GROUP: "SUPPORTED" + BUILD_CONFIG: "Release" BOOST_ROOT: "C:/Libraries/boost_1_67_0" - PLATFORM: "win32" REF_BUILD_ID: "220dev5" # New build on Visual Studio 15 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 GENERATOR: "Visual Studio 15 2017 Win64" GROUP: "EXPERIMENTAL" + BUILD_CONFIG: "Release" + BOOST_ROOT: "C:/Libraries/boost_1_67_0" + PLATFORM: "win64" + REF_BUILD_ID: "381_2" + # adding debug configuration so we can monitor memory leaks + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + GENERATOR: "Visual Studio 15 2017 Win64" + GROUP: "EXPERIMENTAL" + BUILD_CONFIG: "Debug" BOOST_ROOT: "C:/Libraries/boost_1_67_0" PLATFORM: "win64" REF_BUILD_ID: "381_2" @@ -60,7 +69,7 @@ before_build: # run custom build script build_script: - - cmake --build . --config Release + - cmake --build . --config %BUILD_CONFIG% before_test: - cd %EPANET_HOME% @@ -70,11 +79,12 @@ before_test: test_script: # run unit tests - cd %BUILD_HOME%\tests - - ctest -C Release --output-on-failure + - ctest -C %BUILD_CONFIG% --output-on-failure # run regression tests - - cd %EPANET_HOME% - - tools\run-nrtest.cmd %REF_BUILD_ID% %SUT_BUILD_ID% - + - IF "%BUILD_CONFIG%" == "Release" ( + cd %EPANET_HOME% + tools\run-nrtest.cmd %REF_BUILD_ID% %SUT_BUILD_ID% + ) on_success: - cd %TEST_HOME%\benchmark - appveyor PushArtifact receipt.json From 44bea587c09fed996b66eb334e47275a16925be0 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 26 Mar 2019 15:18:54 -0400 Subject: [PATCH 03/49] Fixing bug in appveyor.yml --- appveyor.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 99b2d8d..1ba3beb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -82,8 +82,7 @@ test_script: - ctest -C %BUILD_CONFIG% --output-on-failure # run regression tests - IF "%BUILD_CONFIG%" == "Release" ( - cd %EPANET_HOME% - tools\run-nrtest.cmd %REF_BUILD_ID% %SUT_BUILD_ID% + cd %EPANET_HOME% & tools\run-nrtest.cmd %REF_BUILD_ID% %SUT_BUILD_ID% ) on_success: - cd %TEST_HOME%\benchmark From d4d876da718fa35d43658279f3ca0d506254ae58 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 26 Mar 2019 15:51:09 -0400 Subject: [PATCH 04/49] Update appveyor.yml Adding conditions to post test tasks --- appveyor.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 1ba3beb..dc80e1c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -81,15 +81,21 @@ test_script: - cd %BUILD_HOME%\tests - ctest -C %BUILD_CONFIG% --output-on-failure # run regression tests + - cd %EPANET_HOME% - IF "%BUILD_CONFIG%" == "Release" ( - cd %EPANET_HOME% & tools\run-nrtest.cmd %REF_BUILD_ID% %SUT_BUILD_ID% + tools\run-nrtest.cmd %REF_BUILD_ID% %SUT_BUILD_ID% ) on_success: - cd %TEST_HOME%\benchmark - - appveyor PushArtifact receipt.json + - IF "%BUILD_CONFIG%" == "Release" ( + appveyor PushArtifact receipt.json + ) on_failure: - cd %TEST_HOME%\benchmark # zip up the SUT benchmarks - - 7z a benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip .\epanet-%SUT_BUILD_ID% - - appveyor PushArtifact benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip + - IF "%BUILD_CONFIG%" == "Release" ( + 7z a benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip .\epanet-%SUT_BUILD_ID% & + appveyor PushArtifact benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip + ) + From 8574f522563632264fee5164cd00668eff8268ba Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 26 Mar 2019 16:48:08 -0400 Subject: [PATCH 05/49] Fixing indentation --- appveyor.yml | 1 - src/epanet_py.c | 42 +++++++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index dc80e1c..22c1acf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -98,4 +98,3 @@ on_failure: 7z a benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip .\epanet-%SUT_BUILD_ID% & appveyor PushArtifact benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip ) - diff --git a/src/epanet_py.c b/src/epanet_py.c index fb681aa..4c16cbf 100644 --- a/src/epanet_py.c +++ b/src/epanet_py.c @@ -786,25 +786,29 @@ void error_lookup(int errcode, char *dest_msg, int dest_len) { char *msg = NULL; - switch (errcode) - { - case 1: msg = WARN1; - break; - case 2: msg = WARN2; - break; - case 3: msg = WARN3; - break; - case 4: msg = WARN4; - break; - case 5: msg = WARN5; - break; - case 6: msg = WARN6; - break; - default: - { - char new_msg[MAXMSG + 1]; - msg = geterrmsg(errcode, new_msg); - } + switch (errcode) { + case 1: + msg = WARN1; + break; + case 2: + msg = WARN2; + break; + case 3: + msg = WARN3; + break; + case 4: + msg = WARN4; + break; + case 5: + msg = WARN5; + break; + case 6: + msg = WARN6; + break; + default: { + char new_msg[MAXMSG + 1]; + msg = geterrmsg(errcode, new_msg); + } } strncpy(dest_msg, msg, dest_len); } From 1b167b5caf01ba4563fa1cc71bc355a0bf664a1e Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 28 Mar 2019 09:26:26 -0400 Subject: [PATCH 06/49] Cleaning up include statements Removing inclusion of malloc.h. Adding crtdbg.h --- run/main.c | 1 + src/epanet.c | 45 +++++++++++++++-------------- src/epanet2.c | 10 +++++-- src/epanet_py.c | 1 + src/hash.c | 5 +--- src/hydcoeffs.c | 6 +--- src/hydraul.c | 6 +--- src/hydsolver.c | 6 +--- src/hydstatus.c | 1 + src/inpfile.c | 4 --- src/input1.c | 28 ++++++++++-------- src/input2.c | 63 +++++++++++++++++++++-------------------- src/input3.c | 11 ++++--- src/mempool.c | 4 +-- src/output.c | 6 +--- src/project.c | 12 +++++--- src/quality.c | 6 +--- src/qualreact.c | 1 + src/qualroute.c | 7 ++--- src/report.c | 7 ++--- src/rules.c | 6 +--- src/smatrix.c | 7 +---- src/types.h | 4 ++- src/util/errormanager.c | 6 ---- tests/CMakeLists.txt | 23 ++++++++------- tests/test_analysis.cpp | 1 - tests/test_project.cpp | 50 +++++++++++++++++++------------- tests/test_toolkit.hpp | 6 ++++ 28 files changed, 164 insertions(+), 169 deletions(-) diff --git a/run/main.c b/run/main.c index 793fffa..ea0a91c 100644 --- a/run/main.c +++ b/run/main.c @@ -12,6 +12,7 @@ */ #include + #include "epanet2.h" void writeConsole(char *s) diff --git a/src/epanet.c b/src/epanet.c index 29462bc..a6df228 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -11,12 +11,17 @@ ****************************************************************************** */ -#include -#include -#include -#ifndef __APPLE__ -#include +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include #endif + +#include +#include + #include #include @@ -216,26 +221,24 @@ int DLLEXPORT EN_open(EN_Project p, const char *inpFile, const char *rptFile, ERRCODE(netsize(p)); ERRCODE(allocdata(p)); - // Read input data - ERRCODE(getdata(p)); + if (!errcode) { + // Read input data + ERRCODE(getdata(p)); - // Close input file - if (p->parser.InFile != NULL) - { + // Close input file + if (p->parser.InFile != NULL) { fclose(p->parser.InFile); p->parser.InFile = NULL; - } + } - // Free temporary linked lists used for Patterns & Curves - freeTmplist(p->parser.Patlist); - freeTmplist(p->parser.Curvelist); + // 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)); + // If using previously saved hydraulics file then open it + if (p->outfile.Hydflag == USE) ERRCODE(openhydfile(p)); - // Write input summary to report file - if (!errcode) - { + // Write input summary to report file if (p->report.Summaryflag) writesummary(p); writetime(p, FMT104); p->Openflag = TRUE; @@ -279,7 +282,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 +843,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; } diff --git a/src/epanet2.c b/src/epanet2.c index 935d6c4..3d11608 100644 --- a/src/epanet2.c +++ b/src/epanet2.c @@ -10,11 +10,15 @@ Last Updated: 03/17/2019 ****************************************************************************** */ -#ifndef __APPLE__ -#include + +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include #else -#include + #include #endif + #include #include "types.h" diff --git a/src/epanet_py.c b/src/epanet_py.c index 4c16cbf..e84fdc9 100644 --- a/src/epanet_py.c +++ b/src/epanet_py.c @@ -26,6 +26,7 @@ typedef struct { Project *project; error_handle_t *error; }handle_t; + // Extern functions extern char *geterrmsg(int, char *); // Local functions diff --git a/src/hash.c b/src/hash.c index 95ac8dd..c3f91e2 100755 --- a/src/hash.c +++ b/src/hash.c @@ -11,12 +11,9 @@ ****************************************************************************** */ -#ifndef __APPLE__ -#include -#else #include -#endif #include + #include "hash.h" #define HASHTABLEMAXSIZE 128000 diff --git a/src/hydcoeffs.c b/src/hydcoeffs.c index b6c002c..4b3583d 100644 --- a/src/hydcoeffs.c +++ b/src/hydcoeffs.c @@ -11,13 +11,9 @@ ****************************************************************************** */ +#include #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif #include #include "types.h" diff --git a/src/hydraul.c b/src/hydraul.c index 703f7b7..c442ac6 100755 --- a/src/hydraul.c +++ b/src/hydraul.c @@ -11,13 +11,9 @@ ****************************************************************************** */ +#include #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif #include #include "types.h" diff --git a/src/hydsolver.c b/src/hydsolver.c index 3c0694a..90c93e1 100644 --- a/src/hydsolver.c +++ b/src/hydsolver.c @@ -12,13 +12,9 @@ ****************************************************************************** */ +#include #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif #include #include "types.h" diff --git a/src/hydstatus.c b/src/hydstatus.c index f7edb6b..5905337 100644 --- a/src/hydstatus.c +++ b/src/hydstatus.c @@ -12,6 +12,7 @@ Last Updated: 11/27/2018 */ #include + #include "types.h" #include "funcs.h" diff --git a/src/inpfile.c b/src/inpfile.c index 45b5aab..994830a 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -13,11 +13,7 @@ Last Updated: 03/17/2019 #include #include -#ifndef __APPLE__ -#include -#else #include -#endif #include #include "types.h" diff --git a/src/input1.c b/src/input1.c index fe606d9..4cafa13 100644 --- a/src/input1.c +++ b/src/input1.c @@ -3,26 +3,30 @@ 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 Last Updated: 03/17/2019 ****************************************************************************** */ +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include -#include #include -#ifndef __APPLE__ -#include -#endif +#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 +60,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 +106,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 +357,7 @@ int inittanks(Project *pr) */ { Network *net = &pr->network; - + int i, j, n = 0; double a; int errcode = 0, levelerr; @@ -546,7 +550,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 +648,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 +657,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 2820e35..e4d2d85 100644 --- a/src/input2.c +++ b/src/input2.c @@ -10,13 +10,16 @@ License: see LICENSE Last Updated: 03/17/2019 ****************************************************************************** */ +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include -#include #include -#ifndef __APPLE__ -#include -#endif #include #include "types.h" @@ -56,7 +59,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 @@ -147,7 +150,7 @@ int readdata(Project *pr) inperr, errsum; // Error code & total error count // Allocate input buffer - parser->X = (double *)calloc(MAXTOKS, sizeof(double)); + parser->X = (double *)calloc(MAXTOKS + 1, sizeof(double)); ERRCODE(MEMCHECK(parser->X)); if (errcode) return errcode; @@ -175,7 +178,7 @@ int readdata(Project *pr) while (fgets(line, MAXLINE, parser->InFile) != NULL) { // Make copy of line and scan for tokens - strcpy(wline, line); + strncpy(wline, line, MAXLINE); parser->Ntokens = gettokens(wline, parser->Tok, MAXTOKS, parser->Comment); // Skip blank lines and those filled with a comment @@ -246,10 +249,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 +400,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 +410,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 +421,7 @@ int updatepumpparams(Project *pr, int pumpindex) q2 = curve->X[2]; h2 = curve->Y[2]; } - + // Custom pump curve else { @@ -431,7 +434,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 +464,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 +590,7 @@ int unlinked(Project *pr) Network *net = &pr->network; int *marked; int i, err, errcode; - + errcode = 0; err = 0; @@ -596,19 +599,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 +641,7 @@ int getpatterns(Project *pr) SFloatlist *f; STmplist *tmppattern; Spattern *pattern; - + // Start at head of the list of patterns tmppattern = parser->Patlist; @@ -696,7 +699,7 @@ int getcurves(Project *pr) { Network *net = &pr->network; Parser *parser = &pr->parser; - + int i, j; double x; char errmsg[MAXMSG+1]; @@ -827,14 +830,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) { @@ -868,7 +871,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 @@ -876,7 +879,7 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment) } } return n; -} +} double hour(char *time, char *units) /* @@ -914,7 +917,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 @@ -933,7 +936,7 @@ double hour(char *time, char *units) else return (y[0] + 12.0); } return -1.0; -} +} int getfloat(char *s, double *y) /* @@ -979,14 +982,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..d00a6e9 100644 --- a/src/input3.c +++ b/src/input3.c @@ -10,13 +10,16 @@ License: see LICENSE Last Updated: 03/17/2019 ****************************************************************************** */ +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif #include -#include #include -#ifndef __APPLE__ -#include -#endif #include #include "types.h" diff --git a/src/mempool.c b/src/mempool.c index 55552ed..871b4c8 100755 --- a/src/mempool.c +++ b/src/mempool.c @@ -15,9 +15,7 @@ */ #include -#ifndef __APPLE__ -#include -#endif + #include "mempool.h" /* diff --git a/src/output.c b/src/output.c index fd92077..d86fe50 100644 --- a/src/output.c +++ b/src/output.c @@ -11,13 +11,9 @@ Last Updated: 11/27/2018 ****************************************************************************** */ +#include #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif #include #include "types.h" diff --git a/src/project.c b/src/project.c index fd4cb8d..8355588 100644 --- a/src/project.c +++ b/src/project.c @@ -11,14 +11,18 @@ ****************************************************************************** */ -#include -#include -#ifndef __APPLE__ -#include +#ifdef _DEBUG +#define _CRTDBG_MAP_ALLOC +#include +#include #else #include #endif +#include +#include + + //*** For the Windows SDK _tempnam function ***// #ifdef _WIN32 #include diff --git a/src/quality.c b/src/quality.c index de27f63..06e1997 100644 --- a/src/quality.c +++ b/src/quality.c @@ -11,13 +11,9 @@ Last Updated: 11/27/2018 ****************************************************************************** */ +#include #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif #include #include "mempool.h" diff --git a/src/qualreact.c b/src/qualreact.c index 0805a21..0afac47 100644 --- a/src/qualreact.c +++ b/src/qualreact.c @@ -13,6 +13,7 @@ Last Updated: 11/27/2018 #include #include + #include "types.h" // Exported functions diff --git a/src/qualroute.c b/src/qualroute.c index 72bb66f..03e3545 100644 --- a/src/qualroute.c +++ b/src/qualroute.c @@ -11,13 +11,10 @@ Last Updated: 11/27/2018 ****************************************************************************** */ -#include -#ifndef __APPLE__ -#include -#else #include -#endif +#include #include + #include "mempool.h" #include "types.h" diff --git a/src/report.c b/src/report.c index 5605ffb..dd4ff3d 100644 --- a/src/report.c +++ b/src/report.c @@ -11,13 +11,10 @@ ****************************************************************************** */ +#include #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif + #ifdef _WIN32 #define snprintf _snprintf diff --git a/src/rules.c b/src/rules.c index 7e9945f..eee5568 100644 --- a/src/rules.c +++ b/src/rules.c @@ -11,13 +11,9 @@ ****************************************************************************** */ +#include #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..3446384 100755 --- a/src/smatrix.c +++ b/src/smatrix.c @@ -18,16 +18,11 @@ linsolve() -- called from netsolve() in HYDRAUL.C */ +#include #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif #include #include - #include //For optional timer macros #include "text.h" diff --git a/src/types.h b/src/types.h index 4329414..38d6607 100755 --- a/src/types.h +++ b/src/types.h @@ -14,9 +14,11 @@ #ifndef TYPES_H #define TYPES_H -#include "hash.h" #include +#include "hash.h" + + /* ------------------------------------------- Definition of 4-byte integers & reals diff --git a/src/util/errormanager.c b/src/util/errormanager.c index 5a9876c..b674fe6 100644 --- a/src/util/errormanager.c +++ b/src/util/errormanager.c @@ -10,13 +10,7 @@ // US EPA - ORD/NRMRL //----------------------------------------------------------------------------- -//#ifdef _WIN32 -//#define _CRTDBG_MAP_ALLOC -//#include -//#include -//#else #include -//#endif #include #include "errormanager.h" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d16c376..ffb73b4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,18 +19,19 @@ endif(UNIX) set(toolkit_test_srcs test_toolkit.cpp test_project.cpp - test_hydraulics.cpp - test_quality.cpp - test_report.cpp - test_analysis.cpp - test_node.cpp - test_demand.cpp - test_link.cpp +# test_hydraulics.cpp +# test_quality.cpp +# test_report.cpp +# test_analysis.cpp +# test_node.cpp +# test_demand.cpp +# test_link.cpp # test_pump.cpp - test_pattern.cpp - test_curve.cpp - test_control.cpp - test_net_builder.cpp) +# test_pattern.cpp +# test_curve.cpp +# test_control.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..917b523 100644 --- a/tests/test_analysis.cpp +++ b/tests/test_analysis.cpp @@ -11,7 +11,6 @@ ****************************************************************************** */ -//#define BOOST_ALL_DYN_LINK #include #include "test_toolkit.hpp" diff --git a/tests/test_project.cpp b/tests/test_project.cpp index 6f0b68c..6ae1143 100644 --- a/tests/test_project.cpp +++ b/tests/test_project.cpp @@ -56,35 +56,47 @@ BOOST_AUTO_TEST_CASE(test_save) { int error; - EN_Project ph_save; + EN_Project ph = NULL; - EN_createproject(&ph_save); - error = EN_open(ph_save, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT); - BOOST_REQUIRE(error == 0); - - error = EN_saveinpfile(ph_save, "test_reopen.inp"); - BOOST_REQUIRE(error == 0); - - BOOST_CHECK(boost::filesystem::exists("test_reopen.inp") == true); - - error = EN_close(ph_save); + error = EN_createproject(&ph); BOOST_REQUIRE(error == 0); - EN_deleteproject(&ph_save); + + error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT); + BOOST_REQUIRE(error == 0); + + error = EN_saveinpfile(ph, DATA_PATH_TMP); + BOOST_REQUIRE(error == 0); + + BOOST_CHECK(boost::filesystem::exists(DATA_PATH_TMP) == true); + + error = EN_close(ph); + BOOST_REQUIRE(error == 0); + + error = EN_deleteproject(&ph); + BOOST_REQUIRE(error == 0); + + BOOST_CHECK(ph == NULL); } BOOST_AUTO_TEST_CASE(test_reopen, * boost::unit_test::depends_on("test_project/test_save")) { int error; - EN_Project ph_reopen; + EN_Project ph = NULL; - EN_createproject(&ph_reopen); - error = EN_open(ph_reopen, "test_reopen.inp", DATA_PATH_RPT, DATA_PATH_OUT); - BOOST_REQUIRE(error == 0); + error = EN_createproject(&ph); + BOOST_REQUIRE(error == 0); - error = EN_close(ph_reopen); - BOOST_REQUIRE(error == 0); - EN_deleteproject(&ph_reopen); + error = EN_open(ph, DATA_PATH_TMP, DATA_PATH_RPT, DATA_PATH_OUT); + BOOST_REQUIRE(error == 0); + + error = EN_close(ph); + BOOST_REQUIRE(error == 0); + + EN_deleteproject(&ph); + BOOST_REQUIRE(error == 0); + + BOOST_CHECK(ph == NULL); } BOOST_AUTO_TEST_CASE(test_run) diff --git a/tests/test_toolkit.hpp b/tests/test_toolkit.hpp index 03ac664..f0da4e7 100644 --- a/tests/test_toolkit.hpp +++ b/tests/test_toolkit.hpp @@ -14,6 +14,12 @@ #ifndef TEST_TOOLKIT_HPP #define TEST_TOOLKIT_HPP +// MSVC ONLY +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#endif #include "epanet2_2.h" From 727ede3aba8ce7831d649043ef1360d5d718b2d0 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 28 Mar 2019 17:28:02 -0400 Subject: [PATCH 07/49] Initial commit filemanager --- src/util/filemanager.c | 89 ++++++++++++++++++++++++++++++++++++++++++ src/util/filemanager.h | 44 +++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 src/util/filemanager.c create mode 100644 src/util/filemanager.h diff --git a/src/util/filemanager.c b/src/util/filemanager.c new file mode 100644 index 0000000..f2fcc8f --- /dev/null +++ b/src/util/filemanager.c @@ -0,0 +1,89 @@ + + +#include +#include + +#include "filemanager.h" + + +// local (private) functions +int _get_temp_filename(char *tempname); + + +file_handle_t *create_file_manager(const char *filename, const char *file_mode) { + + file_handle_t *file_handle; + file_handle = (file_handle_t*)calloc(1, sizeof(file_handle_t)); + + if (filename == NULL) + _get_temp_filename(file_handle->filename); + else + strncpy(file_handle->filename, filename, FILE_MAXNAME); + + file_handle->file = NULL; + strncpy(file_handle->mode, file_mode, FILE_MAXMODE); + + return file_handle; +} + +int delete_file_manager(file_handle_t *file_handle) { + free(file_handle); +} + + +int open_file(file_handle_t *file_handle) { + int error = 0; + + if ((file_handle->file = fopen(file_handle->filename, file_handle->mode)) == NULL) + error = -1; + + return error; +} + +FILE *get_file(file_handle_t *file_handle) { + return file_handle->file; +} + +int close_file(file_handle_t *file_handle) { + int error = 0; + + if (file_handle->file != NULL) { + error = fclose(file_handle->file); + file_handle->file = NULL; + } + return error; +} + +int remove_file(file_handle_t *file_handle) { + return remove(file_handle->filename); +} + + +int _get_temp_filename(char *tempname) { + int error = 0 +#ifdef _WIN32 + char* name = NULL; + + // --- use Windows _tempnam function to get a pointer to an + // unused file name that begins with "en" + if ((name = _tempnam(NULL, "en") == NULL) { + error = -1; + return error; + } + else if (strlen(name) < FILE_MAXNAME) + strncpy(tempname, name, FILE_MAXNAME); + else + tempname = NULL; + + // --- free the pointer returned by _tempnam + if (name) + free(name); + + // --- for non-Windows systems: +#else + // --- use system function mkstemp() to create a temporary file name + strncpy(tempname, "enXXXXXX", 8); + error = mkstemp(tempname); +#endif + return error; +} diff --git a/src/util/filemanager.h b/src/util/filemanager.h new file mode 100644 index 0000000..24c8b55 --- /dev/null +++ b/src/util/filemanager.h @@ -0,0 +1,44 @@ + + + + +#ifndef FILEMANAGER_H_ +#define FILEMANAGER_H_ + + +#include + +#define FILE_MAXNAME 259 +#define FILE_MAXMODE 3 + + +#if defined(__cplusplus) +extern "C" { +#endif + + +typedef struct file_s { + char filename[FILE_MAXNAME + 1], + FILE *file; + char mode[FILE_MAXMODE + 1]; +} file_handle_t; + + +file_handle_t *create_file_manager(const char *filename, const char *file_mode); + +int delete_file_manager(file_handle_t *file_handle); + + +int open_file(file_handle_t *file_handle); + +FILE *get_file(file_handle_t *file_handle); + +int close_file(file_handle_t *file_handle); + + + +#if defined(__cplusplus) +} +#endif + +#endif /* FILEMANAGER_H_ */ From d1df792c779d29dedc01d799205c7baa7dc033ea Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 28 Mar 2019 17:39:05 -0400 Subject: [PATCH 08/49] Adding remove_file() --- src/util/filemanager.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/filemanager.h b/src/util/filemanager.h index 24c8b55..4daf04e 100644 --- a/src/util/filemanager.h +++ b/src/util/filemanager.h @@ -35,6 +35,7 @@ FILE *get_file(file_handle_t *file_handle); int close_file(file_handle_t *file_handle); +int remove_file(file_handle_t *file_handle); #if defined(__cplusplus) From 69da9a4997dd86e35ae6c4295c7e28b40493b17b Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 29 Mar 2019 17:04:55 -0400 Subject: [PATCH 09/49] Work in progress --- src/util/filemanager.h | 2 +- tests/util/test_filemanager.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 tests/util/test_filemanager.cpp diff --git a/src/util/filemanager.h b/src/util/filemanager.h index 4daf04e..c9961b8 100644 --- a/src/util/filemanager.h +++ b/src/util/filemanager.h @@ -20,7 +20,7 @@ extern "C" { typedef struct file_s { char filename[FILE_MAXNAME + 1], FILE *file; - char mode[FILE_MAXMODE + 1]; + char mode[FILE_MAXMODE + 1]; } file_handle_t; diff --git a/tests/util/test_filemanager.cpp b/tests/util/test_filemanager.cpp new file mode 100644 index 0000000..b9d830e --- /dev/null +++ b/tests/util/test_filemanager.cpp @@ -0,0 +1,7 @@ + + +#define BOOST_TEST_MODULE filemanager + +#include + +#include "util/filemanager.h" From 23ac179ec120653f7b26ba9118805124a11f8fc9 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Mon, 1 Apr 2019 15:03:02 -0400 Subject: [PATCH 10/49] Implementing filemanager Implementing and testing filemanager and upgrading epanet_output library to use it. --- src/outfile/CMakeLists.txt | 3 +- src/outfile/src/epanet_output.c | 180 +++++++++++-------------------- src/util/filemanager.c | 104 ++++++++++++++---- src/util/filemanager.h | 27 +++-- tests/util/CMakeLists.txt | 6 ++ tests/util/test_errormanager.cpp | 2 +- tests/util/test_filemanager.cpp | 59 ++++++++++ 7 files changed, 231 insertions(+), 150 deletions(-) diff --git a/src/outfile/CMakeLists.txt b/src/outfile/CMakeLists.txt index cdd2f0f..79a8ae1 100644 --- a/src/outfile/CMakeLists.txt +++ b/src/outfile/CMakeLists.txt @@ -21,7 +21,8 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) # configure file groups set(EPANET_OUT_SOURCES src/epanet_output.c - ../util/errormanager.c) + ../util/errormanager.c + ../util/filemanager.c) # the binary output file API diff --git a/src/outfile/src/epanet_output.c b/src/outfile/src/epanet_output.c index dcbcd75..6e0c63d 100644 --- a/src/outfile/src/epanet_output.c +++ b/src/outfile/src/epanet_output.c @@ -40,18 +40,13 @@ #include #include "util/errormanager.h" +#include "util/filemanager.h" #include "epanet_output.h" #include "messages.h" // NOTE: These depend on machine data model and may change when porting -// F_OFF Must be a 8 byte / 64 bit integer for large file support -#ifdef _WIN32 // Windows (32-bit and 64-bit) -#define F_OFF __int64 -#else // Other platforms -#define F_OFF off_t -#endif #define INT4 int // Must be a 4 byte / 32 bit integer type #define REAL4 float // Must be a 4 byte / 32 bit real type #define WORDSIZE 4 // Memory alignment 4 byte word size for both int and real @@ -71,33 +66,28 @@ // Typedefs for opaque pointer typedef struct data_s { - char name[MAXFNAME+1]; // file path/name - FILE* file; // FILE structure pointer INT4 nodeCount, tankCount, linkCount, pumpCount, valveCount, nPeriods; F_OFF outputStartPos; // starting file position of output data F_OFF bytesPerPeriod; // bytes saved per simulation time period - error_handle_t* error_handle; + error_handle_t *error_handle; + file_handle_t *file_handle; } data_t; //----------------------------------------------------------------------------- // Local functions //----------------------------------------------------------------------------- -void errorLookup(int errcode, char* errmsg, int length); -int validateFile(ENR_Handle); -float getNodeValue(ENR_Handle, int, int, int); -float getLinkValue(ENR_Handle, int, int, int); +void errorLookup(int errcode, char* errmsg, int length); +int validateFile(ENR_Handle); +float getNodeValue(ENR_Handle, int, int, int); +float getLinkValue(ENR_Handle, int, int, int); -int _fopen(FILE **f, const char *name, const char *mode); -int _fseek(FILE* stream, F_OFF offset, int whence); -F_OFF _ftell(FILE* stream); - -float* newFloatArray(int n); -int* newIntArray(int n); -char* newCharArray(int n); +float *newFloatArray(int n); +int *newIntArray(int n); +char *newCharArray(int n); -int EXPORT_OUT_API ENR_init(ENR_Handle* dp_handle) +int EXPORT_OUT_API ENR_init(ENR_Handle *dp_handle) // Purpose: Initialized pointer for the opaque ENR_Handle. // // Returns: Error code 0 on success, -1 on failure @@ -114,6 +104,7 @@ int EXPORT_OUT_API ENR_init(ENR_Handle* dp_handle) if (p_data != NULL){ p_data->error_handle = create_error_manager(&errorLookup); + p_data->file_handle = create_file_manager(); *dp_handle = p_data; } else @@ -123,7 +114,7 @@ int EXPORT_OUT_API ENR_init(ENR_Handle* dp_handle) return errorcode; } -int EXPORT_OUT_API ENR_close(ENR_Handle* p_handle) +int EXPORT_OUT_API ENR_close(ENR_Handle *p_handle) /*------------------------------------------------------------------------ ** Input: *p_handle = pointer to ENR_Handle struct ** @@ -143,13 +134,16 @@ int EXPORT_OUT_API ENR_close(ENR_Handle* p_handle) p_data = (data_t*)(*p_handle); - if (p_data == NULL || p_data->file == NULL) + if (p_data == NULL || p_data->file_handle == NULL) errorcode = -1; else { + close_file(p_data->file_handle); + delete_error_manager(p_data->error_handle); - fclose(p_data->file); + delete_file_manager(p_data->file_handle); + free(p_data); *p_handle = NULL; @@ -178,23 +172,22 @@ int EXPORT_OUT_API ENR_open(ENR_Handle p_handle, const char* path) if (p_data == NULL) return -1; else { - strncpy(p_data->name, path, MAXFNAME); // Attempt to open binary output file for reading only - if ((_fopen(&(p_data->file), path, "rb")) != 0) errorcode = 434; + if ((open_file(p_data->file_handle, path, "rb")) != 0) + errorcode = 434; // Perform checks to insure the file is valid else if ((err = validateFile(p_data)) != 0) errorcode = err; // If a warning is encountered read file header if (errorcode < 400 ) { - // read network size - fseek(p_data->file, 2*WORDSIZE, SEEK_SET); - fread(&(p_data->nodeCount), WORDSIZE, 1, p_data->file); - fread(&(p_data->tankCount), WORDSIZE, 1, p_data->file); - fread(&(p_data->linkCount), WORDSIZE, 1, p_data->file); - fread(&(p_data->pumpCount), WORDSIZE, 1, p_data->file); - fread(&(p_data->valveCount), WORDSIZE, 1, p_data->file); + seek_file(p_data->file_handle, 2*WORDSIZE, SEEK_SET); + read_file(&(p_data->nodeCount), WORDSIZE, 1, p_data->file_handle); + read_file(&(p_data->tankCount), WORDSIZE, 1, p_data->file_handle); + read_file(&(p_data->linkCount), WORDSIZE, 1, p_data->file_handle); + read_file(&(p_data->pumpCount), WORDSIZE, 1, p_data->file_handle); + read_file(&(p_data->valveCount), WORDSIZE, 1, p_data->file_handle); // Compute positions and offsets for retrieving data // fixed portion of header + title section + filenames + chem names @@ -240,8 +233,8 @@ int EXPORT_OUT_API ENR_getVersion(ENR_Handle p_handle, int* version) if (p_data == NULL) return -1; else { - fseek(p_data->file, 1*WORDSIZE, SEEK_SET); - if (fread(version, WORDSIZE, 1, p_data->file) != 1) + seek_file(p_data->file_handle, 1*WORDSIZE, SEEK_SET); + if (read_file(version, WORDSIZE, 1, p_data->file_handle) != 1) errorcode = 436; } @@ -319,26 +312,26 @@ int EXPORT_OUT_API ENR_getUnits(ENR_Handle p_handle, ENR_Units code, int* unitFl switch (code) { case ENR_flowUnits: - _fseek(p_data->file, 9*WORDSIZE, SEEK_SET); - fread(unitFlag, WORDSIZE, 1, p_data->file); + seek_file(p_data->file_handle, 9*WORDSIZE, SEEK_SET); + read_file(unitFlag, WORDSIZE, 1, p_data->file_handle); break; case ENR_pressUnits: - _fseek(p_data->file, 10*WORDSIZE, SEEK_SET); - fread(unitFlag, WORDSIZE, 1, p_data->file); + seek_file(p_data->file_handle, 10*WORDSIZE, SEEK_SET); + read_file(unitFlag, WORDSIZE, 1, p_data->file_handle); break; case ENR_qualUnits: offset = 7*WORDSIZE; - _fseek(p_data->file, offset, SEEK_SET); - fread(unitFlag, WORDSIZE, 1, p_data->file); + seek_file(p_data->file_handle, offset, SEEK_SET); + read_file(unitFlag, WORDSIZE, 1, p_data->file_handle); if (*unitFlag == 0) *unitFlag = ENR_NONE; else if (*unitFlag == 1) { offset = 15*WORDSIZE + 3*MAXMSG_P1 + 2*(MAXFNAME+1) + MAXID_P1; - _fseek(p_data->file, offset, SEEK_SET); - fread(temp, MAXID_P1, 1, p_data->file); + seek_file(p_data->file_handle, offset, SEEK_SET); + read_file(temp, MAXID_P1, 1, p_data->file_handle); if (!strcmp(temp, "mg/L")) *unitFlag = ENR_MGL; else *unitFlag = ENR_UGL; @@ -379,18 +372,18 @@ int EXPORT_OUT_API ENR_getTimes(ENR_Handle p_handle, ENR_Time code, int* time) switch (code) { case ENR_reportStart: - fseek(p_data->file, 12*WORDSIZE, SEEK_SET); - fread(time, WORDSIZE, 1, p_data->file); + seek_file(p_data->file_handle, 12*WORDSIZE, SEEK_SET); + read_file(time, WORDSIZE, 1, p_data->file_handle); break; case ENR_reportStep: - fseek(p_data->file, 13*WORDSIZE, SEEK_SET); - fread(time, WORDSIZE, 1, p_data->file); + seek_file(p_data->file_handle, 13*WORDSIZE, SEEK_SET); + read_file(time, WORDSIZE, 1, p_data->file_handle); break; case ENR_simDuration: - fseek(p_data->file, 14*WORDSIZE, SEEK_SET); - fread(time, WORDSIZE, 1, p_data->file); + seek_file(p_data->file_handle, 14*WORDSIZE, SEEK_SET); + read_file(time, WORDSIZE, 1, p_data->file_handle); break; case ENR_numPeriods: @@ -405,7 +398,6 @@ int EXPORT_OUT_API ENR_getTimes(ENR_Handle p_handle, ENR_Time code, int* time) } int EXPORT_OUT_API ENR_getChemData(ENR_Handle p_handle, char** name, int* length) - { return 0; } @@ -459,8 +451,8 @@ int EXPORT_OUT_API ENR_getElementName(ENR_Handle p_handle, ENR_ElementType type, if (!errorcode) { - _fseek(p_data->file, offset, SEEK_SET); - fread(temp, 1, MAXID_P1, p_data->file); + seek_file(p_data->file_handle, offset, SEEK_SET); + read_file(temp, 1, MAXID_P1, p_data->file_handle); *name = temp; *length = MAXID_P1; @@ -505,9 +497,9 @@ int EXPORT_OUT_API ENR_getEnergyUsage(ENR_Handle p_handle, int pumpIndex, offset += (pumpIndex - 1)*(WORDSIZE + 6*WORDSIZE); // Power summary is 1 int and 6 floats for each pump - _fseek(p_data->file, offset, SEEK_SET); - fread(linkIndex, WORDSIZE, 1, p_data->file); - fread(temp, WORDSIZE, 6, p_data->file); + seek_file(p_data->file_handle, offset, SEEK_SET); + read_file(linkIndex, WORDSIZE, 1, p_data->file_handle); + read_file(temp, WORDSIZE, 6, p_data->file_handle); *outValues = temp; *length = NENERGYRESULTS; @@ -541,8 +533,8 @@ int EXPORT_OUT_API ENR_getNetReacts(ENR_Handle p_handle, float** outValues, int* // Reaction summary is 4 floats located right before epilogue. // This offset is relative to the end of the file. offset = - 3*WORDSIZE - 4*WORDSIZE; - _fseek(p_data->file, offset, SEEK_END); - fread(temp, WORDSIZE, 4, p_data->file); + seek_file(p_data->file_handle, offset, SEEK_END); + read_file(temp, WORDSIZE, 4, p_data->file_handle); *outValues = temp; *length = NREACTRESULTS; @@ -670,8 +662,8 @@ int EXPORT_OUT_API ENR_getNodeAttribute(ENR_Handle p_handle, int periodIndex, // add offset for node and attribute offset += ((attr - 1)*p_data->nodeCount)*WORDSIZE; - _fseek(p_data->file, offset, SEEK_SET); - fread(temp, WORDSIZE, p_data->nodeCount, p_data->file); + seek_file(p_data->file_handle, offset, SEEK_SET); + read_file(temp, WORDSIZE, p_data->nodeCount, p_data->file_handle); *outValueArray = temp; *length = p_data->nodeCount; @@ -720,8 +712,8 @@ int EXPORT_OUT_API ENR_getLinkAttribute(ENR_Handle p_handle, int periodIndex, // add offset for link and attribute offset += ((attr - 1)*p_data->linkCount)*WORDSIZE; - _fseek(p_data->file, offset, SEEK_SET); - fread(temp, WORDSIZE, p_data->linkCount, p_data->file); + seek_file(p_data->file_handle, offset, SEEK_SET); + read_file(temp, WORDSIZE, p_data->linkCount, p_data->file_handle); *outValueArray = temp; *length = p_data->linkCount; @@ -852,16 +844,16 @@ int validateFile(ENR_Handle p_handle) p_data = (data_t*)p_handle; // Read magic number from beginning of file - fseek(p_data->file, 0L, SEEK_SET); - fread(&magic1, WORDSIZE, 1, p_data->file); + seek_file(p_data->file_handle, 0L, SEEK_SET); + read_file(&magic1, WORDSIZE, 1, p_data->file_handle); // Fast forward to end and read file epilogue - fseek(p_data->file, -3*WORDSIZE, SEEK_END); - fread(&(p_data->nPeriods), WORDSIZE, 1, p_data->file); - fread(&hydcode, WORDSIZE, 1, p_data->file); - fread(&magic2, WORDSIZE, 1, p_data->file); + seek_file(p_data->file_handle, -3*WORDSIZE, SEEK_END); + read_file(&(p_data->nPeriods), WORDSIZE, 1, p_data->file_handle); + read_file(&hydcode, WORDSIZE, 1, p_data->file_handle); + read_file(&magic2, WORDSIZE, 1, p_data->file_handle); - filepos = _ftell(p_data->file); + filepos = tell_file(p_data->file_handle); // Is the file an EPANET binary file? if (magic1 != magic2) errorcode = 435; @@ -891,8 +883,8 @@ float getNodeValue(ENR_Handle p_handle, int periodIndex, int nodeIndex, // add byte position for attribute and node offset += ((attr - 1)*p_data->nodeCount + (nodeIndex - 1))*WORDSIZE; - _fseek(p_data->file, offset, SEEK_SET); - fread(&y, WORDSIZE, 1, p_data->file); + seek_file(p_data->file_handle, offset, SEEK_SET); + read_file(&y, WORDSIZE, 1, p_data->file_handle); return y; } @@ -915,56 +907,12 @@ float getLinkValue(ENR_Handle p_handle, int periodIndex, int linkIndex, // add byte position for attribute and link offset += ((attr - 1)*p_data->linkCount + (linkIndex - 1))*WORDSIZE; - _fseek(p_data->file, offset, SEEK_SET); - fread(&y, WORDSIZE, 1, p_data->file); + seek_file(p_data->file_handle, offset, SEEK_SET); + read_file(&y, WORDSIZE, 1, p_data->file_handle); return y; } -int _fopen(FILE **f, const char *name, const char *mode) { - // - // Purpose: Substitute for fopen_s on platforms where it doesn't exist - // Note: fopen_s is part of C++11 standard - // - int ret = 0; -#ifdef _WIN32 - ret = (int)fopen_s(f, name, mode); -#else - *f = fopen(name, mode); - if (!*f) - ret = -1; -#endif - return ret; -} - -int _fseek(FILE* stream, F_OFF offset, int whence) -// -// Purpose: Selects platform fseek() for large file support -// -{ -#ifdef _WIN32 // Windows (32-bit and 64-bit) -#define FSEEK64 _fseeki64 -#else // Other platforms -#define FSEEK64 fseeko -#endif - - return FSEEK64(stream, offset, whence); -} - -F_OFF _ftell(FILE* stream) -// -// Purpose: Selects platform ftell() for large file support -// -{ -#ifdef _WIN32 // Windows (32-bit and 64-bit) -#define FTELL64 _ftelli64 -#else // Other platforms -#define FTELL64 ftello -#endif - - return FTELL64(stream); -} - float* newFloatArray(int n) // // Warning: Caller must free memory allocated by this function. diff --git a/src/util/filemanager.c b/src/util/filemanager.c index f2fcc8f..f2bdca3 100644 --- a/src/util/filemanager.c +++ b/src/util/filemanager.c @@ -1,49 +1,91 @@ -#include + +// MSVC ONLY +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif + #include #include "filemanager.h" +typedef struct file_s { + char filename[FILE_MAXNAME + 1]; + FILE *file; + char mode[FILE_MAXMODE + 1]; +} file_handle_t; + + // local (private) functions +int _fopen(FILE **f, const char *name, const char *mode); int _get_temp_filename(char *tempname); -file_handle_t *create_file_manager(const char *filename, const char *file_mode) { +file_handle_t *create_file_manager() { file_handle_t *file_handle; file_handle = (file_handle_t*)calloc(1, sizeof(file_handle_t)); + return file_handle; +} + +void delete_file_manager(file_handle_t *file_handle) { + free(file_handle); +} + + +int open_file(file_handle_t *file_handle, const char *filename, const char *file_mode) { + int error = 0; + if (filename == NULL) _get_temp_filename(file_handle->filename); else strncpy(file_handle->filename, filename, FILE_MAXNAME); - file_handle->file = NULL; - strncpy(file_handle->mode, file_mode, FILE_MAXMODE); - - return file_handle; -} - -int delete_file_manager(file_handle_t *file_handle) { - free(file_handle); -} - - -int open_file(file_handle_t *file_handle) { - int error = 0; - - if ((file_handle->file = fopen(file_handle->filename, file_handle->mode)) == NULL) + if (file_mode == NULL) error = -1; + else { + strncpy(file_handle->mode, file_mode, FILE_MAXMODE); + error = _fopen(&(file_handle->file), file_handle->filename, file_handle->mode); + } return error; } -FILE *get_file(file_handle_t *file_handle) { - return file_handle->file; +int seek_file(file_handle_t *file_handle, F_OFF offset, int whence) +{ +#ifdef _WIN32 // Windows (32-bit and 64-bit) +#define FSEEK64 _fseeki64 +#else // Other platforms +#define FSEEK64 fseeko +#endif + + return FSEEK64(file_handle->file, offset, whence); } +F_OFF tell_file(file_handle_t *file_handle) +{ +#ifdef _WIN32 // Windows (32-bit and 64-bit) +#define FTELL64 _ftelli64 +#else // Other platforms +#define FTELL64 ftello +#endif + + return FTELL64(file_handle->file); +} + +size_t read_file(void *ptr, size_t size, size_t nmemb, file_handle_t *file_handle) +{ + return fread(ptr, size, nmemb, file_handle->file); +} + + int close_file(file_handle_t *file_handle) { int error = 0; @@ -59,14 +101,30 @@ int remove_file(file_handle_t *file_handle) { } -int _get_temp_filename(char *tempname) { - int error = 0 +int _fopen(FILE **f, const char *name, const char *mode) { +// +// Purpose: Substitute for fopen_s on platforms where it doesn't exist +// Note: fopen_s is part of C++11 standard +// + int ret = 0; #ifdef _WIN32 - char* name = NULL; + ret = (int)fopen_s(f, name, mode); +#else + *f = fopen(name, mode); + if (!*f) + ret = -1; +#endif + return ret; +} + +int _get_temp_filename(char *tempname) { + int error = 0; +#ifdef _WIN32 + char *name = NULL; // --- use Windows _tempnam function to get a pointer to an // unused file name that begins with "en" - if ((name = _tempnam(NULL, "en") == NULL) { + if ((name = _tempnam(name, "en")) == NULL) { error = -1; return error; } diff --git a/src/util/filemanager.h b/src/util/filemanager.h index c9961b8..a69c68f 100644 --- a/src/util/filemanager.h +++ b/src/util/filemanager.h @@ -8,6 +8,14 @@ #include + +// F_OFF Must be a 8 byte / 64 bit integer for large file support +#ifdef _WIN32 // Windows (32-bit and 64-bit) +#define F_OFF __int64 +#else // Other platforms +#define F_OFF off_t +#endif + #define FILE_MAXNAME 259 #define FILE_MAXMODE 3 @@ -17,21 +25,22 @@ extern "C" { #endif -typedef struct file_s { - char filename[FILE_MAXNAME + 1], - FILE *file; - char mode[FILE_MAXMODE + 1]; -} file_handle_t; +typedef struct file_s file_handle_t; -file_handle_t *create_file_manager(const char *filename, const char *file_mode); +file_handle_t *create_file_manager(); -int delete_file_manager(file_handle_t *file_handle); +void delete_file_manager(file_handle_t *file_handle); -int open_file(file_handle_t *file_handle); +int open_file(file_handle_t *file_handle, const char *filename, const char *file_mode); + +int seek_file(file_handle_t *file_handle, F_OFF offset, int whence); + +F_OFF tell_file(file_handle_t *file_handle); + +size_t read_file(void *ptr, size_t size, size_t nmemb, file_handle_t *file_handle); -FILE *get_file(file_handle_t *file_handle); int close_file(file_handle_t *file_handle); diff --git a/tests/util/CMakeLists.txt b/tests/util/CMakeLists.txt index 6173a07..a349b4a 100644 --- a/tests/util/CMakeLists.txt +++ b/tests/util/CMakeLists.txt @@ -15,3 +15,9 @@ set (test_source add_executable(test_errormanager ${test_source}) target_include_directories(test_errormanager PUBLIC ../../src/) target_link_libraries(test_errormanager ${Boost_LIBRARIES}) + + + +add_executable(test_filemanager ./test_filemanager.cpp ../../src/util/filemanager.c) +target_include_directories(test_filemanager PUBLIC ../../src/) +target_link_libraries(test_filemanager ${Boost_LIBRARIES}) diff --git a/tests/util/test_errormanager.cpp b/tests/util/test_errormanager.cpp index 0003ee2..f9a88b6 100644 --- a/tests/util/test_errormanager.cpp +++ b/tests/util/test_errormanager.cpp @@ -1,7 +1,7 @@ #define BOOST_TEST_MODULE errormanager -//#define BOOST_TEST_DYN_LINK + #include #include "util/errormanager.h" diff --git a/tests/util/test_filemanager.cpp b/tests/util/test_filemanager.cpp index b9d830e..b81d9d3 100644 --- a/tests/util/test_filemanager.cpp +++ b/tests/util/test_filemanager.cpp @@ -5,3 +5,62 @@ #include #include "util/filemanager.h" + + +#define DATA_PATH_OUTPUT "./example1.out" + + +BOOST_AUTO_TEST_SUITE(test_filemanager) + +BOOST_AUTO_TEST_CASE (test_create_destroy) +{ + file_handle_t *file_handle = NULL; + + file_handle = create_file_manager(); + BOOST_CHECK(file_handle != NULL); + + delete_file_manager(file_handle); +} + +BOOST_AUTO_TEST_CASE(test_open_close) +{ + int error = 0; + file_handle_t *file_handle = NULL; + + file_handle = create_file_manager(); + BOOST_CHECK(file_handle != NULL); + + error = open_file(file_handle, DATA_PATH_OUTPUT, "rb"); + BOOST_REQUIRE(error == 0); + + error = close_file(file_handle); + BOOST_REQUIRE(error == 0); + + delete_file_manager(file_handle); +} + +struct Fixture{ + Fixture() { + error = 0; + file_handle = NULL; + + file_handle = create_file_manager(); + open_file(file_handle, DATA_PATH_OUTPUT, "rb"); + } + ~Fixture() { + close_file(file_handle); + delete_file_manager(file_handle); + } + int error; + file_handle_t *file_handle; +}; + +BOOST_FIXTURE_TEST_CASE(test_get_file, Fixture) +{ + FILE *file; + + //file = get_file(file_handle); + //BOOST_CHECK(file != NULL); +} + +BOOST_AUTO_TEST_SUITE_END() From b9f00421ddeaf507e505698dea950932ac968dc5 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Mon, 1 Apr 2019 15:16:58 -0400 Subject: [PATCH 11/49] Adding header info --- src/util/filemanager.c | 17 +++++++++++++---- src/util/filemanager.h | 18 +++++++++++++----- tests/util/test_filemanager.cpp | 21 +++++++++++++-------- 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/util/filemanager.c b/src/util/filemanager.c index f2bdca3..ddeee4b 100644 --- a/src/util/filemanager.c +++ b/src/util/filemanager.c @@ -1,4 +1,15 @@ - +/* + ****************************************************************************** + Project: OWA EPANET + Version: 2.2 + Module: util/filemanager.c + Description: Provides a simple interface for managing files + Authors: see AUTHORS + Copyright: see AUTHORS + License: see LICENSE + Last Updated: 04/01/2019 + ****************************************************************************** +*/ // MSVC ONLY @@ -18,7 +29,6 @@ typedef struct file_s { char filename[FILE_MAXNAME + 1]; FILE *file; - char mode[FILE_MAXMODE + 1]; } file_handle_t; @@ -51,8 +61,7 @@ int open_file(file_handle_t *file_handle, const char *filename, const char *file if (file_mode == NULL) error = -1; else { - strncpy(file_handle->mode, file_mode, FILE_MAXMODE); - error = _fopen(&(file_handle->file), file_handle->filename, file_handle->mode); + error = _fopen(&(file_handle->file), file_handle->filename, file_mode); } return error; diff --git a/src/util/filemanager.h b/src/util/filemanager.h index a69c68f..63cabd6 100644 --- a/src/util/filemanager.h +++ b/src/util/filemanager.h @@ -1,6 +1,15 @@ - - - +/* + ****************************************************************************** + Project: OWA EPANET + Version: 2.2 + Module: util/filemanager.h + Description: Provides a simple interface for managing files + Authors: see AUTHORS + Copyright: see AUTHORS + License: see LICENSE + Last Updated: 04/01/2019 + ****************************************************************************** +*/ #ifndef FILEMANAGER_H_ #define FILEMANAGER_H_ @@ -17,14 +26,13 @@ #endif #define FILE_MAXNAME 259 -#define FILE_MAXMODE 3 #if defined(__cplusplus) extern "C" { #endif - +// Forward declariation of file_handle_t typedef struct file_s file_handle_t; diff --git a/tests/util/test_filemanager.cpp b/tests/util/test_filemanager.cpp index b81d9d3..b73d139 100644 --- a/tests/util/test_filemanager.cpp +++ b/tests/util/test_filemanager.cpp @@ -1,4 +1,15 @@ - +/* + ****************************************************************************** + Project: OWA EPANET + Version: 2.2 + Module: util/test_filemanager.cpp + Description: Tests filemanager + Authors: see AUTHORS + Copyright: see AUTHORS + License: see LICENSE + Last Updated: 04/01/2019 + ****************************************************************************** +*/ #define BOOST_TEST_MODULE filemanager @@ -12,6 +23,7 @@ BOOST_AUTO_TEST_SUITE(test_filemanager) + BOOST_AUTO_TEST_CASE (test_create_destroy) { file_handle_t *file_handle = NULL; @@ -55,12 +67,5 @@ struct Fixture{ file_handle_t *file_handle; }; -BOOST_FIXTURE_TEST_CASE(test_get_file, Fixture) -{ - FILE *file; - - //file = get_file(file_handle); - //BOOST_CHECK(file != NULL); -} BOOST_AUTO_TEST_SUITE_END() From 36a12cd4b689ccd9e7da54c775b20967d01b0bc8 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Mon, 1 Apr 2019 15:23:13 -0400 Subject: [PATCH 12/49] Adding test_filemanager to ctest --- tests/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ffb73b4..fd9a8d8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -60,6 +60,10 @@ add_test(NAME test_reent add_test(NAME test_errormanager COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_errormanager) +add_test(NAME test_filemanager + COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_filemanager + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/outfile/data) + add_test(NAME test_output COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_output WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/outfile/data) From a0b08921fc3856acf9b376f85f5f69727eccf41d Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Mon, 1 Apr 2019 15:24:52 -0400 Subject: [PATCH 13/49] Tweaking header doc --- tests/util/test_filemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/util/test_filemanager.cpp b/tests/util/test_filemanager.cpp index b73d139..0b35293 100644 --- a/tests/util/test_filemanager.cpp +++ b/tests/util/test_filemanager.cpp @@ -3,7 +3,7 @@ Project: OWA EPANET Version: 2.2 Module: util/test_filemanager.cpp - Description: Tests filemanager + Description: Tests for util/filemanager.c Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE From 2c6d4ca74d72540d3a6f0c88d4bef2b08c24da5e Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Mon, 1 Apr 2019 18:05:02 -0400 Subject: [PATCH 14/49] Work in progress Added test for temp files, getter for filename, and wrappers for fwrite, fprintf, and fgets --- src/util/filemanager.c | 36 +++++++++++++++++++++++++++++++++ src/util/filemanager.h | 14 +++++++++++++ tests/util/CMakeLists.txt | 8 +------- tests/util/test_filemanager.cpp | 25 ++++++++++++++++++++++- 4 files changed, 75 insertions(+), 8 deletions(-) diff --git a/src/util/filemanager.c b/src/util/filemanager.c index ddeee4b..a5f5c43 100644 --- a/src/util/filemanager.c +++ b/src/util/filemanager.c @@ -21,6 +21,7 @@ #include #endif +#include #include #include "filemanager.h" @@ -50,6 +51,15 @@ void delete_file_manager(file_handle_t *file_handle) { } +void get_filename(file_handle_t *file_handle, char **filename) +{ + char *temp = (char*) malloc((FILE_MAXNAME)*sizeof(char)); + + strncpy(temp, file_handle->filename, FILE_MAXNAME); + *filename = temp; +} + + int open_file(file_handle_t *file_handle, const char *filename, const char *file_mode) { int error = 0; @@ -89,11 +99,37 @@ F_OFF tell_file(file_handle_t *file_handle) return FTELL64(file_handle->file); } +// Read and write to a binary file size_t read_file(void *ptr, size_t size, size_t nmemb, file_handle_t *file_handle) { return fread(ptr, size, nmemb, file_handle->file); } +size_t write_file(const void * ptr, size_t size, size_t count, file_handle_t *file_handle) +{ + return fwrite(ptr, size, count, file_handle->file); +} + + +// print and get from a text file +int printf_file(file_handle_t *file_handle, const char *format, ... ) +{ + int error = 0; + va_list args; + + va_start(args, format); + error = vfprintf(file_handle->file, format, args); + va_end(args); + + return error; +} + +int gets_file(char *str, int num, file_handle_t *file_handle) +{ + fgets(str, num, file_handle->file); + return 0; +} + int close_file(file_handle_t *file_handle) { int error = 0; diff --git a/src/util/filemanager.h b/src/util/filemanager.h index 63cabd6..1e313b8 100644 --- a/src/util/filemanager.h +++ b/src/util/filemanager.h @@ -16,6 +16,7 @@ #include +#include // F_OFF Must be a 8 byte / 64 bit integer for large file support @@ -41,14 +42,27 @@ file_handle_t *create_file_manager(); void delete_file_manager(file_handle_t *file_handle); +void get_filename(file_handle_t *file_handle, char **filename); + + int open_file(file_handle_t *file_handle, const char *filename, const char *file_mode); int seek_file(file_handle_t *file_handle, F_OFF offset, int whence); F_OFF tell_file(file_handle_t *file_handle); + +// Functions for working with binary files size_t read_file(void *ptr, size_t size, size_t nmemb, file_handle_t *file_handle); +size_t write_file(const void *ptr, size_t size, size_t count, file_handle_t *file_handle); + + +// Functions for working with text files +int printf_file(file_handle_t *file_handle, const char *format, ... ); + +int gets_file(char *str, int num, file_handle_t *file_handle); + int close_file(file_handle_t *file_handle); diff --git a/tests/util/CMakeLists.txt b/tests/util/CMakeLists.txt index a349b4a..e126ceb 100644 --- a/tests/util/CMakeLists.txt +++ b/tests/util/CMakeLists.txt @@ -7,17 +7,11 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -set (test_source -./test_errormanager.cpp -../../src/util/errormanager.c -) - -add_executable(test_errormanager ${test_source}) +add_executable(test_errormanager ./test_errormanager.cpp ../../src/util/errormanager.c) target_include_directories(test_errormanager PUBLIC ../../src/) target_link_libraries(test_errormanager ${Boost_LIBRARIES}) - add_executable(test_filemanager ./test_filemanager.cpp ../../src/util/filemanager.c) target_include_directories(test_filemanager PUBLIC ../../src/) target_link_libraries(test_filemanager ${Boost_LIBRARIES}) diff --git a/tests/util/test_filemanager.cpp b/tests/util/test_filemanager.cpp index 0b35293..79fcec7 100644 --- a/tests/util/test_filemanager.cpp +++ b/tests/util/test_filemanager.cpp @@ -14,6 +14,7 @@ #define BOOST_TEST_MODULE filemanager #include +#include #include "util/filemanager.h" @@ -21,6 +22,15 @@ #define DATA_PATH_OUTPUT "./example1.out" +boost::test_tools::predicate_result check_string(std::string test, std::string ref) +{ + if (ref.compare(test) == 0) + return true; + else + return false; +} + + BOOST_AUTO_TEST_SUITE(test_filemanager) @@ -57,7 +67,7 @@ struct Fixture{ file_handle = NULL; file_handle = create_file_manager(); - open_file(file_handle, DATA_PATH_OUTPUT, "rb"); + open_file(file_handle, NULL, "wt"); } ~Fixture() { close_file(file_handle); @@ -67,5 +77,18 @@ struct Fixture{ file_handle_t *file_handle; }; +BOOST_FIXTURE_TEST_CASE(test_temp_file, Fixture) +{ + char *filename; + + printf_file(file_handle, "%s", "This is a test."); + + get_filename(file_handle, &filename); + //BOOST_CHECK(check_string(filename, "./test_file.txt")); + + BOOST_CHECK(boost::filesystem::exists(filename) == true); + + free(filename); +} BOOST_AUTO_TEST_SUITE_END() From c98d13de803ffeec5280dd7ba3305720b586e659 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 2 Apr 2019 11:05:56 -0400 Subject: [PATCH 15/49] Updated filemanager to use dynamically allocated strings converted filename to dynamically allocated string created cstr_helper --- src/outfile/CMakeLists.txt | 3 +- src/util/cstr_helper.c | 22 +++++++++++++++ src/util/cstr_helper.h | 9 ++++++ src/util/filemanager.c | 49 ++++++++++++++++++++------------- src/util/filemanager.h | 4 ++- tests/util/CMakeLists.txt | 7 +++-- tests/util/test_filemanager.cpp | 3 +- 7 files changed, 73 insertions(+), 24 deletions(-) create mode 100644 src/util/cstr_helper.c create mode 100644 src/util/cstr_helper.h diff --git a/src/outfile/CMakeLists.txt b/src/outfile/CMakeLists.txt index 79a8ae1..c129221 100644 --- a/src/outfile/CMakeLists.txt +++ b/src/outfile/CMakeLists.txt @@ -22,7 +22,8 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) # configure file groups set(EPANET_OUT_SOURCES src/epanet_output.c ../util/errormanager.c - ../util/filemanager.c) + ../util/filemanager.c + ../util/cstr_helper.c) # the binary output file API diff --git a/src/util/cstr_helper.c b/src/util/cstr_helper.c new file mode 100644 index 0000000..9266551 --- /dev/null +++ b/src/util/cstr_helper.c @@ -0,0 +1,22 @@ + +#include +#include + + +int copy_cstr(const char *source, char **destination, size_t *size) +// Determines length, allocates memory, and returns a null terminated copy +// Be Aware: caller is responsible for freeing memory +{ + size_t len; + + len = strlen(source); + *destination = (char *) calloc(len + 1, sizeof(char)); + + if (*destination == NULL) + return -1; + else { + strncpy(*destination, source, len); + *size = len + 1; + } + return 0; +} diff --git a/src/util/cstr_helper.h b/src/util/cstr_helper.h new file mode 100644 index 0000000..1b435c1 --- /dev/null +++ b/src/util/cstr_helper.h @@ -0,0 +1,9 @@ + +#ifndef CSTR_HELPER_H_ +#define CSTR_HELPER_H_ + + +int copy_cstr(const char *source, char **destination, size_t *size); + + +#endif /* CSTR_HELPER_H_ */ diff --git a/src/util/filemanager.c b/src/util/filemanager.c index a5f5c43..98d775c 100644 --- a/src/util/filemanager.c +++ b/src/util/filemanager.c @@ -22,41 +22,50 @@ #endif #include -#include #include "filemanager.h" typedef struct file_s { - char filename[FILE_MAXNAME + 1]; + char *filename; + size_t size; FILE *file; } file_handle_t; // local (private) functions int _fopen(FILE **f, const char *name, const char *mode); -int _get_temp_filename(char *tempname); +int _get_temp_filename(char **tempname, size_t *size); file_handle_t *create_file_manager() { file_handle_t *file_handle; - file_handle = (file_handle_t*)calloc(1, sizeof(file_handle_t)); + file_handle = (file_handle_t *)calloc(1, sizeof(file_handle_t)); + + file_handle->filename = NULL; + file_handle->size = 0; + file_handle->file = NULL; return file_handle; } void delete_file_manager(file_handle_t *file_handle) { - free(file_handle); + + if (file_handle->file != NULL) + close_file(file_handle); + + free(file_handle->filename); + free(file_handle); } -void get_filename(file_handle_t *file_handle, char **filename) +void get_filename(file_handle_t *file_handle, char **filename, size_t *size) +// +// BE AWARE: The memory allocated here must be freed by the caller +// { - char *temp = (char*) malloc((FILE_MAXNAME)*sizeof(char)); - - strncpy(temp, file_handle->filename, FILE_MAXNAME); - *filename = temp; + copy_cstr(file_handle->filename, filename, size); } @@ -64,9 +73,9 @@ int open_file(file_handle_t *file_handle, const char *filename, const char *file int error = 0; if (filename == NULL) - _get_temp_filename(file_handle->filename); + _get_temp_filename(&(file_handle->filename), &(file_handle->size)); else - strncpy(file_handle->filename, filename, FILE_MAXNAME); + copy_cstr(filename, &(file_handle->filename), &(file_handle->size)); if (file_mode == NULL) error = -1; @@ -146,12 +155,14 @@ int remove_file(file_handle_t *file_handle) { } -int _fopen(FILE **f, const char *name, const char *mode) { +int _fopen(FILE **f, const char *name, const char *mode) // // Purpose: Substitute for fopen_s on platforms where it doesn't exist // Note: fopen_s is part of C++11 standard // +{ int ret = 0; + #ifdef _WIN32 ret = (int)fopen_s(f, name, mode); #else @@ -162,8 +173,10 @@ int _fopen(FILE **f, const char *name, const char *mode) { return ret; } -int _get_temp_filename(char *tempname) { +int _get_temp_filename(char **tempname, size_t *size) +{ int error = 0; + #ifdef _WIN32 char *name = NULL; @@ -173,10 +186,8 @@ int _get_temp_filename(char *tempname) { error = -1; return error; } - else if (strlen(name) < FILE_MAXNAME) - strncpy(tempname, name, FILE_MAXNAME); else - tempname = NULL; + copy_cstr(name, tempname, size); // --- free the pointer returned by _tempnam if (name) @@ -185,8 +196,8 @@ int _get_temp_filename(char *tempname) { // --- for non-Windows systems: #else // --- use system function mkstemp() to create a temporary file name - strncpy(tempname, "enXXXXXX", 8); - error = mkstemp(tempname); + copy_cstr("enXXXXXX", tempname, size) + error = mkstemp(*tempname); #endif return error; } diff --git a/src/util/filemanager.h b/src/util/filemanager.h index 1e313b8..f0b00d2 100644 --- a/src/util/filemanager.h +++ b/src/util/filemanager.h @@ -18,6 +18,8 @@ #include #include +#include "cstr_helper.h" + // F_OFF Must be a 8 byte / 64 bit integer for large file support #ifdef _WIN32 // Windows (32-bit and 64-bit) @@ -42,7 +44,7 @@ file_handle_t *create_file_manager(); void delete_file_manager(file_handle_t *file_handle); -void get_filename(file_handle_t *file_handle, char **filename); +void get_filename(file_handle_t *file_handle, char **filename, size_t *size); int open_file(file_handle_t *file_handle, const char *filename, const char *file_mode); diff --git a/tests/util/CMakeLists.txt b/tests/util/CMakeLists.txt index e126ceb..0bd4a43 100644 --- a/tests/util/CMakeLists.txt +++ b/tests/util/CMakeLists.txt @@ -7,11 +7,14 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -add_executable(test_errormanager ./test_errormanager.cpp ../../src/util/errormanager.c) +add_executable(test_errormanager ./test_errormanager.cpp + ../../src/util/errormanager.c) target_include_directories(test_errormanager PUBLIC ../../src/) target_link_libraries(test_errormanager ${Boost_LIBRARIES}) -add_executable(test_filemanager ./test_filemanager.cpp ../../src/util/filemanager.c) +add_executable(test_filemanager ./test_filemanager.cpp + ../../src/util/filemanager.c + ../../src/util/cstr_helper.c) target_include_directories(test_filemanager PUBLIC ../../src/) target_link_libraries(test_filemanager ${Boost_LIBRARIES}) diff --git a/tests/util/test_filemanager.cpp b/tests/util/test_filemanager.cpp index 79fcec7..310c620 100644 --- a/tests/util/test_filemanager.cpp +++ b/tests/util/test_filemanager.cpp @@ -80,10 +80,11 @@ struct Fixture{ BOOST_FIXTURE_TEST_CASE(test_temp_file, Fixture) { char *filename; + size_t size; printf_file(file_handle, "%s", "This is a test."); - get_filename(file_handle, &filename); + get_filename(file_handle, &filename, &size); //BOOST_CHECK(check_string(filename, "./test_file.txt")); BOOST_CHECK(boost::filesystem::exists(filename) == true); From a89f3c90053f2c2c40c99d39d8de38c8e9e6626d Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 2 Apr 2019 12:31:05 -0400 Subject: [PATCH 16/49] Making sure filename is null terminated string Added file_handle validation --- src/util/cstr_helper.c | 22 +++++++++++++++++----- src/util/cstr_helper.h | 6 +++++- src/util/filemanager.c | 27 +++++++++++++++++---------- src/util/filemanager.h | 3 +++ tests/util/test_filemanager.cpp | 4 +++- 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/util/cstr_helper.c b/src/util/cstr_helper.c index 9266551..2e33d50 100644 --- a/src/util/cstr_helper.c +++ b/src/util/cstr_helper.c @@ -2,21 +2,33 @@ #include #include +#include "cstr_helper.h" -int copy_cstr(const char *source, char **destination, size_t *size) + +int copy_cstr(const char *source, char **dest) // Determines length, allocates memory, and returns a null terminated copy // Be Aware: caller is responsible for freeing memory { size_t len; len = strlen(source); - *destination = (char *) calloc(len + 1, sizeof(char)); + *dest = (char *) calloc((len + 1), sizeof(char)); - if (*destination == NULL) + if (*dest == NULL) return -1; else { - strncpy(*destination, source, len); - *size = len + 1; + strncpy(*dest, source, (len + 1)); + strncat(*dest, "\0", 1); } return 0; } + + +bool isnullterm_cstr(const char *source) +{ + if (strchr(source, '\0')) + return true; + else + return false; + +} diff --git a/src/util/cstr_helper.h b/src/util/cstr_helper.h index 1b435c1..55f71d0 100644 --- a/src/util/cstr_helper.h +++ b/src/util/cstr_helper.h @@ -3,7 +3,11 @@ #define CSTR_HELPER_H_ -int copy_cstr(const char *source, char **destination, size_t *size); +#include + + +int copy_cstr(const char *source, char **destination); +bool isnullterm_cstr(const char *source); #endif /* CSTR_HELPER_H_ */ diff --git a/src/util/filemanager.c b/src/util/filemanager.c index 98d775c..49ca4a3 100644 --- a/src/util/filemanager.c +++ b/src/util/filemanager.c @@ -27,15 +27,14 @@ typedef struct file_s { - char *filename; - size_t size; + char *filename; // Assumes this is a null terminated string FILE *file; } file_handle_t; // local (private) functions int _fopen(FILE **f, const char *name, const char *mode); -int _get_temp_filename(char **tempname, size_t *size); +int _get_temp_filename(char **tempname); file_handle_t *create_file_manager() { @@ -44,14 +43,13 @@ file_handle_t *create_file_manager() { file_handle = (file_handle_t *)calloc(1, sizeof(file_handle_t)); file_handle->filename = NULL; - file_handle->size = 0; file_handle->file = NULL; return file_handle; } void delete_file_manager(file_handle_t *file_handle) { - + if (file_handle->file != NULL) close_file(file_handle); @@ -65,7 +63,7 @@ void get_filename(file_handle_t *file_handle, char **filename, size_t *size) // BE AWARE: The memory allocated here must be freed by the caller // { - copy_cstr(file_handle->filename, filename, size); + copy_cstr(file_handle->filename, filename); } @@ -73,9 +71,9 @@ int open_file(file_handle_t *file_handle, const char *filename, const char *file int error = 0; if (filename == NULL) - _get_temp_filename(&(file_handle->filename), &(file_handle->size)); + _get_temp_filename(&(file_handle->filename)); else - copy_cstr(filename, &(file_handle->filename), &(file_handle->size)); + copy_cstr(filename, &(file_handle->filename)); if (file_mode == NULL) error = -1; @@ -173,7 +171,7 @@ int _fopen(FILE **f, const char *name, const char *mode) return ret; } -int _get_temp_filename(char **tempname, size_t *size) +int _get_temp_filename(char **tempname) { int error = 0; @@ -187,7 +185,7 @@ int _get_temp_filename(char **tempname, size_t *size) return error; } else - copy_cstr(name, tempname, size); + copy_cstr(name, tempname); // --- free the pointer returned by _tempnam if (name) @@ -201,3 +199,12 @@ int _get_temp_filename(char **tempname, size_t *size) #endif return error; } + +bool is_valid(file_handle_t *file_handle) +{ + if ((file_handle->filename == NULL && file_handle->file == NULL) || + (isnullterm_cstr(file_handle->filename) && file_handle != NULL)) + return true; + else + return false; +} diff --git a/src/util/filemanager.h b/src/util/filemanager.h index f0b00d2..93ee8d9 100644 --- a/src/util/filemanager.h +++ b/src/util/filemanager.h @@ -71,6 +71,9 @@ int close_file(file_handle_t *file_handle); int remove_file(file_handle_t *file_handle); +bool is_valid(file_handle_t *file_handle); + + #if defined(__cplusplus) } #endif diff --git a/tests/util/test_filemanager.cpp b/tests/util/test_filemanager.cpp index 310c620..70ff6c6 100644 --- a/tests/util/test_filemanager.cpp +++ b/tests/util/test_filemanager.cpp @@ -40,6 +40,7 @@ BOOST_AUTO_TEST_CASE (test_create_destroy) file_handle = create_file_manager(); BOOST_CHECK(file_handle != NULL); + BOOST_CHECK(is_valid(file_handle) == true); delete_file_manager(file_handle); } @@ -54,6 +55,7 @@ BOOST_AUTO_TEST_CASE(test_open_close) error = open_file(file_handle, DATA_PATH_OUTPUT, "rb"); BOOST_REQUIRE(error == 0); + BOOST_CHECK(is_valid(file_handle) == true); error = close_file(file_handle); BOOST_REQUIRE(error == 0); @@ -85,7 +87,7 @@ BOOST_FIXTURE_TEST_CASE(test_temp_file, Fixture) printf_file(file_handle, "%s", "This is a test."); get_filename(file_handle, &filename, &size); - //BOOST_CHECK(check_string(filename, "./test_file.txt")); + BOOST_CHECK(is_valid(file_handle) == true); BOOST_CHECK(boost::filesystem::exists(filename) == true); From 3828ebb1cd4af7600dc0462b875d66ada24641d3 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 2 Apr 2019 13:48:38 -0400 Subject: [PATCH 17/49] updating cstr_helper to use secure string functions --- src/util/cstr_helper.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/util/cstr_helper.c b/src/util/cstr_helper.c index 2e33d50..13ca1c4 100644 --- a/src/util/cstr_helper.c +++ b/src/util/cstr_helper.c @@ -9,16 +9,19 @@ int copy_cstr(const char *source, char **dest) // Determines length, allocates memory, and returns a null terminated copy // Be Aware: caller is responsible for freeing memory { - size_t len; + size_t size; - len = strlen(source); - *dest = (char *) calloc((len + 1), sizeof(char)); + size = 1 + strlen(source); + *dest = (char *) calloc(size, sizeof(char)); if (*dest == NULL) return -1; else { - strncpy(*dest, source, (len + 1)); - strncat(*dest, "\0", 1); +#ifdef _MSC_VER + strncpy_s(*dest, size, source, size); +#else + strncpy(*dest, source, size); +#endif } return 0; } @@ -30,5 +33,4 @@ bool isnullterm_cstr(const char *source) return true; else return false; - } From 44fc73cf41c3f10af99e001f3daab68ef67f3360 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 2 Apr 2019 14:37:32 -0400 Subject: [PATCH 18/49] Fixing bug --- src/util/filemanager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/filemanager.c b/src/util/filemanager.c index 49ca4a3..9603ce4 100644 --- a/src/util/filemanager.c +++ b/src/util/filemanager.c @@ -194,7 +194,7 @@ int _get_temp_filename(char **tempname) // --- for non-Windows systems: #else // --- use system function mkstemp() to create a temporary file name - copy_cstr("enXXXXXX", tempname, size) + copy_cstr("enXXXXXX", tempname); error = mkstemp(*tempname); #endif return error; From ecf0e5173c159f414481af8506d430a56e3f6628 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 2 Apr 2019 15:27:05 -0400 Subject: [PATCH 19/49] revert 1a01b46 to 1b167b5 --- run/main.c | 1 - src/epanet.c | 43 +++++++++++++--------------- src/epanet2.c | 10 ++----- src/epanet_py.c | 1 - src/hash.c | 5 +++- src/hydcoeffs.c | 6 +++- src/hydraul.c | 6 +++- src/hydsolver.c | 6 +++- src/hydstatus.c | 1 - src/inpfile.c | 4 +++ src/input1.c | 28 ++++++++---------- src/input2.c | 63 ++++++++++++++++++++--------------------- src/input3.c | 11 +++---- src/mempool.c | 4 ++- src/output.c | 6 +++- src/project.c | 12 +++----- src/quality.c | 6 +++- src/qualreact.c | 1 - src/qualroute.c | 7 +++-- src/report.c | 7 +++-- src/rules.c | 6 +++- src/smatrix.c | 7 ++++- src/types.h | 4 +-- src/util/errormanager.c | 6 ++++ tests/CMakeLists.txt | 23 +++++++-------- tests/test_analysis.cpp | 1 + tests/test_project.cpp | 40 +++++++++----------------- tests/test_toolkit.hpp | 6 ---- 28 files changed, 163 insertions(+), 158 deletions(-) diff --git a/run/main.c b/run/main.c index ea0a91c..793fffa 100644 --- a/run/main.c +++ b/run/main.c @@ -12,7 +12,6 @@ */ #include - #include "epanet2.h" void writeConsole(char *s) diff --git a/src/epanet.c b/src/epanet.c index a6df228..29462bc 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -11,17 +11,12 @@ ****************************************************************************** */ -#ifdef _DEBUG - #define _CRTDBG_MAP_ALLOC - #include - #include -#else - #include -#endif - #include +#include #include - +#ifndef __APPLE__ +#include +#endif #include #include @@ -221,24 +216,26 @@ int DLLEXPORT EN_open(EN_Project p, const char *inpFile, const char *rptFile, ERRCODE(netsize(p)); ERRCODE(allocdata(p)); - if (!errcode) { - // Read input data - ERRCODE(getdata(p)); + // Read input data + ERRCODE(getdata(p)); - // Close input file - if (p->parser.InFile != NULL) { + // Close input file + if (p->parser.InFile != NULL) + { fclose(p->parser.InFile); p->parser.InFile = NULL; - } + } - // Free temporary linked lists used for Patterns & Curves - freeTmplist(p->parser.Patlist); - freeTmplist(p->parser.Curvelist); + // 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)); + // If using previously saved hydraulics file then open it + if (p->outfile.Hydflag == USE) ERRCODE(openhydfile(p)); - // Write input summary to report file + // Write input summary to report file + if (!errcode) + { if (p->report.Summaryflag) writesummary(p); writetime(p, FMT104); p->Openflag = TRUE; @@ -282,7 +279,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 **---------------------------------------------------------------- @@ -843,7 +840,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; } diff --git a/src/epanet2.c b/src/epanet2.c index 3d11608..935d6c4 100644 --- a/src/epanet2.c +++ b/src/epanet2.c @@ -10,15 +10,11 @@ Last Updated: 03/17/2019 ****************************************************************************** */ - -#ifdef _DEBUG - #define _CRTDBG_MAP_ALLOC - #include - #include +#ifndef __APPLE__ +#include #else - #include +#include #endif - #include #include "types.h" diff --git a/src/epanet_py.c b/src/epanet_py.c index e84fdc9..4c16cbf 100644 --- a/src/epanet_py.c +++ b/src/epanet_py.c @@ -26,7 +26,6 @@ typedef struct { Project *project; error_handle_t *error; }handle_t; - // Extern functions extern char *geterrmsg(int, char *); // Local functions diff --git a/src/hash.c b/src/hash.c index c3f91e2..95ac8dd 100755 --- a/src/hash.c +++ b/src/hash.c @@ -11,9 +11,12 @@ ****************************************************************************** */ +#ifndef __APPLE__ +#include +#else #include +#endif #include - #include "hash.h" #define HASHTABLEMAXSIZE 128000 diff --git a/src/hydcoeffs.c b/src/hydcoeffs.c index 4b3583d..b6c002c 100644 --- a/src/hydcoeffs.c +++ b/src/hydcoeffs.c @@ -11,9 +11,13 @@ ****************************************************************************** */ -#include #include #include +#ifndef __APPLE__ +#include +#else +#include +#endif #include #include "types.h" diff --git a/src/hydraul.c b/src/hydraul.c index c442ac6..703f7b7 100755 --- a/src/hydraul.c +++ b/src/hydraul.c @@ -11,9 +11,13 @@ ****************************************************************************** */ -#include #include #include +#ifndef __APPLE__ +#include +#else +#include +#endif #include #include "types.h" diff --git a/src/hydsolver.c b/src/hydsolver.c index 90c93e1..3c0694a 100644 --- a/src/hydsolver.c +++ b/src/hydsolver.c @@ -12,9 +12,13 @@ ****************************************************************************** */ -#include #include #include +#ifndef __APPLE__ +#include +#else +#include +#endif #include #include "types.h" diff --git a/src/hydstatus.c b/src/hydstatus.c index 5905337..f7edb6b 100644 --- a/src/hydstatus.c +++ b/src/hydstatus.c @@ -12,7 +12,6 @@ Last Updated: 11/27/2018 */ #include - #include "types.h" #include "funcs.h" diff --git a/src/inpfile.c b/src/inpfile.c index 994830a..45b5aab 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -13,7 +13,11 @@ Last Updated: 03/17/2019 #include #include +#ifndef __APPLE__ +#include +#else #include +#endif #include #include "types.h" diff --git a/src/input1.c b/src/input1.c index 4cafa13..fe606d9 100644 --- a/src/input1.c +++ b/src/input1.c @@ -3,30 +3,26 @@ 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 Last Updated: 03/17/2019 ****************************************************************************** */ -#ifdef _DEBUG - #define _CRTDBG_MAP_ALLOC - #include - #include -#else - #include -#endif #include +#include #include -#include +#ifndef __APPLE__ +#include +#endif #include "types.h" #include "funcs.h" #include "hash.h" #include "text.h" - +#include // Default values #define MAXITER 200 // Default max. # hydraulic iterations @@ -60,7 +56,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 @@ -106,7 +102,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 @@ -357,7 +353,7 @@ int inittanks(Project *pr) */ { Network *net = &pr->network; - + int i, j, n = 0; double a; int errcode = 0, levelerr; @@ -550,7 +546,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++) @@ -648,7 +644,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]; @@ -657,7 +653,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 e4d2d85..2820e35 100644 --- a/src/input2.c +++ b/src/input2.c @@ -10,16 +10,13 @@ License: see LICENSE Last Updated: 03/17/2019 ****************************************************************************** */ -#ifdef _DEBUG - #define _CRTDBG_MAP_ALLOC - #include - #include -#else - #include -#endif #include +#include #include +#ifndef __APPLE__ +#include +#endif #include #include "types.h" @@ -59,7 +56,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 @@ -150,7 +147,7 @@ int readdata(Project *pr) inperr, errsum; // Error code & total error count // Allocate input buffer - parser->X = (double *)calloc(MAXTOKS + 1, sizeof(double)); + parser->X = (double *)calloc(MAXTOKS, sizeof(double)); ERRCODE(MEMCHECK(parser->X)); if (errcode) return errcode; @@ -178,7 +175,7 @@ int readdata(Project *pr) while (fgets(line, MAXLINE, parser->InFile) != NULL) { // Make copy of line and scan for tokens - strncpy(wline, line, MAXLINE); + strcpy(wline, line); parser->Ntokens = gettokens(wline, parser->Tok, MAXTOKS, parser->Comment); // Skip blank lines and those filled with a comment @@ -249,10 +246,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); @@ -400,7 +397,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; @@ -410,7 +407,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) { @@ -421,7 +418,7 @@ int updatepumpparams(Project *pr, int pumpindex) q2 = curve->X[2]; h2 = curve->Y[2]; } - + // Custom pump curve else { @@ -434,7 +431,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) { @@ -464,7 +461,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; @@ -590,7 +587,7 @@ int unlinked(Project *pr) Network *net = &pr->network; int *marked; int i, err, errcode; - + errcode = 0; err = 0; @@ -599,19 +596,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); @@ -641,7 +638,7 @@ int getpatterns(Project *pr) SFloatlist *f; STmplist *tmppattern; Spattern *pattern; - + // Start at head of the list of patterns tmppattern = parser->Patlist; @@ -699,7 +696,7 @@ int getcurves(Project *pr) { Network *net = &pr->network; Parser *parser = &pr->parser; - + int i, j; double x; char errmsg[MAXMSG+1]; @@ -830,14 +827,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) { @@ -871,7 +868,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 @@ -879,7 +876,7 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment) } } return n; -} +} double hour(char *time, char *units) /* @@ -917,7 +914,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 @@ -936,7 +933,7 @@ double hour(char *time, char *units) else return (y[0] + 12.0); } return -1.0; -} +} int getfloat(char *s, double *y) /* @@ -982,14 +979,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 d00a6e9..fb35da2 100644 --- a/src/input3.c +++ b/src/input3.c @@ -10,16 +10,13 @@ License: see LICENSE Last Updated: 03/17/2019 ****************************************************************************** */ -#ifdef _DEBUG - #define _CRTDBG_MAP_ALLOC - #include - #include -#else - #include -#endif #include +#include #include +#ifndef __APPLE__ +#include +#endif #include #include "types.h" diff --git a/src/mempool.c b/src/mempool.c index 871b4c8..55552ed 100755 --- a/src/mempool.c +++ b/src/mempool.c @@ -15,7 +15,9 @@ */ #include - +#ifndef __APPLE__ +#include +#endif #include "mempool.h" /* diff --git a/src/output.c b/src/output.c index d86fe50..fd92077 100644 --- a/src/output.c +++ b/src/output.c @@ -11,9 +11,13 @@ Last Updated: 11/27/2018 ****************************************************************************** */ -#include #include #include +#ifndef __APPLE__ +#include +#else +#include +#endif #include #include "types.h" diff --git a/src/project.c b/src/project.c index 8355588..fd4cb8d 100644 --- a/src/project.c +++ b/src/project.c @@ -11,18 +11,14 @@ ****************************************************************************** */ -#ifdef _DEBUG -#define _CRTDBG_MAP_ALLOC -#include -#include +#include +#include +#ifndef __APPLE__ +#include #else #include #endif -#include -#include - - //*** For the Windows SDK _tempnam function ***// #ifdef _WIN32 #include diff --git a/src/quality.c b/src/quality.c index 06e1997..de27f63 100644 --- a/src/quality.c +++ b/src/quality.c @@ -11,9 +11,13 @@ Last Updated: 11/27/2018 ****************************************************************************** */ -#include #include #include +#ifndef __APPLE__ +#include +#else +#include +#endif #include #include "mempool.h" diff --git a/src/qualreact.c b/src/qualreact.c index 0afac47..0805a21 100644 --- a/src/qualreact.c +++ b/src/qualreact.c @@ -13,7 +13,6 @@ Last Updated: 11/27/2018 #include #include - #include "types.h" // Exported functions diff --git a/src/qualroute.c b/src/qualroute.c index 03e3545..72bb66f 100644 --- a/src/qualroute.c +++ b/src/qualroute.c @@ -11,10 +11,13 @@ Last Updated: 11/27/2018 ****************************************************************************** */ -#include #include +#ifndef __APPLE__ +#include +#else +#include +#endif #include - #include "mempool.h" #include "types.h" diff --git a/src/report.c b/src/report.c index dd4ff3d..5605ffb 100644 --- a/src/report.c +++ b/src/report.c @@ -11,10 +11,13 @@ ****************************************************************************** */ -#include #include #include - +#ifndef __APPLE__ +#include +#else +#include +#endif #ifdef _WIN32 #define snprintf _snprintf diff --git a/src/rules.c b/src/rules.c index eee5568..7e9945f 100644 --- a/src/rules.c +++ b/src/rules.c @@ -11,9 +11,13 @@ ****************************************************************************** */ -#include #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 3446384..510bb3e 100755 --- a/src/smatrix.c +++ b/src/smatrix.c @@ -18,11 +18,16 @@ linsolve() -- called from netsolve() in HYDRAUL.C */ -#include #include #include +#ifndef __APPLE__ +#include +#else +#include +#endif #include #include + #include //For optional timer macros #include "text.h" diff --git a/src/types.h b/src/types.h index 38d6607..4329414 100755 --- a/src/types.h +++ b/src/types.h @@ -14,10 +14,8 @@ #ifndef TYPES_H #define TYPES_H -#include - #include "hash.h" - +#include /* ------------------------------------------- diff --git a/src/util/errormanager.c b/src/util/errormanager.c index b674fe6..5a9876c 100644 --- a/src/util/errormanager.c +++ b/src/util/errormanager.c @@ -10,7 +10,13 @@ // US EPA - ORD/NRMRL //----------------------------------------------------------------------------- +//#ifdef _WIN32 +//#define _CRTDBG_MAP_ALLOC +//#include +//#include +//#else #include +//#endif #include #include "errormanager.h" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fd9a8d8..64c7c23 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,19 +19,18 @@ endif(UNIX) set(toolkit_test_srcs test_toolkit.cpp test_project.cpp -# test_hydraulics.cpp -# test_quality.cpp -# test_report.cpp -# test_analysis.cpp -# test_node.cpp -# test_demand.cpp -# test_link.cpp + test_hydraulics.cpp + test_quality.cpp + test_report.cpp + test_analysis.cpp + test_node.cpp + test_demand.cpp + test_link.cpp # test_pump.cpp -# test_pattern.cpp -# test_curve.cpp -# test_control.cpp -# test_net_builder.cpp -) + test_pattern.cpp + test_curve.cpp + test_control.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 917b523..f7120f1 100644 --- a/tests/test_analysis.cpp +++ b/tests/test_analysis.cpp @@ -11,6 +11,7 @@ ****************************************************************************** */ +//#define BOOST_ALL_DYN_LINK #include #include "test_toolkit.hpp" diff --git a/tests/test_project.cpp b/tests/test_project.cpp index 6ae1143..6f0b68c 100644 --- a/tests/test_project.cpp +++ b/tests/test_project.cpp @@ -56,47 +56,35 @@ BOOST_AUTO_TEST_CASE(test_save) { int error; - EN_Project ph = NULL; + EN_Project ph_save; - error = EN_createproject(&ph); - BOOST_REQUIRE(error == 0); - - error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT); + EN_createproject(&ph_save); + error = EN_open(ph_save, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT); BOOST_REQUIRE(error == 0); - error = EN_saveinpfile(ph, DATA_PATH_TMP); + error = EN_saveinpfile(ph_save, "test_reopen.inp"); BOOST_REQUIRE(error == 0); - BOOST_CHECK(boost::filesystem::exists(DATA_PATH_TMP) == true); + BOOST_CHECK(boost::filesystem::exists("test_reopen.inp") == true); - error = EN_close(ph); + error = EN_close(ph_save); BOOST_REQUIRE(error == 0); - - error = EN_deleteproject(&ph); - BOOST_REQUIRE(error == 0); - - BOOST_CHECK(ph == NULL); + EN_deleteproject(&ph_save); } BOOST_AUTO_TEST_CASE(test_reopen, * boost::unit_test::depends_on("test_project/test_save")) { int error; - EN_Project ph = NULL; + EN_Project ph_reopen; - error = EN_createproject(&ph); - BOOST_REQUIRE(error == 0); + EN_createproject(&ph_reopen); + error = EN_open(ph_reopen, "test_reopen.inp", DATA_PATH_RPT, DATA_PATH_OUT); + BOOST_REQUIRE(error == 0); - error = EN_open(ph, DATA_PATH_TMP, DATA_PATH_RPT, DATA_PATH_OUT); - BOOST_REQUIRE(error == 0); - - error = EN_close(ph); - BOOST_REQUIRE(error == 0); - - EN_deleteproject(&ph); - BOOST_REQUIRE(error == 0); - - BOOST_CHECK(ph == NULL); + error = EN_close(ph_reopen); + BOOST_REQUIRE(error == 0); + EN_deleteproject(&ph_reopen); } BOOST_AUTO_TEST_CASE(test_run) diff --git a/tests/test_toolkit.hpp b/tests/test_toolkit.hpp index f0da4e7..03ac664 100644 --- a/tests/test_toolkit.hpp +++ b/tests/test_toolkit.hpp @@ -14,12 +14,6 @@ #ifndef TEST_TOOLKIT_HPP #define TEST_TOOLKIT_HPP -// MSVC ONLY -#ifdef _DEBUG - #define _CRTDBG_MAP_ALLOC - #include - #include -#endif #include "epanet2_2.h" From 907760540e40c68d06a0d80c8a30ad94f6687ba9 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 2 Apr 2019 15:34:21 -0400 Subject: [PATCH 20/49] Reorganizing public functions --- src/util/filemanager.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/util/filemanager.c b/src/util/filemanager.c index 9603ce4..7a4469f 100644 --- a/src/util/filemanager.c +++ b/src/util/filemanager.c @@ -153,6 +153,16 @@ int remove_file(file_handle_t *file_handle) { } +bool is_valid(file_handle_t *file_handle) +{ + if ((file_handle->filename == NULL && file_handle->file == NULL) || + (isnullterm_cstr(file_handle->filename) && file_handle != NULL)) + return true; + else + return false; +} + + int _fopen(FILE **f, const char *name, const char *mode) // // Purpose: Substitute for fopen_s on platforms where it doesn't exist @@ -199,12 +209,3 @@ int _get_temp_filename(char **tempname) #endif return error; } - -bool is_valid(file_handle_t *file_handle) -{ - if ((file_handle->filename == NULL && file_handle->file == NULL) || - (isnullterm_cstr(file_handle->filename) && file_handle != NULL)) - return true; - else - return false; -} From 3ba40015b2c4577f1b84bb426fd9dd51464c002a Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 2 Apr 2019 15:41:24 -0400 Subject: [PATCH 21/49] revert 8574f52 --- appveyor.yml | 1 + src/epanet_py.c | 42 +++++++++++++++++++----------------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 22c1acf..dc80e1c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -98,3 +98,4 @@ on_failure: 7z a benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip .\epanet-%SUT_BUILD_ID% & appveyor PushArtifact benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip ) + diff --git a/src/epanet_py.c b/src/epanet_py.c index 4c16cbf..fb681aa 100644 --- a/src/epanet_py.c +++ b/src/epanet_py.c @@ -786,29 +786,25 @@ void error_lookup(int errcode, char *dest_msg, int dest_len) { char *msg = NULL; - switch (errcode) { - case 1: - msg = WARN1; - break; - case 2: - msg = WARN2; - break; - case 3: - msg = WARN3; - break; - case 4: - msg = WARN4; - break; - case 5: - msg = WARN5; - break; - case 6: - msg = WARN6; - break; - default: { - char new_msg[MAXMSG + 1]; - msg = geterrmsg(errcode, new_msg); - } + switch (errcode) + { + case 1: msg = WARN1; + break; + case 2: msg = WARN2; + break; + case 3: msg = WARN3; + break; + case 4: msg = WARN4; + break; + case 5: msg = WARN5; + break; + case 6: msg = WARN6; + break; + default: + { + char new_msg[MAXMSG + 1]; + msg = geterrmsg(errcode, new_msg); + } } strncpy(dest_msg, msg, dest_len); } From ddf0a088db598edc3b3af1341f9997b0b466bd57 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 2 Apr 2019 15:47:06 -0400 Subject: [PATCH 22/49] revert 1a01b46 --- appveyor.yml | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index dc80e1c..5972e3c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,23 +20,14 @@ environment: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 GENERATOR: "Visual Studio 15 2017" GROUP: "SUPPORTED" - BUILD_CONFIG: "Release" BOOST_ROOT: "C:/Libraries/boost_1_67_0" + PLATFORM: "win32" REF_BUILD_ID: "220dev5" # New build on Visual Studio 15 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 GENERATOR: "Visual Studio 15 2017 Win64" GROUP: "EXPERIMENTAL" - BUILD_CONFIG: "Release" - BOOST_ROOT: "C:/Libraries/boost_1_67_0" - PLATFORM: "win64" - REF_BUILD_ID: "381_2" - # adding debug configuration so we can monitor memory leaks - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - GENERATOR: "Visual Studio 15 2017 Win64" - GROUP: "EXPERIMENTAL" - BUILD_CONFIG: "Debug" BOOST_ROOT: "C:/Libraries/boost_1_67_0" PLATFORM: "win64" REF_BUILD_ID: "381_2" @@ -69,7 +60,7 @@ before_build: # run custom build script build_script: - - cmake --build . --config %BUILD_CONFIG% + - cmake --build . --config Release before_test: - cd %EPANET_HOME% @@ -79,12 +70,11 @@ before_test: test_script: # run unit tests - cd %BUILD_HOME%\tests - - ctest -C %BUILD_CONFIG% --output-on-failure + - ctest -C Release --output-on-failure # run regression tests - cd %EPANET_HOME% - - IF "%BUILD_CONFIG%" == "Release" ( - tools\run-nrtest.cmd %REF_BUILD_ID% %SUT_BUILD_ID% - ) + - tools\run-nrtest.cmd %REF_BUILD_ID% %SUT_BUILD_ID% + on_success: - cd %TEST_HOME%\benchmark - IF "%BUILD_CONFIG%" == "Release" ( @@ -98,4 +88,3 @@ on_failure: 7z a benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip .\epanet-%SUT_BUILD_ID% & appveyor PushArtifact benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip ) - From 611afbafd2c8399380fae0904f4a4142806901a1 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 2 Apr 2019 15:58:16 -0400 Subject: [PATCH 23/49] Update .travis.yml No apt-get update --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3349562..308cb2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ env: - TEST_HOME=nrtestsuite before_install: - - sudo apt-get -qq update +# - sudo apt-get -qq update - eval "${MATRIX_EVAL}" #install: From 90325d7a65748a35f760afee8b5f7265fcee9194 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 2 Apr 2019 16:14:28 -0400 Subject: [PATCH 24/49] Update appveyor.yml Rolling back changes to match dev HEAD --- appveyor.yml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 5972e3c..4eda106 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -21,7 +21,6 @@ environment: GENERATOR: "Visual Studio 15 2017" GROUP: "SUPPORTED" BOOST_ROOT: "C:/Libraries/boost_1_67_0" - PLATFORM: "win32" REF_BUILD_ID: "220dev5" # New build on Visual Studio 15 2017 @@ -77,14 +76,10 @@ test_script: on_success: - cd %TEST_HOME%\benchmark - - IF "%BUILD_CONFIG%" == "Release" ( - appveyor PushArtifact receipt.json - ) + - appveyor PushArtifact receipt.json on_failure: - cd %TEST_HOME%\benchmark # zip up the SUT benchmarks - - IF "%BUILD_CONFIG%" == "Release" ( - 7z a benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip .\epanet-%SUT_BUILD_ID% & - appveyor PushArtifact benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip - ) + - 7z a benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip .\epanet-%SUT_BUILD_ID% & + - appveyor PushArtifact benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip From 525c861d4b51bebff5f6e9a04223cbe30b369226 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 2 Apr 2019 16:16:53 -0400 Subject: [PATCH 25/49] Update appveyor.yml Fixing bug --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 4eda106..d8e6ce9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -81,5 +81,5 @@ on_success: on_failure: - cd %TEST_HOME%\benchmark # zip up the SUT benchmarks - - 7z a benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip .\epanet-%SUT_BUILD_ID% & + - 7z a benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip .\epanet-%SUT_BUILD_ID% - appveyor PushArtifact benchmark-%PLATFORM%-%SUT_BUILD_ID%.zip From ea5d2894b1603ff6cdfd02bd4fa1277cf3002d18 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 2 Apr 2019 16:51:55 -0400 Subject: [PATCH 26/49] Bumping version, updating headers --- src/outfile/src/epanet_output.c | 5 +++-- src/util/cstr_helper.c | 12 ++++++++++++ src/util/cstr_helper.h | 12 ++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/outfile/src/epanet_output.c b/src/outfile/src/epanet_output.c index 6e0c63d..7d46e03 100644 --- a/src/outfile/src/epanet_output.c +++ b/src/outfile/src/epanet_output.c @@ -2,8 +2,9 @@ // // epanet_output.c -- API for reading results from EPANET binary output file // -// Version: 0.30 -// Date 09/06/2017 +// Version: 0.40 +// Date 04/02/2019 +// 09/06/2017 // 06/17/2016 // 08/05/2014 // 05/21/2014 diff --git a/src/util/cstr_helper.c b/src/util/cstr_helper.c index 13ca1c4..9106446 100644 --- a/src/util/cstr_helper.c +++ b/src/util/cstr_helper.c @@ -1,3 +1,15 @@ +/* + ****************************************************************************** + Project: OWA EPANET + Version: 2.2 + Module: util/cstr_helper.c + Description: Provides a simple interface for managing files + Authors: see AUTHORS + Copyright: see AUTHORS + License: see LICENSE + Last Updated: 04/02/2019 + ****************************************************************************** +*/ #include #include diff --git a/src/util/cstr_helper.h b/src/util/cstr_helper.h index 55f71d0..ba4aac9 100644 --- a/src/util/cstr_helper.h +++ b/src/util/cstr_helper.h @@ -1,3 +1,15 @@ +/* + ****************************************************************************** + Project: OWA EPANET + Version: 2.2 + Module: util/cstr_helper.h + Description: Provides a simple interface for managing files + Authors: see AUTHORS + Copyright: see AUTHORS + License: see LICENSE + Last Updated: 04/02/2019 + ****************************************************************************** +*/ #ifndef CSTR_HELPER_H_ #define CSTR_HELPER_H_ From 0e30d57d4e96ee9a9efd48a3ff7f3a5361f89a06 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 2 Apr 2019 17:01:35 -0400 Subject: [PATCH 27/49] Update errormanager Make error_handle_t "private". Update headers. --- src/util/errormanager.c | 29 ++++++++++++++++++----------- src/util/errormanager.h | 25 +++++++++++++------------ 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/util/errormanager.c b/src/util/errormanager.c index 5a9876c..96a40bd 100644 --- a/src/util/errormanager.c +++ b/src/util/errormanager.c @@ -1,14 +1,15 @@ -//----------------------------------------------------------------------------- -// -// errormanager.c -// -// Purpose: Provides a simple interface for managing runtime error messages. -// -// Date: 08/25/2017 -// -// Author: Michael E. Tryby -// US EPA - ORD/NRMRL -//----------------------------------------------------------------------------- +/* + ****************************************************************************** + Project: OWA EPANET + Version: 2.2 + Module: util/errormanager.c + Description: Provides a simple interface for managing files + Authors: see AUTHORS + Copyright: see AUTHORS + License: see LICENSE + Last Updated: 04/02/2019 + ****************************************************************************** +*/ //#ifdef _WIN32 //#define _CRTDBG_MAP_ALLOC @@ -22,6 +23,12 @@ #include "errormanager.h" +typedef struct error_s { + int error_status; + void (*p_msg_lookup)(int, char*, int); +} error_handle_t; + + error_handle_t *create_error_manager(void (*p_error_message)(int, char*, int)) // // Purpose: Constructs a new error handle. diff --git a/src/util/errormanager.h b/src/util/errormanager.h index 6939f35..450eb88 100644 --- a/src/util/errormanager.h +++ b/src/util/errormanager.h @@ -1,11 +1,15 @@ /* - * errormanager.h - * - * Created on: Aug 25, 2017 - * - * Author: Michael E. Tryby - * US EPA - ORD/NRMRL - */ + ****************************************************************************** + Project: OWA EPANET + Version: 2.2 + Module: util/errormanager.h + Description: Provides a simple interface for managing files + Authors: see AUTHORS + Copyright: see AUTHORS + License: see LICENSE + Last Updated: 04/02/2019 + ****************************************************************************** +*/ #ifndef ERRORMANAGER_H_ #define ERRORMANAGER_H_ @@ -17,11 +21,8 @@ extern "C" { #endif - -typedef struct error_s { - int error_status; - void (*p_msg_lookup)(int, char*, int); -} error_handle_t; +// Forward declaration +typedef struct error_s error_handle_t; error_handle_t* create_error_manager(void (*p_error_message)(int, char*, int)); void delete_error_manager(error_handle_t* error_handle); From db85975151c240bb113a94a95faae66148cae167 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 2 Apr 2019 17:28:48 -0400 Subject: [PATCH 28/49] Fixing header comments --- src/util/cstr_helper.c | 2 +- src/util/cstr_helper.h | 2 +- src/util/errormanager.c | 2 +- src/util/errormanager.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/cstr_helper.c b/src/util/cstr_helper.c index 9106446..7d005a0 100644 --- a/src/util/cstr_helper.c +++ b/src/util/cstr_helper.c @@ -3,7 +3,7 @@ Project: OWA EPANET Version: 2.2 Module: util/cstr_helper.c - Description: Provides a simple interface for managing files + Description: Provides C string helper functions Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE diff --git a/src/util/cstr_helper.h b/src/util/cstr_helper.h index ba4aac9..c344042 100644 --- a/src/util/cstr_helper.h +++ b/src/util/cstr_helper.h @@ -3,7 +3,7 @@ Project: OWA EPANET Version: 2.2 Module: util/cstr_helper.h - Description: Provides a simple interface for managing files + Description: Provides C string helper functions Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE diff --git a/src/util/errormanager.c b/src/util/errormanager.c index 96a40bd..57c19de 100644 --- a/src/util/errormanager.c +++ b/src/util/errormanager.c @@ -3,7 +3,7 @@ Project: OWA EPANET Version: 2.2 Module: util/errormanager.c - Description: Provides a simple interface for managing files + Description: Provides a simple interface for managing errors Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE diff --git a/src/util/errormanager.h b/src/util/errormanager.h index 450eb88..49823a9 100644 --- a/src/util/errormanager.h +++ b/src/util/errormanager.h @@ -3,7 +3,7 @@ Project: OWA EPANET Version: 2.2 Module: util/errormanager.h - Description: Provides a simple interface for managing files + Description: Provides a simple interface for managing errors Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE From 6a4b95f4d517942ce750bb5abaa07dadb6ff5c9f Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Tue, 2 Apr 2019 22:21:05 -0400 Subject: [PATCH 29/49] Bug fixes --- src/epanet.c | 19 +++++++++++++------ src/inpfile.c | 7 +++---- src/input2.c | 8 +++++++- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 29462bc..8eb1ecf 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 03/17/2019 + Last Updated: 04/02/2019 ****************************************************************************** */ @@ -1589,13 +1589,20 @@ int DLLEXPORT EN_setqualtype(EN_Project p, int qualType, char *chemName, Quality *qual = &p->quality; double *Ucf = p->Ucf; - int i; + int i, oldQualFlag, traceNodeIndex; double ccf = 1.0; if (!p->Openflag) return 102; if (qual->OpenQflag) return 262; - if (qualType < EN_NONE || qualType > EN_TRACE) return 251; - qual->Qualflag = (char)qualType; + if (qualType < NONE || qualType > TRACE) return 251; + if (qualType == TRACE) + { + traceNodeIndex = findnode(net, traceNode); + if (traceNodeIndex == 0) return 212; + } + + oldQualFlag = qual->Qualflag; + qual->Qualflag = qualType; qual->Ctol *= Ucf[QUALITY]; if (qual->Qualflag == CHEM) // Chemical analysis { @@ -1623,14 +1630,14 @@ int DLLEXPORT EN_setqualtype(EN_Project p, int qualType, char *chemName, // When changing from CHEM to AGE or TRACE, nodes initial quality // values must be returned to their original ones - if ((qual->Qualflag == AGE || qual->Qualflag == TRACE) & (Ucf[QUALITY] != 1)) + if ((qual->Qualflag == AGE || qual->Qualflag == TRACE) && oldQualFlag == CHEM) { for (i = 1; i <= p->network.Nnodes; i++) { p->network.Node[i].C0 *= Ucf[QUALITY]; } } - + Ucf[QUALITY] = ccf; Ucf[LINKQUAL] = ccf; Ucf[REACTRATE] = ccf; diff --git a/src/inpfile.c b/src/inpfile.c index 45b5aab..8aa3c52 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: 03/17/2019 +Last Updated: 04/02/2019 ****************************************************************************** */ @@ -542,7 +542,7 @@ int saveinpfile(Project *pr, const char *fname) if (qual->Climit > 0.0) { - fprintf(f, "\n LIMITING POTENTIAL %-.6f", qual->Climit); + fprintf(f, "\n LIMITING POTENTIAL %-.6f", qual->Climit * pr->Ucf[QUALITY]); } if (qual->Rfactor != MISSING && qual->Rfactor != 0.0) { @@ -797,8 +797,7 @@ int saveinpfile(Project *pr, const char *fname) saveauxdata(pr, f); // Close the new input file - fprintf(f, "\n"); - fprintf(f, s_END); + fprintf(f, "\n%s\n", s_END); fclose(f); return 0; } diff --git a/src/input2.c b/src/input2.c index 2820e35..f1d0c9f 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: 03/17/2019 +Last Updated: 04/02/2019 ****************************************************************************** */ @@ -860,6 +860,12 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment) while (len > 0 && n < MAXTOKS) { m = (int)strcspn(s,SEPSTR); // Find token length + if (m == len) // s is last token + { + Tok[n] = s; + n++; + break; + } len -= m+1; // Update length of s if (m == 0) s++; // No token found else From ca0ea0e17c15411cf6103c311197514b6cd1f4e1 Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Wed, 3 Apr 2019 00:58:40 -0400 Subject: [PATCH 30/49] 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 31/49] 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 207cc53b047e04ad9db6ad9bb34d126dc5c4b390 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 3 Apr 2019 09:27:51 -0400 Subject: [PATCH 32/49] Cleaning up build on gcc --- src/util/filemanager.c | 6 +++--- src/util/filemanager.h | 2 +- tests/test_link.cpp | 2 ++ tests/util/test_errormanager.cpp | 4 ++-- tests/util/test_filemanager.cpp | 6 +++--- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/util/filemanager.c b/src/util/filemanager.c index 7a4469f..1d4e643 100644 --- a/src/util/filemanager.c +++ b/src/util/filemanager.c @@ -58,12 +58,12 @@ void delete_file_manager(file_handle_t *file_handle) { } -void get_filename(file_handle_t *file_handle, char **filename, size_t *size) +int get_filename(file_handle_t *file_handle, char **filename) // // BE AWARE: The memory allocated here must be freed by the caller // { - copy_cstr(file_handle->filename, filename); + return copy_cstr(file_handle->filename, filename); } @@ -171,7 +171,7 @@ int _fopen(FILE **f, const char *name, const char *mode) { int ret = 0; -#ifdef _WIN32 +#ifdef _MSC_VER ret = (int)fopen_s(f, name, mode); #else *f = fopen(name, mode); diff --git a/src/util/filemanager.h b/src/util/filemanager.h index 93ee8d9..68bd7c2 100644 --- a/src/util/filemanager.h +++ b/src/util/filemanager.h @@ -44,7 +44,7 @@ file_handle_t *create_file_manager(); void delete_file_manager(file_handle_t *file_handle); -void get_filename(file_handle_t *file_handle, char **filename, size_t *size); +int get_filename(file_handle_t *file_handle, char **filename); int open_file(file_handle_t *file_handle, const char *filename, const char *file_mode); diff --git a/tests/test_link.cpp b/tests/test_link.cpp index 15f451e..aa20d23 100644 --- a/tests/test_link.cpp +++ b/tests/test_link.cpp @@ -11,6 +11,8 @@ ****************************************************************************** */ +#include + #include #include "test_toolkit.hpp" diff --git a/tests/util/test_errormanager.cpp b/tests/util/test_errormanager.cpp index f9a88b6..43f59e2 100644 --- a/tests/util/test_errormanager.cpp +++ b/tests/util/test_errormanager.cpp @@ -15,10 +15,10 @@ void mock_lookup(int errcode, char *errmsg, int len) char *msg = NULL; if (errcode == 100) { - msg = MESSAGE_STRING; + msg = (char *)MESSAGE_STRING; } else { - msg = ""; + msg = (char *)""; } strncpy(errmsg, msg, len); } diff --git a/tests/util/test_filemanager.cpp b/tests/util/test_filemanager.cpp index 70ff6c6..7e17577 100644 --- a/tests/util/test_filemanager.cpp +++ b/tests/util/test_filemanager.cpp @@ -82,12 +82,12 @@ struct Fixture{ BOOST_FIXTURE_TEST_CASE(test_temp_file, Fixture) { char *filename; - size_t size; printf_file(file_handle, "%s", "This is a test."); - get_filename(file_handle, &filename, &size); - BOOST_CHECK(is_valid(file_handle) == true); + error = get_filename(file_handle, &filename); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(is_valid(file_handle) == true); BOOST_CHECK(boost::filesystem::exists(filename) == true); From 83ffc1cfc7550313d2e0712c7ab7e7599bc0e9e1 Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Wed, 3 Apr 2019 10:25:37 -0400 Subject: [PATCH 33/49] 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 9da7e9a81b09d6e6aaae6b337ce25611423da268 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 3 Apr 2019 10:29:10 -0400 Subject: [PATCH 34/49] Cleaning up build on gcc --- src/project.c | 12 ++++-------- src/util/filemanager.c | 6 +++--- src/util/filemanager.h | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/project.c b/src/project.c index fd4cb8d..1e99817 100644 --- a/src/project.c +++ b/src/project.c @@ -11,13 +11,9 @@ ****************************************************************************** */ +#include #include #include -#ifndef __APPLE__ -#include -#else -#include -#endif //*** For the Windows SDK _tempnam function ***// #ifdef _WIN32 @@ -174,7 +170,7 @@ int openoutfile(Project *pr) // Close output file if already opened closeoutfile(pr); - + // If output file name was supplied, then attempt to // open it. Otherwise open a temporary output file. pr->outfile.OutFile = fopen(pr->outfile.OutFname, "w+b"); @@ -284,7 +280,7 @@ void initpointers(Project *pr) pr->hydraul.smatrix.XLNZ = NULL; pr->hydraul.smatrix.NZSUB = NULL; pr->hydraul.smatrix.LNZ = NULL; - + initrules(pr); } @@ -1027,7 +1023,7 @@ char *xstrcpy(char **s1, const char *s2, const size_t n) { size_t n1 = 0, n2; - // Source string is empty -- free destination string + // Source string is empty -- free destination string if (s2 == NULL || strlen(s2) == 0) { free(*s1); diff --git a/src/util/filemanager.c b/src/util/filemanager.c index 1d4e643..eb9c4cd 100644 --- a/src/util/filemanager.c +++ b/src/util/filemanager.c @@ -86,7 +86,7 @@ int open_file(file_handle_t *file_handle, const char *filename, const char *file int seek_file(file_handle_t *file_handle, F_OFF offset, int whence) { -#ifdef _WIN32 // Windows (32-bit and 64-bit) +#ifdef _MSC_VER // Windows (32-bit and 64-bit) #define FSEEK64 _fseeki64 #else // Other platforms #define FSEEK64 fseeko @@ -97,7 +97,7 @@ int seek_file(file_handle_t *file_handle, F_OFF offset, int whence) F_OFF tell_file(file_handle_t *file_handle) { -#ifdef _WIN32 // Windows (32-bit and 64-bit) +#ifdef _MSC_VER // Windows (32-bit and 64-bit) #define FTELL64 _ftelli64 #else // Other platforms #define FTELL64 ftello @@ -185,7 +185,7 @@ int _get_temp_filename(char **tempname) { int error = 0; -#ifdef _WIN32 +#ifdef _MSC_VER char *name = NULL; // --- use Windows _tempnam function to get a pointer to an diff --git a/src/util/filemanager.h b/src/util/filemanager.h index 68bd7c2..a3866c3 100644 --- a/src/util/filemanager.h +++ b/src/util/filemanager.h @@ -22,7 +22,7 @@ // F_OFF Must be a 8 byte / 64 bit integer for large file support -#ifdef _WIN32 // Windows (32-bit and 64-bit) +#ifdef _MSC_VER // Windows (32-bit and 64-bit) #define F_OFF __int64 #else // Other platforms #define F_OFF off_t From af825005d4bc37cd66fbbfb465775efae7ea86b0 Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Wed, 3 Apr 2019 10:43:19 -0400 Subject: [PATCH 35/49] 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 36/49] 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 37/49] 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 38/49] 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 39/49] 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 40/49] 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 41/49] 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 42/49] 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 43/49] 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 44/49] 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 45/49] 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 46/49] 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; From b8443230c660b0e69f51e24218d5f552f1d12e58 Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Mon, 8 Apr 2019 11:16:23 -0400 Subject: [PATCH 47/49] Bug fix for 2Comp and LIFO tank mixing models (issue #448) --- src/qualreact.c | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/src/qualreact.c b/src/qualreact.c index 8faf89b..3b4b741 100644 --- a/src/qualreact.c +++ b/src/qualreact.c @@ -32,6 +32,7 @@ double mixtank(Project *, int, double, double ,double); // Imported functions extern void addseg(Project *, int, double, double); +extern void reversesegs(Project *, int); // Local functions static double piperate(Project *, int); @@ -170,7 +171,7 @@ void reactpipes(Project *pr, long dt) } -void reacttanks(Project *pr, long dt) +void reacttanks(Project *pr, long dt) /* **-------------------------------------------------------------- ** Input: dt = time step @@ -539,7 +540,7 @@ void tankmix2(Project *pr, int i, double vin, double win, double vnet) vt = MAX(0.0, (mixzone->v + vnet - vmz)); if (vin > 0.0) { - mixzone->c = ((stagzone->c) * (stagzone->v) + win) / + mixzone->c = ((mixzone->c) * (mixzone->v) + win) / (mixzone->v + vin); } if (vt > 0.0) @@ -683,18 +684,14 @@ void tankmix4(Project *pr, int i, double vin, double win, double vnet) seg = qual->LastSeg[k]; if (vnet > 0.0) { - // ... quality is the same, so just add flow volume to last seg + // ... inflow quality is same as last segment's quality, + // so just add inflow volume to last segment if (fabs(seg->c - cin) < qual->Ctol) seg->v += vnet; - // ... otherwise add a new last seg to tank which points to old last seg - else - { - qual->LastSeg[k] = NULL; - addseg(pr, k, vnet, cin); - qual->LastSeg[k]->prev = seg; - } + // ... otherwise add a new last segment with inflow quality + else addseg(pr, k, vnet, cin); - // ... update reported tank quality + // Update reported tank quality tank->C = qual->LastSeg[k]->c; } @@ -704,28 +701,48 @@ void tankmix4(Project *pr, int i, double vin, double win, double vnet) vsum = 0.0; wsum = 0.0; vnet = -vnet; + + // Reverse segment chain so segments are processed from last to first + reversesegs(pr, k); + + // While there is still volume to remove while (vnet > 0.0) { - seg = qual->LastSeg[k]; + // ... start with reversed first segment + seg = qual->FirstSeg[k]; if (seg == NULL) break; + + // ... find volume to remove from it vseg = seg->v; vseg = MIN(vseg, vnet); - if (seg == qual->FirstSeg[k]) vseg = vnet; + if (seg == qual->LastSeg[k]) vseg = vnet; + + // ... update total volume & mass removed vsum += vseg; wsum += (seg->c) * vseg; + + // ... update remiaing volume to remove vnet -= vseg; - if (vnet >= 0.0 && vseg >= seg->v) // Seg used up + + // ... if no more volume left in current segment + if (vnet >= 0.0 && vseg >= seg->v) { + // ... replace current segment with previous one if (seg->prev) { - qual->LastSeg[k] = seg->prev; + qual->FirstSeg[k] = seg->prev; seg->prev = qual->FreeSeg; qual->FreeSeg = seg; } } - else seg->v -= vseg; // Remaining volume in segment + + // ... otherwise reduce volume of current segment + else seg->v -= vseg; } + // Restore original orientation of segment chain + reversesegs(pr, k); + // Reported tank quality is mixture of flow released and any inflow tank->C = (wsum + win) / (vsum + vin); } From d436b232b547c0b6ea7c205d2632493f56a87b56 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Mon, 8 Apr 2019 13:40:17 -0400 Subject: [PATCH 48/49] Triggering build to update benchmarks --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 56dc1fa..5e5949e 100755 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ EPANET {#epanet-readme} ## For EPANET-related questions and discussion -For community discussion, FAQ, and roadmapping of the project, go to the [Community Forum](http://community.wateranalytics.org/category/epanet). +For community discussion, FAQ, and roadmapping of the project, go to the [Community Forum](http://community.wateranalytics.org/category/epanet). ## What is on this Repository? The EPANET Library is a pressurized pipe network hydraulic and water quality analysis toolkit written in C. If you are interested in using/extending EPANET for academic, personal, or commercial use, then you've come to the right place. From 04a6ece769094fd651ac4d3d8c66b1a11a098c87 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Mon, 8 Apr 2019 14:07:00 -0400 Subject: [PATCH 49/49] Added new reg tests Updating reference build id --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index d8e6ce9..dd74d64 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,14 +22,14 @@ environment: GROUP: "SUPPORTED" BOOST_ROOT: "C:/Libraries/boost_1_67_0" PLATFORM: "win32" - REF_BUILD_ID: "220dev5" + REF_BUILD_ID: "538_1" # New build on Visual Studio 15 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 GENERATOR: "Visual Studio 15 2017 Win64" GROUP: "EXPERIMENTAL" BOOST_ROOT: "C:/Libraries/boost_1_67_0" PLATFORM: "win64" - REF_BUILD_ID: "381_2" + REF_BUILD_ID: "538_2" # called before repo cloning init: