From fcbbbf9b2e04f1e60a84b108395abc9d4b596996 Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Wed, 20 Feb 2019 12:43:32 -0500 Subject: [PATCH] Adds new pattern, curve and reporting functions to API --- ReleaseNotes2_2.md | 13 ++- doc/modules.dox | 7 ++ include/epanet2.bas | 5 + include/epanet2.def | 9 +- include/epanet2.h | 10 ++ include/epanet2.vb | 5 + include/epanet2_2.h | 53 ++++++++++- src/epanet.c | 140 ++++++++++++++++++++++++++- src/epanet2.c | 25 +++++ src/funcs.h | 3 + src/project.c | 109 +++++++++++++++++++++ src/report.c | 45 +++++++++ tests/test_pattern_curve_funcs.cpp | 146 +++++++++++++++++++++++++++++ 13 files changed, 562 insertions(+), 8 deletions(-) create mode 100644 tests/test_pattern_curve_funcs.cpp diff --git a/ReleaseNotes2_2.md b/ReleaseNotes2_2.md index 8c4115e..9494f74 100644 --- a/ReleaseNotes2_2.md +++ b/ReleaseNotes2_2.md @@ -1,6 +1,6 @@ Release Notes for EPANET 2.2 (Draft) ============================ -This document describes the changes and updates that have been made to version 2.2 of EPANET. +This document describes the changes and updates that have been made in version 2.2 of EPANET. ## Thread-Safe API Functions @@ -140,8 +140,8 @@ Both network files are available [here](https://doi.org/10.23719/1375314). ## New API functions |Function|Description| |--|--| -|`EN_createproject` | creates a new EPANET project | -|`EN_deleteproject` | deletes an EPANET project | +|`EN_createproject` | Creates a new EPANET project | +|`EN_deleteproject` | Deletes an EPANET project | |`EN_init`|Initializes an EPANET project| |`EN_setflowunits`|Sets the project's flow units| |`EN_addnode`|Adds a new node to a project| @@ -150,6 +150,8 @@ Both network files are available [here](https://doi.org/10.23719/1375314). |`EN_addrule`|Adds a new control rule to a project| |`EN_deletenode`|Deletes a node from the project| |`EN_deletelink`|Deletes a link from the project| +|`EN_deletepattern`|Deletes a time pattern from the project| +|`EN_deletecurve`|Deletes a data curve from the project| |`EN_deletecontrol`|Deletes a simple control from the project| |`EN_deleterule`|Deletes a rule-based control from the project| |`EN_setnodeid`|Changes the ID name for a node| @@ -164,6 +166,8 @@ Both network files are available [here](https://doi.org/10.23719/1375314). |`EN_getdemandname`|Gets the name of a node's demand category| |`EN_setdemandname`|Sets the name of a node's demand category| |`EN_setdemandpattern`|Assigns a time pattern to a node's demand category | +|`EN_setpatternid`|Changes the ID name of a time pattern| +|`EN_setcurveid`|Changes the ID name of a data curve| |`EN_getcurvetype`|Gets a curve's type| |`EN_setheadcurveindex`|Sets the index of a head curve used by a pump | |`EN_getrule`|Gets the number of elements in a rule-based control | @@ -176,11 +180,12 @@ Both network files are available [here](https://doi.org/10.23719/1375314). |`EN_getthenaction`|Gets the contents of a THEN action in a rule-based control| |`EN_setthenaction`|Sets the contents of a THEN action in a rule-based control| |`EN_getelseaction`|Gets the contents of an ELSE action in a rule-based control| -|`EN_setelseaction`|Set the contents of an ELSE action in a rule-based control| +|`EN_setelseaction`|Sets the contents of an ELSE action in a rule-based control| |`EN_setrulepriority`|Sets the priority of a rule-based control| |`EN_gettitle` |Gets a project's title | |`EN_settitle` |Sets a project's title | |`EN_clearreport` |Clears the contents of a project's report file | +|`EN_copyreport` | Copies the contents of a project's report file | In addition to these new functions, a tank's volume curve `EN_VOLCURVE` can be set using `EN_setnodevalue` and `EN_setlinkvalue` can now be used to set the following pump properties: - `EN_PUMP_POWER` (constant power rating) - `EN_PUMP_HCURVE` (head characteristic curve) diff --git a/doc/modules.dox b/doc/modules.dox index 9eb38d0..77369fc 100644 --- a/doc/modules.dox +++ b/doc/modules.dox @@ -112,6 +112,7 @@ These are symbolic constants used as function arguments. @{ @fn int EN_writeline(EN_Project ph, char *line) @fn int EN_report(EN_Project ph) +@fn int EN_copyreport(EN_Project ph, char *filename) @fn int EN_clearreport(EN_Project ph) @fn int EN_resetreport(EN_Project ph) @fn int EN_setreport(EN_Project ph, char *reportFormat) @@ -196,8 +197,10 @@ These are symbolic constants used as function arguments. @addtogroup Patterns @{ @fn int EN_addpattern(EN_Project ph, char *id) +@fn int EN_deletepattern(EN_Project ph, int index) @fn int EN_getpatternindex(EN_Project ph, char *id, int *index) @fn int EN_getpatternid(EN_Project ph, int index, char *id) +@fn int EN_setpatternid(EN_Project ph, int index, char *id) @fn int EN_getpatternlen(EN_Project ph, int index, int *len) @fn int EN_getpatternvalue(EN_Project ph, int index, int period, double *value) @fn int EN_setpatternvalue(EN_Project ph, int index, int period, double value) @@ -210,8 +213,10 @@ These are symbolic constants used as function arguments. @addtogroup Curves @{ @fn int EN_addcurve(EN_Project ph, char *id) +@fn int EN_deletecurve(EN_Project ph, int index) @fn int EN_getcurveindex(EN_Project ph, char *id, int *index) @fn int EN_getcurveid(EN_Project ph, int index, char *id) +@fn int EN_setcurveid(EN_Project ph, int index, char *id) @fn int EN_getcurvelen(EN_Project ph, int index, int *len) @fn int EN_getcurvetype(EN_Project ph, int index, int *type) @fn int EN_getcurvevalue(EN_Project ph, int curveIndex, int pointIndex, double *x, double *y) @@ -302,6 +307,8 @@ To suppress the writing of all error and warning messages to the Report file eit To route a formatted report to a different file than the Report file either include the command `FILE filename` in the [REPORT] section of the Input file or call the Toolkit function `EN_setreport("FILE filename")`, where `filename` is the name of the file to use. +Toolkit clients will not be able to access the contents of a Report file until a project is closed. If access is needed before then, the @ref EN_copyreport function can be used to copy its current contents to another file. A @ref EN_clearreport function is also available to clear the current contents of the Report file. + @section OutputFile Output File The Output file is an unformatted binary file used to store both hydraulic and water quality results at uniform reporting intervals (see @ref OutFileFormat). It is the third file name supplied to the @ref EN_open function (or second name to @ref EN_init). If an empty string ("") is used as its name then a scratch temporary file will be used. Otherwise the Output file will be saved after the @ref EN_close function is called. Saving this file is useful if further post-processing of the output results are needed. The function @ref EN_saveH will transfer hydraulic results to the Output file if no water quality analysis will be made. Using @ref EN_solveQ to run a water quality analysis automatically saves both hydraulic and water quality results to this file. If the @ref EN_initQ - @ref EN_runQ - @ref EN_nextQ set of functions is used to perform a water quality analysis, then results will be saved only if the `saveflag` argument of @ref EN_initQ is set to @ref EN_SAVE. Again, the need to save results to the Output file is application-dependent. If a formatted output report is to be generated using @ref EN_report, then results must first be saved to the Output file. diff --git a/include/epanet2.bas b/include/epanet2.bas index 3f4dcb9..1bda793 100644 --- a/include/epanet2.bas +++ b/include/epanet2.bas @@ -253,6 +253,7 @@ Public Const EN_R_IS_ACTIVE = 3 'Reporting Functions Declare Function ENwriteline Lib "epanet2.dll" (ByVal line As String) As Long Declare Function ENreport Lib "epanet2.dll" () As Long + Declare Function ENcopyreport Lib "epanet2.dll" (ByVal filename As String) As Long Declare Function ENclearreport Lib "epanet2.dll" () As Long Declare Function ENresetreport Lib "epanet2.dll" () As Long Declare Function ENsetreport Lib "epanet2.dll" (ByVal format As String) As Long @@ -318,8 +319,10 @@ Public Const EN_R_IS_ACTIVE = 3 'Time Pattern Functions Declare Function ENaddpattern Lib "epanet2.dll" (ByVal id As String) As Long + Declare Function ENdeletepattern Lib "epanet2.dll" (ByVal index As Long) As Long Declare Function ENgetpatternindex Lib "epanet2.dll" (ByVal id As String, index As Long) As Long Declare Function ENgetpatternid Lib "epanet2.dll" (ByVal index As Long, ByVal id As String) As Long + Declare Function ENsetpatternid Lib "epanet2.dll" (ByVal index As Long, ByVal newid As String) As Long Declare Function ENgetpatternlen Lib "epanet2.dll" (ByVal index As Long, len_ As Long) As Long Declare Function ENgetpatternvalue Lib "epanet2.dll" (ByVal index As Long, ByVal period As Long, value As Single) As Long Declare Function ENsetpatternvalue Lib "epanet2.dll" (ByVal index As Long, ByVal period As Long, ByVal value As Single) As Long @@ -328,8 +331,10 @@ Public Const EN_R_IS_ACTIVE = 3 'Data Curve Functions Declare Function ENaddcurve Lib "epanet2.dll" (ByVal id As String) As Long + Declare Function ENdeletecurve Lib "epanet2.dll" (ByVal index As Long) As Long Declare Function ENgetcurveindex Lib "epanet2.dll" (ByVal id As String, index As Long) As Long Declare Function ENgetcurveid Lib "epanet2.dll" (ByVal index As Long, ByVal id As String) As Long + Declare Function ENsetcurveid Lib "epanet2.dll" (ByVal index As Long, ByVal newid As String) As Long Declare Function ENgetcurvelen Lib "epanet2.dll" (ByVal index As Long, len_ As Long) As Long Declare Function ENgetcurvetype Lib "epanet2.dll" (ByVal index As Long, type_ As Long) As Long Declare Function ENgetcurvevalue Lib "epanet2.dll" (ByVal curveIndex As Long, ByVal pointIndex As Long, x As Single, y As Single) As Long diff --git a/include/epanet2.def b/include/epanet2.def index 878ca99..42c9d0e 100644 --- a/include/epanet2.def +++ b/include/epanet2.def @@ -11,9 +11,12 @@ EXPORTS ENclose = _ENclose@0 ENcloseH = _ENcloseH@0 ENcloseQ = _ENcloseQ@0 + ENcopyreport = _ENcopyreport@4 ENdeletecontrol = _ENdeletecontrol@4 + ENdeletecurve = _ENdeletecurve@4 ENdeletelink = _ENdeletelink@8 ENdeletenode = _ENdeletenode@8 + ENdeletepattern = _ENdeletepattern@4 ENdeleterule = _ENdeleterule@4 ENepanet = _ENepanet@16 ENgetaveragepatternvalue = _ENgetaveragepatternvalue@8 @@ -79,7 +82,8 @@ EXPORTS ENsetbasedemand = _ENsetbasedemand@12 ENsetcontrol = _ENsetcontrol@24 ENsetcoord = _ENsetcoord@12 - ENsetcurve = _ENsetcurve@16 + ENsetcurve = _ENsetcurve@16 + ENsetcurveid = _ENsetcurveid@8 ENsetcurvevalue = _ENsetcurvevalue@16 ENsetdemandmodel = _ENsetdemandmodel@16 ENsetdemandname = _ENsetdemandname@12 @@ -95,7 +99,8 @@ EXPORTS ENsetnodeid = _ENsetnodeid@8 ENsetnodevalue = _ENsetnodevalue@12 ENsetoption = _ENsetoption@8 - ENsetpattern = _ENsetpattern@12 + ENsetpattern = _ENsetpattern@12 + ENsetpatternid = _ENsetpatternid@8 ENsetpatternvalue = _ENsetpatternvalue@12 ENsetpipedata = _ENsetpipedata@20 ENsetpremise = _ENsetpremise@36 diff --git a/include/epanet2.h b/include/epanet2.h index 64cf3d4..671724a 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -137,6 +137,8 @@ extern "C" { int DLLEXPORT ENreport(); + int DLLEXPORT ENcopyreport(char *filename); + int DLLEXPORT ENclearreport(); int DLLEXPORT ENresetreport(); @@ -292,10 +294,14 @@ extern "C" { int DLLEXPORT ENaddpattern(char *id); + int DLLEXPORT ENdeletepattern(int index); + int DLLEXPORT ENgetpatternindex(char *id, int *index); int DLLEXPORT ENgetpatternid(int index, char *id); + int DLLEXPORT ENsetpatternid(int index, char *id); + int DLLEXPORT ENgetpatternlen(int index, int *len); int DLLEXPORT ENgetpatternvalue(int index, int period, EN_API_FLOAT_TYPE *value); @@ -314,10 +320,14 @@ extern "C" { int DLLEXPORT ENaddcurve(char *id); + int DLLEXPORT ENdeletecurve(int index); + int DLLEXPORT ENgetcurveindex(char *id, int *index); int DLLEXPORT ENgetcurveid(int index, char *id); + int DLLEXPORT ENsetcurveid(int index, char *id); + int DLLEXPORT ENgetcurvelen(int index, int *len); int DLLEXPORT ENgetcurvetype(int index, int *type); diff --git a/include/epanet2.vb b/include/epanet2.vb index b882562..f98b381 100644 --- a/include/epanet2.vb +++ b/include/epanet2.vb @@ -258,6 +258,7 @@ Public Const EN_R_IS_ACTIVE = 3 'Reporting Functions Declare Function ENwriteline Lib "epanet2.dll" (ByVal line As String) As Int32 Declare Function ENreport Lib "epanet2.dll" () As Int32 + Declare Function ENcopyreport Lib "epanet2.dll" (ByVal filename As String) As Int32 Declare Function ENclearreport Lib "epanet2.dll" () As Int32 Declare Function ENresetreport Lib "epanet2.dll" () As Int32 Declare Function ENsetreport Lib "epanet2.dll" (ByVal format As String) As Int32 @@ -323,8 +324,10 @@ Public Const EN_R_IS_ACTIVE = 3 'Time Pattern Functions Declare Function ENaddpattern Lib "epanet2.dll" (ByVal id As String) As Int32 + Declare Function ENdeletepattern Lib "epanet2.dll" (ByVal index As Int32) As Int32 Declare Function ENgetpatternindex Lib "epanet2.dll" (ByVal id As String, index As Int32) As Int32 Declare Function ENgetpatternid Lib "epanet2.dll" (ByVal index As Int32, ByVal id As String) As Int32 + Declare Function ENsetpatternid Lib "epanet2.dll" (ByVal index As Int32, ByVal newid As String) As Int32 Declare Function ENgetpatternlen Lib "epanet2.dll" (ByVal index As Int32, len_ As Int32) As Int32 Declare Function ENgetpatternvalue Lib "epanet2.dll" (ByVal index As Int32, ByVal period As Int32, value As Single) As Int32 Declare Function ENsetpatternvalue Lib "epanet2.dll" (ByVal index As Int32, ByVal period As Int32, ByVal value As Single) As Int32 @@ -333,8 +336,10 @@ Public Const EN_R_IS_ACTIVE = 3 'Data Curve Functions Declare Function ENaddcurve Lib "epanet2.dll" (ByVal id As String) As Int32 + Declare Function ENdeletecurve Lib "epanet2.dll" (ByVal index As Int32) As Int32 Declare Function ENgetcurveindex Lib "epanet2.dll" (ByVal id As String, index As Int32) As Int32 Declare Function ENgetcurveid Lib "epanet2.dll" (ByVal index As Int32, ByVal id As String) As Int32 + Declare Function ENsetcurveid Lib "epanet2.dll" (ByVal index As Int32, ByVal newid As String) As Int32 Declare Function ENgetcurvelen Lib "epanet2.dll" (ByVal index As Int32, len_ As Int32) As Int32 Declare Function ENgetcurvetype Lib "epanet2.dll" (ByVal index As Int32, type_ As Int32) As Int32 Declare Function ENgetcurvevalue Lib "epanet2.dll" (ByVal curveIndex As Int32, ByVal pointIndex As Int32, x As Single, y As Single) As Int32 diff --git a/include/epanet2_2.h b/include/epanet2_2.h index 7b79701..924bb1a 100644 --- a/include/epanet2_2.h +++ b/include/epanet2_2.h @@ -128,6 +128,7 @@ typedef struct Project *EN_Project; /** @brief Retrieves the title lines of the project + @param ph an EPANET project handle. @param[out] line1 first title line @param[out] line2 second title line @param[out] line3 third title line @@ -137,6 +138,7 @@ typedef struct Project *EN_Project; /** @brief Sets the title lines of the project + @param ph an EPANET project handle. @param line1 first title line @param line2 second title line @param line3 third title line @@ -517,10 +519,21 @@ typedef struct Project *EN_Project; */ int DLLEXPORT EN_report(EN_Project ph); + /** + @brief Copies the current contents of a project's report file to another file. + @param ph an EPANET project handle. + @param filename the full path name of the destination file. + @return an error code. + + This function allows toolkit clients to retrieve the contents of a project's + report file while the project is still open. + */ + int DLLEXPORT EN_copyreport(EN_Project ph, char *filename); + /** @brief Clears the contents of a project's report file. @param ph an EPANET project handle. - @return and error code. + @return an error code. */ int DLLEXPORT EN_clearreport(EN_Project ph); @@ -1185,6 +1198,14 @@ typedef struct Project *EN_Project; */ int DLLEXPORT EN_addpattern(EN_Project ph, char *id); + /** + @brief Deletes a time pattern from a project. + @param ph an EPANET project handle. + @param index the time pattern's index (starting from 1). + @return an error code. + */ + int DLLEXPORT EN_deletepattern(EN_Project ph, int index); + /** @brief Retrieves the index of a time pattern given its ID name. @param ph an EPANET project handle. @@ -1205,6 +1226,17 @@ typedef struct Project *EN_Project; */ int DLLEXPORT EN_getpatternid(EN_Project ph, int index, char *id); + /** + @brief Changes the ID name of a time pattern given its index. + @param ph an EPANET project handle. + @param index a time pattern index (starting from 1). + @param id the time pattern's new ID name. + @return an error code. + + The new ID name must not exceed @ref EN_MAXID characters. + */ + int DLLEXPORT EN_setpatternid(EN_Project ph, int index, char *id); + /** @brief Retrieves the number of time periods in a time pattern. @param ph an EPANET project handle. @@ -1274,6 +1306,14 @@ typedef struct Project *EN_Project; */ int DLLEXPORT EN_addcurve(EN_Project ph, char *id); + /** + @brief Deletes a data curve from a project. + @param ph an EPANET project handle. + @param index the data curve's index (starting from 1). + @return an error code. + */ + int DLLEXPORT EN_deletecurve(EN_Project ph, int index); + /** @brief Retrieves the index of a curve given its ID name. @param ph an EPANET project handle. @@ -1294,6 +1334,17 @@ typedef struct Project *EN_Project; */ int DLLEXPORT EN_getcurveid(EN_Project ph, int index, char *id); + /** + @brief Changes the ID name of a data curve given its index. + @param ph an EPANET project handle. + @param index a data curve index (starting from 1). + @param id the data curve's new ID name. + @return an error code. + + The new ID name must not exceed @ref EN_MAXID characters. + */ + int DLLEXPORT EN_setcurveid(EN_Project ph, int index, char *id); + /** @brief Retrieves the number of points in a curve. @param ph an EPANET project handle. diff --git a/src/epanet.c b/src/epanet.c index 969c4a0..626d65b 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -864,6 +864,19 @@ int DLLEXPORT EN_report(EN_Project p) return errcode; } +int DLLEXPORT EN_copyreport(EN_Project p, char *filename) +/*---------------------------------------------------------------- +** Input: filename = name of file to receive copy of report +** Output: none +** Returns: error code +** Purpose: copies the contents of a project's report file to +** another file +**---------------------------------------------------------------- +*/ +{ + return copyreport(p, filename); +} + int DLLEXPORT EN_clearreport(EN_Project p) /*---------------------------------------------------------------- ** Input: none @@ -873,7 +886,6 @@ int DLLEXPORT EN_clearreport(EN_Project p) **---------------------------------------------------------------- */ { - if (!p->Openflag) return 102; return clearreport(p); } @@ -3870,6 +3882,53 @@ int DLLEXPORT EN_addpattern(EN_Project p, char *id) return 0; } +int DLLEXPORT EN_deletepattern(EN_Project p, int index) +/*---------------------------------------------------------------- +** Input: index = index of the pattern to delete +** Output: none +** Returns: error code +** Purpose: deletes a time pattern from a project +**---------------------------------------------------------------- +*/ +{ + int i; + + Network *net = &p->network; + Parser *parser = &p->parser; + Hydraul *hyd = &p->hydraul; + + // Can't delete a pattern while a solver is active + if (!p->Openflag)return 102; + if (p->hydraul.OpenHflag || p->quality.OpenQflag) return 262; + + // Check that pattern exists + if (index < 1 || index > p->network.Npats) return 205; + + // 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--; + + // Free the pattern's factor array + FREE(net->Pattern[index].F); + + // Shift the entries in the network's Pattern array + for (i = index; i < net->Npats; i++) net->Pattern[i] = net->Pattern[i+1]; + net->Npats--; + parser->MaxPats--; + return 0; +} + int DLLEXPORT EN_getpatternindex(EN_Project p, char *id, int *index) /*---------------------------------------------------------------- ** Input: id = time pattern name @@ -3911,6 +3970,28 @@ int DLLEXPORT EN_getpatternid(EN_Project p, int index, char *id) return 0; } +int DLLEXPORT EN_setpatternid(EN_Project p, int index, char *id) +/*---------------------------------------------------------------- +** Input: index = time pattern index +** id = time pattern ID name +** Returns: error code +** Purpose: changes the ID name of a time pattern +**---------------------------------------------------------------- +*/ +{ + int i; + + if (!p->Openflag) return 102; + if (index < 1 || index > p->network.Npats) return 205; + if (strlen(id) > MAXID) return 250; + for (i = 1; i <= p->network.Npats; i++) + { + if (i != index && strcmp(id, p->network.Pattern[i].ID) == 0) return 215; + } + strcpy(p->network.Pattern[index].ID, id); + return 0; +} + int DLLEXPORT EN_getpatternlen(EN_Project p, int index, int *len) /*---------------------------------------------------------------- ** Input: index = time pattern index @@ -4083,6 +4164,41 @@ int DLLEXPORT EN_addcurve(EN_Project p, char *id) return 0; } +int DLLEXPORT EN_deletecurve(EN_Project p, int index) +/*---------------------------------------------------------------- +** Input: index = index of the curve to delete +** Output: none +** Returns: error code +** Purpose: deletes a data curve from a project +**---------------------------------------------------------------- +*/ +{ + int i; + + Network *net = &p->network; + Parser *parser = &p->parser; + + // Can't delete a curve while a solver is active + if (!p->Openflag)return 102; + if (p->hydraul.OpenHflag || p->quality.OpenQflag) return 262; + + // Check that curve exists + if (index < 1 || index > p->network.Ncurves) return 205; + + // Adjust references by other objects to curves + adjustcurves(net, index); + + // Free the curve's data arrays + FREE(net->Curve[index].X); + FREE(net->Curve[index].Y); + + // Shift the entries in the network's Curve array + for (i = index; i < net->Ncurves; i++) net->Curve[i] = net->Curve[i + 1]; + net->Ncurves--; + parser->MaxCurves--; + return 0; +} + int DLLEXPORT EN_getcurveindex(EN_Project p, char *id, int *index) /*---------------------------------------------------------------- ** Input: id = data curve name @@ -4124,6 +4240,28 @@ int DLLEXPORT EN_getcurveid(EN_Project p, int index, char *id) return 0; } +int DLLEXPORT EN_setcurveid(EN_Project p, int index, char *id) +/*---------------------------------------------------------------- +** Input: index = data curve index +** id = data curve ID name +** Returns: error code +** Purpose: changes the ID name of a data curve +**---------------------------------------------------------------- +*/ +{ + int i; + + if (!p->Openflag) return 102; + if (index < 1 || index > p->network.Ncurves) return 205; + if (strlen(id) > MAXID) return 250; + for (i = 1; i <= p->network.Ncurves; i++) + { + if (i != index && strcmp(id, p->network.Curve[i].ID) == 0) return 215; + } + strcpy(p->network.Curve[index].ID, id); + return 0; +} + int DLLEXPORT EN_getcurvelen(EN_Project p, int index, int *len) /*---------------------------------------------------------------- ** Input: index = data curve index diff --git a/src/epanet2.c b/src/epanet2.c index 33d30cf..46c31ce 100644 --- a/src/epanet2.c +++ b/src/epanet2.c @@ -189,6 +189,11 @@ int DLLEXPORT ENwriteline(char *line) { return EN_writeline(_defaultProject, lin int DLLEXPORT ENreport() { return EN_report(_defaultProject); } +int DLLEXPORT ENcopyreport(char *filename) +{ + return EN_copyreport(_defaultProject, filename); +} + int DLLEXPORT ENclearreport() { return EN_clearreport(_defaultProject); } int DLLEXPORT ENresetreport() { return EN_resetreport(_defaultProject); } @@ -515,6 +520,11 @@ int DLLEXPORT ENaddpattern(char *id) return EN_addpattern(_defaultProject, id); } +int DLLEXPORT ENdeletepattern(int index) +{ + return EN_deletepattern(_defaultProject, index); +} + int DLLEXPORT ENgetpatternindex(char *id, int *index) { return EN_getpatternindex(_defaultProject, id, index); @@ -525,6 +535,11 @@ int DLLEXPORT ENgetpatternid(int index, char *id) return EN_getpatternid(_defaultProject, index, id); } +int DLLEXPORT ENsetpatternid(int index, char *id) +{ + return EN_setpatternid(_defaultProject, index, id); +} + int DLLEXPORT ENgetpatternlen(int index, int *len) { return EN_getpatternlen(_defaultProject, index, len); @@ -577,6 +592,11 @@ int DLLEXPORT ENaddcurve(char *id) return EN_addcurve(_defaultProject, id); } +int DLLEXPORT ENdeletecurve(int index) +{ + return EN_deletecurve(_defaultProject, index); +} + int DLLEXPORT ENgetcurveindex(char *id, int *index) { return EN_getcurveindex(_defaultProject, id, index); @@ -587,6 +607,11 @@ int DLLEXPORT ENgetcurveid(int index, char *id) return EN_getcurveid(_defaultProject, index, id); } +int DLLEXPORT ENsetcurveid(int index, char *id) +{ + return EN_setcurveid(_defaultProject, index, id); +} + int DLLEXPORT ENgetcurvelen(int index, int *len) { return EN_getcurvelen(_defaultProject, index, len); diff --git a/src/funcs.h b/src/funcs.h index 5594f22..dde13c4 100755 --- a/src/funcs.h +++ b/src/funcs.h @@ -35,6 +35,8 @@ int findlink(Network *, char *); int findtank(Network *, int); int findvalve(Network *, int); int findpump(Network *, int); +void adjustpatterns(Network *, int); +void adjustcurves(Network *, int); char *getTmpName(char *); int strcomp(const char *, const char *); @@ -109,6 +111,7 @@ int checkrules(Project *, long); // ------- REPORT.C ----------------- int clearreport(Project *); +int copyreport(Project *, char *); int writereport(Project *); void writelogo(Project *); void writesummary(Project *); diff --git a/src/project.c b/src/project.c index 85e6552..349fa13 100644 --- a/src/project.c +++ b/src/project.c @@ -219,6 +219,19 @@ void initpointers(Project *pr) **---------------------------------------------------------------- */ { + Network* nw = &pr->network; + nw->Nnodes = 0; + nw->Ntanks = 0; + nw->Njuncs = 0; + nw->Nlinks = 0; + nw->Npipes = 0; + nw->Npumps = 0; + nw->Nvalves = 0; + nw->Ncontrols = 0; + nw->Nrules = 0; + nw->Npats = 0; + nw->Ncurves = 0; + pr->hydraul.NodeDemand = NULL; pr->hydraul.NodeHead = NULL; pr->hydraul.LinkFlow = NULL; @@ -755,6 +768,102 @@ int findvalve(Network *network, int index) return NOTFOUND; } +void adjustpattern(int *pat, int index) +/*---------------------------------------------------------------- +** Local function that modifies a reference to a deleted time pattern +**---------------------------------------------------------------- +*/ +{ + if (*pat == index) *pat = 0; + else if (*pat > index) (*pat)--; +} + +void adjustpatterns(Network *network, int index) +/*---------------------------------------------------------------- +** Input: index = index of time pattern being deleted +** Output: none +** Purpose: modifies references made to a deleted time pattern +**---------------------------------------------------------------- +*/ +{ + int j; + Pdemand demand; + Psource source; + + // Adjust patterns used by junctions + for (j = 1; j <= network->Njuncs; j++) + { + // Adjust demand patterns + for (demand = network->Node[j].D; demand != NULL; demand = demand->next) + { + adjustpattern(&demand->Pat, index); + } + // Adjust WQ source patterns + source = network->Node[j].S; + if (source) adjustpattern(&source->Pat, index); + } + + // Adjust patterns used by reservoir tanks + for (j = 1; j <= network->Ntanks; j++) + { + adjustpattern(&network->Tank[j].Pat, index); + } + + // Adjust patterns used by pumps + for (j = 1; j <= network->Npumps; j++) + { + adjustpattern(&network->Pump[j].Upat, index); + adjustpattern(&network->Pump[j].Epat, index); + } +} + +void adjustcurve(int *curve, int index) +/*---------------------------------------------------------------- +** Local function that modifies a reference to a deleted data curve +**---------------------------------------------------------------- +*/ +{ + if (*curve == index) *curve = 0; + else if (*curve > index) (*curve)--; +} + +void adjustcurves(Network *network, int index) +/*---------------------------------------------------------------- +** Input: index = index of data curve being deleted +** Output: none +** Purpose: modifies references made to a deleted data curve +**---------------------------------------------------------------- +*/ +{ + int j, k, setting; + + // Adjust tank volume curves + for (j = 1; j <= network->Ntanks; j++) + { + adjustcurve(&network->Tank[j].Vcurve, index); + } + + // Adjust pump curves + for (j = 1; j <= network->Npumps; j++) + { + adjustcurve(&network->Pump[j].Hcurve, index); + adjustcurve(&network->Pump[j].Ecurve, index); + } + + // Adjust GPV curves + for (j = 1; j <= network->Nvalves; j++) + { + k = network->Valve[j].Link; + if (network->Link[k].Type == GPV) + { + setting = INT(network->Link[k].Kc); + adjustcurve(&setting, index); + network->Link[k].Kc = setting; + } + } +} + + char *getTmpName(char *fname) //---------------------------------------------------------------- // Input: fname = file name string diff --git a/src/report.c b/src/report.c index 84f3bb3..55387da 100644 --- a/src/report.c +++ b/src/report.c @@ -71,6 +71,51 @@ int clearreport(Project *pr) return 0; } +int copyreport(Project* pr, char *filename) +/* +**------------------------------------------------------ +** Input: filename = name of file to copy to +** Output: returns error code +** Purpose: copies contents of a project's report file +**------------------------------------------------------ +*/ +{ + FILE *tfile; + int c; + Report *rpt = &pr->report; + + // Check that project's report file exists + if (rpt->RptFile == NULL) return 0; + + // Open the new destination file + tfile = fopen(filename, "w"); + if (tfile == NULL) return 303; + + // Re-open project's report file in read mode + fclose(rpt->RptFile); + rpt->RptFile = fopen(rpt->Rpt1Fname, "r"); + + // Copy contents of project's report file + if (rpt->RptFile) + { + c = fgetc(rpt->RptFile); + while (c != EOF) + { + fputc(c, tfile); + c = fgetc(rpt->RptFile); + } + fclose(rpt->RptFile); + } + + // Close destination file + fclose(tfile); + + // Re-open project's report file in append mode + rpt->RptFile = fopen(rpt->Rpt1Fname, "a"); + if (rpt->RptFile == NULL) return 303; + return 0; +} + int writereport(Project *pr) /* **------------------------------------------------------ diff --git a/tests/test_pattern_curve_funcs.cpp b/tests/test_pattern_curve_funcs.cpp new file mode 100644 index 0000000..cbb1513 --- /dev/null +++ b/tests/test_pattern_curve_funcs.cpp @@ -0,0 +1,146 @@ +// Test of the EN_setpatternid, EN_setcurveid, EN_deletepattern & EN_deletecurve +// EPANET 2.2 API functions +#define _CRT_SECURE_NO_DEPRECATE + +//#define NO_BOOST + +#ifndef NO_BOOST +#define BOOST_TEST_MODULE "toolkit" +#include +#endif + +#include +#include +#include "epanet2_2.h" + +#define DATA_PATH_INP "./net1.inp" +#define DATA_PATH_RPT "./test.rpt" +#define DATA_PATH_OUT "./test.out" + +#ifdef NO_BOOST +#define BOOST_REQUIRE(x) (((x)) ? cout << "\nPassed at line " << __LINE__ : cout << "\nFailed at line " << __LINE__ ) +#endif + +using namespace std; + +#ifndef NO_BOOST +BOOST_AUTO_TEST_SUITE (test_toolkit) +BOOST_AUTO_TEST_CASE(test_setid) +#else +int main(int argc, char *argv[]) +#endif +{ + string path_inp(DATA_PATH_INP); + string path_rpt(DATA_PATH_RPT); + string path_out(DATA_PATH_OUT); + string inp_save("net1_setid.inp"); + + int error = 0; + + EN_Project ph = NULL; + EN_createproject(&ph); + + 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; + int patIdx; + EN_getoption(ph, EN_DEFDEMANDPAT, &dblPatIdx); + defPatIdx = (int)dblPatIdx; + + // Rename the default pattern + EN_setpatternid(ph, defPatIdx, (char *)"Pat1"); + EN_getpatternindex(ph, (char *)"Pat1", &patIdx); + BOOST_REQUIRE(defPatIdx == patIdx); + + // Add 2 new patterns + EN_addpattern(ph, (char *)"Pat2"); + EN_addpattern(ph, (char *)"Pat3"); + double f2[] = {2.1, 2.2}; + double f3[] = {3.1, 3.2, 3.3, 3.4}; + EN_setpattern(ph, 2, f2, 2); + EN_setpattern(ph, 3, f3, 4); + + // Assign Pat3 to 3rd junction + EN_setdemandpattern(ph, 3, 1, 3); + + // Delete Pat2 + EN_deletepattern(ph, 2); + + // Check that there are now 2 patterns + int n; + EN_getcount(ph, EN_PATCOUNT, &n); + BOOST_REQUIRE(n == 2); + + // Check that Pat3 with 4 factors is still assigned to 3rd junction + EN_getdemandpattern(ph, 3, 1, &patIdx); + EN_getpatternlen(ph, patIdx, &n); + BOOST_REQUIRE(n == 4); + + // Delete the default pattern + EN_deletepattern(ph, defPatIdx); + + // Check that junction 4 has no pattern + EN_getdemandpattern(ph, 4, 1, &patIdx); + BOOST_REQUIRE(patIdx == 0); + + // And that junction 3 still uses Pat3 + EN_getdemandpattern(ph, 3, 1, &patIdx); + char patID[EN_MAXID+1]; + EN_getpatternid(ph, patIdx, patID); + BOOST_REQUIRE(strcmp(patID, "Pat3") == 0); + + // Re-name the pump's (Link 9) head curve + int pumpIdx; + char pumpID[] = "9"; + int curveIdx; + char newCurveID[] = "PumpHeadCurve"; + EN_getlinkindex(ph, pumpID, &pumpIdx); + EN_getheadcurveindex(ph, pumpIdx, &curveIdx); + EN_setcurveid(ph, curveIdx, newCurveID); + + // Check that rename was successful + char curveID[EN_MAXID + 1]; + EN_getcurveid(ph, curveIdx, curveID); + BOOST_REQUIRE(strcmp(curveID, newCurveID) == 0); + + // Add two new curves + double x2[] = {0.0, 1.0, 2.0}; + double y2[] = {400.0, 60.0, 30.0}; + double x3[] = {2000.0}; + double y3[] = {100.0}; + char curve2[] = "Curve2"; + char curve3[] = "Curve3"; + EN_addcurve(ph, curve2); + EN_setcurve(ph, 2, x2, y2, 3); + EN_addcurve(ph, curve3); + EN_setcurve(ph, 3, x3, y3, 1); + + // Assign Curve3 to pump's head curve + EN_getcurveindex(ph, curve3, &curveIdx); + EN_setheadcurveindex(ph, pumpIdx, curveIdx); + + // Delete Curve2 + EN_getcurveindex(ph, curve2, &curveIdx); + EN_deletecurve(ph, curveIdx); + + // Check that pump's head curve is still Curve3 + EN_getheadcurveindex(ph, pumpIdx, &curveIdx); + EN_getcurveid(ph, curveIdx, curveID); + BOOST_REQUIRE(strcmp(curveID, curve3) == 0); + + // And that it contains the correct data + double x, y; + EN_getcurvevalue(ph, curveIdx, 1, &x, &y); + BOOST_REQUIRE(x == x3[0]); + BOOST_REQUIRE(y == y3[0]); + + EN_close(ph); + EN_deleteproject(&ph); +} + +#ifndef NO_BOOST +BOOST_AUTO_TEST_SUITE_END() +#endif